forked from faif/python-patterns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
blackboard.py
127 lines (91 loc) · 3.46 KB
/
blackboard.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Eugene Duboviy <[email protected]> | github.com/duboviy
In Blackboard pattern several specialised sub-systems (knowledge sources)
assemble their knowledge to build a possibly partial or approximate solution.
In this way, the sub-systems work together to solve the problem,
where the solution is the sum of its parts.
https://en.wikipedia.org/wiki/Blackboard_system
"""
import abc
import random
class Blackboard(object):
def __init__(self):
self.experts = []
self.common_state = {
'problems': 0,
'suggestions': 0,
'contributions': [],
'progress': 0 # percentage, if 100 -> task is finished
}
def add_expert(self, expert):
self.experts.append(expert)
class Controller(object):
def __init__(self, blackboard):
self.blackboard = blackboard
def run_loop(self):
while self.blackboard.common_state['progress'] < 100:
for expert in self.blackboard.experts:
if expert.is_eager_to_contribute:
expert.contribute()
return self.blackboard.common_state['contributions']
class AbstractExpert(object):
__metaclass__ = abc.ABCMeta
def __init__(self, blackboard):
self.blackboard = blackboard
@abc.abstractproperty
def is_eager_to_contribute(self):
raise NotImplementedError('Must provide implementation in subclass.')
@abc.abstractmethod
def contribute(self):
raise NotImplementedError('Must provide implementation in subclass.')
class Student(AbstractExpert):
@property
def is_eager_to_contribute(self):
return True
def contribute(self):
self.blackboard.common_state['problems'] += random.randint(1, 10)
self.blackboard.common_state['suggestions'] += random.randint(1, 10)
self.blackboard.common_state['contributions'] += [self.__class__.__name__]
self.blackboard.common_state['progress'] += random.randint(1, 2)
class Scientist(AbstractExpert):
@property
def is_eager_to_contribute(self):
return random.randint(0, 1)
def contribute(self):
self.blackboard.common_state['problems'] += random.randint(10, 20)
self.blackboard.common_state['suggestions'] += random.randint(10, 20)
self.blackboard.common_state['contributions'] += [self.__class__.__name__]
self.blackboard.common_state['progress'] += random.randint(10, 30)
class Professor(AbstractExpert):
@property
def is_eager_to_contribute(self):
return True if self.blackboard.common_state['problems'] > 100 else False
def contribute(self):
self.blackboard.common_state['problems'] += random.randint(1, 2)
self.blackboard.common_state['suggestions'] += random.randint(10, 20)
self.blackboard.common_state['contributions'] += [self.__class__.__name__]
self.blackboard.common_state['progress'] += random.randint(10, 100)
if __name__ == '__main__':
blackboard = Blackboard()
blackboard.add_expert(Student(blackboard))
blackboard.add_expert(Scientist(blackboard))
blackboard.add_expert(Professor(blackboard))
c = Controller(blackboard)
contributions = c.run_loop()
from pprint import pprint
pprint(contributions)
### OUTPUT ###
# ['Student',
# 'Student',
# 'Scientist',
# 'Student',
# 'Scientist',
# 'Student',
# 'Scientist',
# 'Student',
# 'Scientist',
# 'Student',
# 'Scientist',
# 'Professor']