Skip to content

Commit 18b5102

Browse files
authored
Merge pull request gennad#4 from duboviy/master
Add Blackboard pattern
2 parents c83fd65 + 8e18c64 commit 18b5102

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

blackboard.py

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

0 commit comments

Comments
 (0)