Skip to content

Instantly share code, notes, and snippets.

@thomasballinger
Created January 23, 2014 00:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomasballinger/8570367 to your computer and use it in GitHub Desktop.
Save thomasballinger/8570367 to your computer and use it in GitHub Desktop.
Examples of Python syntax
"""An immutable Tic Tac Toe board and minimax ai"""
import itertools
class Board(object):
"""Immutable Tic Tac Toe board
>>> Board().rows
((' ', ' ', ' '), (' ', ' ', ' '), (' ', ' ', ' '))
>>> print Board()
| |
-----
| |
-----
| |
>>> Board().columns
((' ', ' ', ' '), (' ', ' ', ' '), (' ', ' ', ' '))
>>> Board().turn
0
>>> Board().whose_turn
'x'
>>> b = Board().move(2); print b
| |x
-----
| |
-----
| |
>>> b.possible()
[< Board |o.x......| >, < Board |.ox......| >, < Board |..xo.....| >, < Board |..x.o....| >, < Board |..x..o...| >, < Board |..x...o..| >, < Board |..x....o.| >, < Board |..x.....o| >]
"""
def __init__(self, width=3, height=3):
self._rows = [[' ' for _ in range(width)] for _ in range(height)]
rows = property(lambda self: tuple(tuple(row) for row in self._rows))
columns = property(lambda self: tuple(zip(*self._rows)))
spots = property(lambda self: tuple(c for row in self._rows for c in row))
def __str__(self):
return ('\n'+'-'*(len(self.columns)*2-1) + '\n').join(['|'.join(row) for row in self._rows])
def __repr__(self): return '< Board |'+''.join(self.spots).replace(' ','.')+'| >'
def __eq__(self, other): return self.spots == other.spots
@property
def turn(self):
return 9 - self.spots.count(' ')
@property
def whose_turn(self):
return 'xo'[self.turn % 2]
def winner(self):
for c in 'xo':
for comb in [(0,3,6), (1,4,7), (2,5,8), (0,1,2), (3,4,5), (6,7,8), (0,4,8), (2,4,6)]:
if all(self.spots[p] == c for p in comb):
return c
return None
def move(self, pos):
assert self.spots[pos] == ' '
new = Board(len(self.rows), len(self.columns))
new._rows = list(list(row) for row in self.rows)
new._rows[pos / 3][pos % 3] = self.whose_turn
return new
def possible(self):
return [self.move(p) for p in range(len(self.spots)) if self.spots[p] == ' ']
def opp(c):
"""
>>> opp('x'), opp('o')
('o', 'x')
"""
return 'x' if c == 'o' else 'o'
def value(board, who='x'):
"""Returns the value of a board
>>> b = Board(); b._rows = [['x', 'x', 'x'], ['x', 'x', 'x'], ['x', 'x', 'x']]
>>> value(b)
1
>>> b = Board(); b._rows = [['o', 'o', 'o'], ['o', 'o', 'o'], ['o', 'o', 'o']]
>>> value(b)
-1
>>> b = Board(); b._rows = [['x', 'o', ' '], ['x', 'o', ' '], [' ', ' ', ' ']]
>>> value(b)
1
>>> b._rows[0][2] = 'x'
>>> value(b)
-1
"""
w = board.winner()
if w == who: return 1
if w == opp(who): return -1
if board.turn == 9: return 0
if who == board.whose_turn: return max([value(b, who) for b in board.possible()])
else: return min([value(b, who) for b in board.possible()])
def ai(board):
"""Returns best next board
>>> b = Board(); b._rows = [['x', 'o', ' '], ['x', 'o', ' '], [' ', ' ', ' ']]
>>> ai(b)
< Board |xo.xo.x..| >
>>> b = Board(); b._rows = [['x', ' ', ' '], [' ', 'x', 'o'], [' ', ' ', ' ']]
>>> ai(b)
< Board |x...xo..o| >
"""
return sorted([(value(b, who=board.whose_turn), b) for b in board.possible()])[-1][1]
def human(board):
"""Returns the next board as selected by raw_input"""
while True:
x = int(raw_input('x:'))
y = int(raw_input('y:'))
if not (0 <= x <= 2 and 0 <= y <= 2): continue
s = x + y*3
if board.spots[s] != ' ': continue
return board.move(x+y*3)
def play():
b = Board()
for player in itertools.cycle([human, ai]):
print player.__name__, 'move...'
print b
b = player(b)
if b.winner() or b.turn == 9:
break
print '%s won!' % (b.winner() or 'no one')
if __name__ == '__main__':
import doctest
doctest.testmod(verbose=True)
play()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment