-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathprisonerlib.py
121 lines (99 loc) · 3.3 KB
/
prisonerlib.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
from pkgutil import iter_modules
from random import choice
import threading
import time
import sys
# generates available strategies for argparse choices
STRATEGIES = [mod[1] for mod in iter_modules(['strategies'])]
NUM_PRISONERS = 100
TIMEOUT = 15 # seconds
RUN_TIME = 3 # seconds
class LightBulb:
def __init__(self):
self.on = False
@property
def on(self):
return self.__on
@on.setter
def on(self, value):
if isinstance(value, bool):
self.__on = value
else:
raise TypeError('LightBulb can only receive bool values')
class Prisoner:
def __init__(self, pid):
self.__pid = pid
def visit(self, bulb, day):
# all work must be in visit function
raise NotImplementedError
@property
def pid(self):
return self.__pid
class Simulation:
__visited = set()
def __init__(self, mod):
self.__mod = mod
self.__run_times = []
self.__runs = 0
self.__alive = True
@property
def run_times(self):
return max(self.__run_times) / 365.25, min(self.__run_times) / 365.25,\
(sum(self.__run_times) / len(self.__run_times)) / 365.25
@property
def runs(self):
return self.__runs
@staticmethod
def solved(): # Measures __visited set to total number of prisoners
if len(Simulation.__visited) == NUM_PRISONERS:
return True
else:
return False
def simulate(self):
# build list
prisoners = []
try:
for i in range(NUM_PRISONERS):
prisoners.append(self.__mod.Prisoner(i)) # STRATEGY
except:
self.__alive = False
raise RuntimeError('Error occurred while building the prisoners list')
# simulate
light_bulb = LightBulb()
days = 0
victorious = False
while self.__alive and not victorious:
prisoner = choice(prisoners)
Simulation.__visited.add(prisoner.pid)
try:
victorious = prisoner.visit(light_bulb, days) # STRATEGY
except:
print("Error in the strategy's visit: {}".format(sys.exc_info()[0]))
if isinstance(victorious, bool):
days += 1
else:
self.__alive = False
raise TypeError('Visit can only return bool value')
# check if solved
if self.solved():
self.__run_times.append(days)
else:
self.__alive = False
# add to runs and clear visited set
self.__runs += 1
Simulation.__visited.clear()
def run(self):
start = time.time()
while (time.time() - start) < RUN_TIME and self.__alive:
thread = threading.Thread(target=self.simulate)
thread.start()
if self.__runs == 0:
thread.join(timeout=TIMEOUT)
if thread.is_alive():
self.__alive = False
raise TimeoutError('Strategy took longer than allowed')
else:
thread.join()
if not self.__alive:
print('\n\tSTRATEGY FAILED')
exit()