-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
139 lines (120 loc) · 4.28 KB
/
main.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
128
129
130
131
132
133
134
135
136
137
138
139
from itertools import combinations
import signal
from contextlib import contextmanager
import sys
import dilemma_lib
from prisoners import BETRAY, LOYAL
def raise_timeout(x1, x2):
raise TimeoutError("time limit passed")
@contextmanager
def timeout(time):
# Register a function to raise a TimeoutError on the signal.
signal.signal(signal.SIGALRM, raise_timeout)
# Schedule the signal to be sent after ``time``.
signal.alarm(time)
try:
yield
finally:
# Unregister the signal so it won't be triggered
# if the timeout is not reached.
signal.signal(signal.SIGALRM, signal.SIG_IGN)
def get_disable_prints():
stdout, stderr = sys.stdout, sys.stderr
count = [0]
class __T:
def __enter__(self):
sys.stdout, sys.stderr = None, None
sys.__stdout__, sys.__stderr__ = None, None
count[0] += 1
def __exit__(self, exc_type, exc_val, exc_tb):
count[0] -= 1
if count[0] == 0:
sys.stdout, sys.stderr = stdout, stderr
sys.__stdout__, sys.__stderr__ = stdout, stderr
return __T()
disable_prints = get_disable_prints()
def run_competition(bots=None, turns_per_match=100, max_bot_runtime=1):
scores = {}
if bots is None:
bots = dilemma_lib.get_registered_classes()
for i in bots:
scores[i.__name__] = 0
for cls1, cls2 in combinations(bots, 2):
print(f'{cls1.__name__} VS {cls2.__name__}')
try:
with disable_prints:
p1 = cls1()
except BaseException as e:
print(f'trying to create instance of {cls1.__name__} caused {e}')
continue
try:
with disable_prints:
p2 = cls2()
except BaseException as e:
print(f'trying to create instance of {cls2.__name__} caused {e}')
continue
h1, h2 = [], []
for i in range(turns_per_match):
try:
with timeout(max_bot_runtime):
with disable_prints:
c1 = p1.do_turn(h1)
except BaseException as e:
print(f'{cls1.__name__} crushed: {e}')
break
try:
with timeout(max_bot_runtime):
with disable_prints:
c2 = p2.do_turn(h2)
except BaseException as e:
print(f'{cls2.__name__} crushed: {e}')
break
if c1 is LOYAL and c2 is LOYAL:
scores[cls1.__name__] += 5
scores[cls2.__name__] += 5
elif c1 is LOYAL and c2 is BETRAY:
scores[cls1.__name__] += 0
scores[cls2.__name__] += 20
elif c1 is BETRAY and c2 is LOYAL:
scores[cls1.__name__] += 20
scores[cls2.__name__] += 0
elif c1 is BETRAY and c2 is BETRAY:
scores[cls1.__name__] += 1
scores[cls2.__name__] += 1
else:
if c1 not in {BETRAY, LOYAL}:
print(f'{cls1.__name__} returned illegal output: {c1}')
if c2 not in {BETRAY, LOYAL}:
print(f'{cls2.__name__} returned illegal output: {c2}')
h1.append((c1, c2))
h2.append((c2, c1))
return scores
def show_scores(scores: dict):
name_score_tuples = list(scores.items())
name_score_tuples.sort(key=lambda x: x[1], reverse=True)
try:
winners = name_score_tuples.copy()
for place in ['FIRST', 'SECOND', 'THIRD']:
print(f'{place} PLACE: {" & ".join(x[0] for x in winners if x[1] == winners[0][1])}')
if place == 'THIRD':
break
winners = [x for x in winners if x[1] != winners[0][1]]
if len(winners) == 0:
break
except IndexError:
pass
print()
for index, (name, score) in enumerate(name_score_tuples):
print(f'{index + 1}. {name} => {score}')
if __name__ == '__main__':
print('finished registering competitors')
print()
print()
print('running competition...')
results = run_competition()
print()
print()
print('finished running competitions')
print('calculating results...')
print()
show_scores(results)