-
Notifications
You must be signed in to change notification settings - Fork 0
/
ttt_module.py
173 lines (141 loc) · 5.37 KB
/
ttt_module.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
"""
Tic Tac Toe (and more generally, 2-D grid environments) that display in browser.
Created by Peter Norvig
NB: need to work on both Python 2 and 3
"""
##############################################################################
# CSS and HTML
##############################################################################
if False:
def setCSS(text):
"Set (or append??) CSS to be text."
global __CSS__
__CSS__ = text
print('setCSS: ' + text)
def setHTML(text):
"Set (or append??) HTML to be text."
global __HTML__
__HTML__ = text
print('setHTML: ' + text)
def tagger(tagname):
"Make a function that can be used to generate HTML."
def tagfn(*content, **kwargs):
args = ('' if not kwargs else
' ' + ' '.join('{}={!r}'.format(k, kwargs[k]) for k in kwargs))
return "<{}{}>{}</{}>".format(
tagname, args, join(content), tagname)
#tagfn.__name__ = tagname # not allowed in OPT sandbox
return tagfn
A, B, I, P, TABLE, TR, TD, TH = map(tagger, 'A B I P, TABLE TR TD TH'.split())
def join(content):
"Like ' '.join(content), but recurses into nested lists."
return (content if isinstance(content, str) else
' '.join(map(join, content)) if isinstance(content, (list, tuple)) else
str(content))
# Python 3 doesn't have xrange, so bind it to range
try:
_ = xrange
except NameError:
xrange = range
def table(matrix, **kwargs):
"""Given [[a, b, c], [d, e, f]], lay it out as a table.
Each cell gets an id number, starting at 0. Table can have kwargs."""
ints = iter(xrange(1000000))
return TABLE([TR([TD(c, id=next(ints)) for c in row])
for row in matrix],
**kwargs)
css = """#htmlOutputDiv table, #htmlOutputDiv td, #htmlOutputDiv th {
background-color: white;
border-collapse: collapse;
border: 2px solid black; }
#htmlOutputDiv td, #htmlOutputDiv th {
width: 30px;
height: 30px;
font-family: sans-serif;
text-align: center; }"""
class Game(object):
"Move stuff here later"
pass
class TTTGame(Game):
def __init__(self, player1, player2, verbose=True):
print('Initializing TTTGame')
self.board = [' '] * 9 # board is 1-D array of squares; can be mapped to 2-D.
self.tomove = 0
self.symbols = ['X', 'O']
self.players = [player1, player2] # player strategy functions
self.lines = [(0, 1, 2), (3, 4, 5), (6, 7, 8),
(0, 3, 6), (1, 4, 7), (2, 5, 8),
(0, 4, 8), (2, 4, 6)]
self.winner = None
self.verbose = verbose
# mouse handler for board
# TODO: clean this up
setJS("$('#htmlOutputDiv table td').click(function(){myVisualizer.executeCodeWithRawInputFunc($(this).attr('id'), myVisualizer.curInstr)})")
def draw(self):
setCSS(css)
s = table([[self.board[3*r + c] for c in range(3)] for r in range(3)])
if self.over():
s += P('Game over; ', 'nobody' if self.winner is None else self.symbols[self.winner], ' wins')
else:
s += P(self.symbols[self.tomove] + ' to play')
if self.verbose: print(s)
setHTML(s)
return s
def play(self):
self.draw()
#while not self.over():
for i in range(2):
p = self.tomove
move = self.players[p](list(self.board), self.symbols[p])
self.makemove(move)
self.draw()
def displayWarning(self, msg):
print('WARNING! ' + msg)
def makemove(self, move):
player = self.tomove
print('making move ' + str(move) + ' for player ' + str(player))
if self.over():
self.displayWarning('game over, no more moves')
elif move not in range(9):
self.displayWarning('not a legal square ' + str(move))
return None
elif self.board[move] != ' ':
self.displayWarning('not an empty square ' + str(move))
return None
else:
self.board[move] = self.symbols[player]
self.tomove = other(player)
return move
def legal(self, move):
"A legal move is an index to a blank square."
return move in range(9) and self.board[move] == ' '
def over(self):
"Return True when game is over."
if ' ' not in self.board:
winner = None
return True # no moves left; game is a draw
for player in [0, 1]:
for line in self.lines:
if self.linecount(line, player) == 3:
self.winner = player
return True
return False
def playgame(self):
while not self.over():
self.makemove()
def linecount(self, line, player):
"Return the number of pieces that player (0 or 1) has on this line."
return [self.board[i] for i in line].count(self.symbols[player])
def illegalmove(self, move):
"Report that move is illegal; decrement remaining count for player."
## How to report ???
self.allowed_illegal_moves[self.tomove] -= 1
if self.allowed_illegal_moves[self.tomove] < 0:
### Report game over on illegal move ???
self.winner = other(self.tomove)
def copystate(self):
clone = TTTGame(*self.players)
clone.tomove = self.tomove
clone.board = list(self.board)
return clone
def other(player): return 1 - player