-
Notifications
You must be signed in to change notification settings - Fork 0
/
play.py
152 lines (117 loc) · 4.39 KB
/
play.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
140
141
142
143
144
145
146
147
148
149
150
151
152
import matplotlib.pyplot as plt
import numpy as np
import timeit
from copy import copy
TIME_LIMIT_MILLIS = 150.
class Play:
def __init__(self, game, player1=None, player2=None, name='game'):
self.original_game = game
self.game = copy(game)
self.player1 = player1
self.player2 = player2
self.player = self.game.player
self.end = False
self.play()
def reset(self):
self.game = copy(self.original_game)
self.click_cid = None
self.end = False
def play(self, name='Game'):
self.reset()
if self.game.w * self.game.h < 25:
figsize = (self.game.w / 1.6, self.game.h / 1.6)
else:
figsize = (self.game.w / 2.1, self.game.h / 2.1)
self.fig = plt.figure(name, figsize=figsize)
if self.game.w * self.game.h < 25:
self.fig.subplots_adjust(.2, .2, 1, 1)
else:
self.fig.subplots_adjust(.1, .1, 1, 1)
self.fig.show()
w, h = self.game.size
self.ax = self.fig.gca()
self.ax.grid()
# remove hovering coordinate tooltips
self.ax.format_coord = lambda x, y: ''
self.ax.set_xlim([-.5,w-.5])
self.ax.set_ylim([-.5,h-.5])
self.ax.set_xticks(np.arange(0, w, 1))
self.ax.set_yticks(np.arange(0, h, 1))
self.ax.set_aspect('equal')
for loc in ['top', 'right', 'bottom', 'left']:
self.ax.spines[loc].set_visible(False)
# fully AI game
if self.player1 is not None and self.player2 is not None:
self.agent_game()
return
# at least one human
if self.player1 is not None:
# first move from AI first
succeed = False
while not succeed:
loc = self.agent_move(self.player1)
succeed = self.game.move(loc)
self.draw_move()
self.click_cid = self.fig.canvas.mpl_connect('button_press_event', self.click)
def agent_move(self, player, time_limit=TIME_LIMIT_MILLIS):
time_millis = lambda: 1000 * timeit.default_timer()
move_start = time_millis()
time_left = lambda: time_limit - (time_millis() - move_start)
move = player.search(self.game, time_left)
move_end = time_left()
if move_end < 0:
print('Timeout')
return False
return move
def agent_game(self):
score = None
# game not concluded yet
while score is None:
self.player = self.game.player
if self.game.player == 1:
loc = self.agent_move(self.player1)
else:
loc = self.agent_move(self.player2)
success = self.game.move(loc)
# see if game is done
if success:
score = self.game.score
self.draw_move()
def draw_move(self):
if self.end:
return
i, j = self.game.last_move
c = 'salmon' if self.player==1 else 'lightskyblue'
self.ax.scatter(i, j, s=500, marker='o', zorder=3, c=c)
score = self.game.score
self.draw_winner(score)
self.fig.canvas.draw()
def draw_winner(self, score):
if score is None:
return
if score == -1 or score == 1:
locs = self.game.get_winning_loc()
c = 'darkred' if score == 1 else 'darkblue'
self.ax.scatter(locs[:,0],locs[:,1], s=300, marker='*',c=c,zorder=4)
# try to disconnect if game is over
if hasattr(self, 'click_cid'):
self.fig.canvas.mpl_disconnect(self.click_cid)
self.end=True
def click(self, event):
col = int(round(event.xdata))
self.player = self.game.player
succeed = self.game.move(col)
if succeed:
self.draw_move()
else:
return
if self.player1 is not None or self.player2 is not None:
succeed = False
self.player = self.game.player
while not succeed:
if self.game.player == 1:
col = self.agent_move(self.player1)
else:
col = self.agent_move(self.player2)
succeed = self.game.move(col)
self.draw_move()