-
Notifications
You must be signed in to change notification settings - Fork 0
/
Handler.py
289 lines (253 loc) · 11.5 KB
/
Handler.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import logging
import tornado.escape
import tornado.web
import tornado.websocket
from tornado.httputil import HTTPServerRequest
from tornado.options import options
from base import *
from Board import Board
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("index.html", board=SocketHandler.board.get_scene_dict())
class SocketHandler(tornado.websocket.WebSocketHandler):
board = Board(options.history)
waiters = set()
players = [None,None] #Black player, White player
def get_compression_options(self):
# Non-None enables compression with default options.
return {}
def open(self):
SocketHandler.waiters.add(self)
# first two waiters become players
if SocketHandler.players[0] == None:
SocketHandler.players[0] = self
elif SocketHandler.players[1] == None:
SocketHandler.players[1] = self
else:
pass
#print "open", SocketHandler.players
self.update_board()
def on_close(self):
SocketHandler.waiters.remove(self)
if self in SocketHandler.players:
SocketHandler.players[SocketHandler.players.index(self)] = None
#if SocketHandler.board.winner:
# SocketHandler.board = Board(options.history)
#print "close", SocketHandler.players
def winnerCOLOR(self, opponent=False, string=False):
# this can be called by non-player
if string:
b = "BLACK"
w = "WHITE"
else:
b = BLACK
w = WHITE
if not opponent:
if SocketHandler.board.winner == BLACK:
return b # BLACK is player1
elif SocketHandler.board.winner == WHITE:
return w # WHITE is player2
else:
raise
else:
if SocketHandler.board.winner == BLACK:
return w
elif SocketHandler.board.winner == WHITE:
return b
else:
raise
def COLOR(self, opponent=False, string=False):
# this will fail when self is not in players[]
if string:
b = "BLACK"
w = "WHITE"
else:
b = BLACK
w = WHITE
if not opponent:
if SocketHandler.players.index(self) == 0:
return b # BLACK is player1
elif SocketHandler.players.index(self) == 1:
return w # WHITE is player2
else:
raise
else:
if SocketHandler.players.index(self) == 0:
return w
elif SocketHandler.players.index(self) == 1:
return b
else:
raise
def opponent_player(self):
# this will fail when self is not in players[]
if SocketHandler.players.index(self) == 0:
return SocketHandler.players[1]
elif SocketHandler.players.index(self) == 1:
return SocketHandler.players[0]
else:
raise
def update_board(self):
logging.info("called update_board from "+str(self))
SocketHandler.board.show()
if SocketHandler.board.winner:
self.gameover()
return
json = {}
json["type"] = "SUCCESS"
if SocketHandler.board.nextColor == BLACK:
json["turn"] = "BLACK"
else:
json["turn"] = "WHITE"
json["html"] = tornado.escape.to_basestring(self.render_string("board.html", board=SocketHandler.board.get_scene_dict()))
json["scene"] = SocketHandler.board.get_scene_list()
# in order to send message in a correct order,
# updates need to be sent to caller first, then audience, lastly opponent.
# if sent opponent first, AI will think of new move and send new update while you call write_message() of AI
# ,which makes player receive AI's new move first, and his own move next!
# if sent audience last, audience will receive the all moves in a reverse order(when it is AI vs AI)
#TODO: make the AI thinking function asynchronous
if self in SocketHandler.players: #may always be true(except called from open())
#caller
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
json["you"] = self.COLOR(string=True)
self.write_message(json)
#audience
for waiter in SocketHandler.waiters:
if waiter not in SocketHandler.players:
json["connection"] = "<font color='red'>A.I.</font> vs. PLAYER<br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
json["you"] = "AUDIENCE"
try:
waiter.write_message(json)
except:
logging.error("Error sending message", exc_info=True)
#opponent
if self.opponent_player():
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
json["you"] = self.COLOR(opponent=True, string=True)
self.opponent_player().write_message(json)
else:
#audience
for waiter in SocketHandler.waiters:
if waiter not in SocketHandler.players:
json["connection"] = "<font color='red'>A.I.</font> vs. PLAYER<br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
json["you"] = "AUDIENCE"
try:
waiter.write_message(json)
except:
logging.error("Error sending message", exc_info=True)
#second player, first
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
json["you"] = SocketHandler.players[1].COLOR(string=True)
SocketHandler.players[1].write_message(json)
#first player, next
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
json["you"] = SocketHandler.players[0].COLOR(string=True)
SocketHandler.players[0].write_message(json)
def reset_board(self):
SocketHandler.board = Board(options.history)
json = {}
json["type"] = "RESET"
for waiter in SocketHandler.waiters:
if waiter in SocketHandler.players:
json["you"] = waiter.COLOR(string=True)
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
else:
json["connection"] = "<font color='red'>A.I.</font> vs. PLAYER<br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
json["you"] = "AUDIENCE"
try:
waiter.write_message(json)
except:
logging.error("Error sending message", exc_info=True)
self.update_board()
def gameover(self):
# this is called someone requested for update after gameover
# this method is called by anyone (not only winner)
if not SocketHandler.board.winner:
raise
json = {}
json["type"] = "GAMEOVER"
json["html"] = tornado.escape.to_basestring(self.render_string("board.html", board=SocketHandler.board.get_scene_dict()))
json["scene"] = SocketHandler.board.get_scene_list()
if self in SocketHandler.players:
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
if self.COLOR() == self.winnerCOLOR(): # for winner
json["info"] = "YOU WIN!!"
json["you"] = self.winnerCOLOR(string=True)
self.write_message(json)
else: # for looser
json["info"] = "YOU LOSE..."
json["you"] = self.winnerCOLOR(opponent=True, string=True)
self.write_message(json)
else:
# for audience
json["info"] = "%s WIN!!" % self.winnerCOLOR(string=True)
json["you"] = "AUDIENCE"
json["connection"] = "<font color='red'>A.I.</font> vs. PLAYER<br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
self.write_message(json)
def win_gameover(self):
logging.info(self.winnerCOLOR(string=True)+" win!!")
# this method should be called once just after the game is over
# this is designed to be called by winner
if not SocketHandler.board.winner:
raise
json = {}
json["type"] = "GAMEOVER"
json["html"] = tornado.escape.to_basestring(self.render_string("board.html", board=SocketHandler.board.get_scene_dict()))
json["scene"] = SocketHandler.board.get_scene_list()
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
# for winner
json["info"] = "YOU WIN!!"
json["you"] = self.winnerCOLOR(string=True)
self.write_message(json)
# for looser
json["info"] = "YOU LOSE..."
json["you"] = self.winnerCOLOR(opponent=True, string=True)
self.opponent_player().write_message(json)
# for audience
json["info"] = "%s WIN!!" % self.winnerCOLOR(string=True)
json["you"] = "AUDIENCE"
json["connection"] = "<font color='red'>A.I.</font> vs. PLAYER<br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
for waiter in SocketHandler.waiters:
if not waiter in SocketHandler.players:
try:
waiter.write_message(json)
except:
logging.error("Error sending message", exc_info=True)
def on_message(self, message):
logging.info("got message %r", message)
parsed = tornado.escape.json_decode(message)
json = {}
if self in SocketHandler.players:
json["connection"] = "<font color='red'>A.I.</font> vs. <b>YOU</b><br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
else:
json["connection"] = "<font color='red'>A.I.</font> vs. PLAYER<br>AUDIENCE:%d" % (len(SocketHandler.waiters)-2)
if parsed["type"] == "MOVE":
if SocketHandler.board.winner:
json["type"] = "ERROR"
json["html"] = "Game Is Over!"
self.write_message(json)
return
if self in SocketHandler.players and SocketHandler.board.nextColor==self.COLOR():
try:
SocketHandler.board.user_put(parsed["body"], self.COLOR())
except (ValueError, IndexError),mes:
json["type"] = "ERROR"
json["html"] = str(mes)
self.write_message(json)
else:
if SocketHandler.board.is_finished():
SocketHandler.board.winner = self.COLOR()
self.win_gameover()
else:
SocketHandler.board.nextColor = self.COLOR(opponent=True)
self.update_board()
else:
json["type"] = "ERROR"
json["html"] = "Not your turn!"
self.write_message(json)
elif parsed["type"] == "RESET":
#if self in SocketHandler.players:
# self.reset_board()
self.reset_board()