Skip to content

Instantly share code, notes, and snippets.

@vladimiroff
Last active March 28, 2016 20:37
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 vladimiroff/633dec5791d59d3a4f5b to your computer and use it in GitHub Desktop.
Save vladimiroff/633dec5791d59d3a4f5b to your computer and use it in GitHub Desktop.
tictactoe
import unittest
from tictac import (
Board, IllegalMoveError, WrongTurnError,
IN_PROGRESS, X_WON, O_WON, DRAW)
class TestBoard(unittest.TestCase):
def setUp(self):
self.board = Board()
def test_size(self):
self.assertEqual(self.board.width, 3)
self.assertEqual(self.board.height, 3)
def test_make_a_move(self):
self.board["A1"] = 'X'
self.assertEqual(self.board['A1'], 'X')
def test_make_an_invalid_move(self):
with self.assertRaises(IndexError):
self.board["Щ5"] = 'X'
with self.assertRaises(IndexError):
self.board["A42"] = 'O'
def test_misunderstood_move(self):
with self.assertRaises(IndexError):
self.board["A12"] = 'X'
self.assertEqual(self.board['A1'], ' ')
def test_change_move(self):
self.board['A1'] = 'X'
with self.assertRaises(IllegalMoveError):
self.board['A1'] = 'O'
def test_place_illegal_chars(self):
with self.assertRaises(IllegalMoveError):
self.board['A1'] = 'Щ'
def test_two_moves_by_the_same_player(self):
self.board['A1'] = 'X'
with self.assertRaises(WrongTurnError):
self.board['A2'] = 'X'
def test_game_state_in_progress(self):
self.assertEqual(self.board.state, IN_PROGRESS)
def test_game_x_won(self):
self.board._Board__grid = [
['X', 'X', 'X'],
['O', 'O', ' '],
[' ', ' ', ' '],
]
self.assertEqual(self.board.state, X_WON)
self.board._Board__grid = [
['X', 'O', 'O'],
['X', ' ', ' '],
['X', ' ', ' '],
]
self.assertEqual(self.board.state, X_WON)
self.board._Board__grid = [
['X', 'O', 'O'],
[' ', 'X', ' '],
[' ', ' ', 'X'],
]
self.assertEqual(self.board.state, X_WON)
def test_game_o_won(self):
self.board._Board__grid = [
['O', 'O', 'O'],
['X', 'X', ' '],
[' ', ' ', ' '],
]
self.assertEqual(self.board.state, O_WON)
self.board._Board__grid = [
['O', 'X', 'X'],
['O', ' ', ' '],
['O', ' ', ' '],
]
self.assertEqual(self.board.state, O_WON)
self.board._Board__grid = [
['O', 'X', 'X'],
[' ', 'O', ' '],
[' ', ' ', 'O'],
]
self.assertEqual(self.board.state, O_WON)
def test_draw(self):
self.board._Board__grid = [
['O', 'X', 'X'],
['X', 'X', 'O'],
['O', 'O', 'X'],
]
self.assertEqual(self.board.state, DRAW)
def test_move_on_ended_game(self):
self.board._Board__grid = [
['O', 'X', 'X'],
[' ', 'O', ' '],
[' ', ' ', 'O'],
]
with self.assertRaises(IllegalMoveError):
self.board['B1'] = 'X'
if __name__ == '__main__':
unittest.main()
from copy import deepcopy
X = 'X'
O = 'O'
IN_PROGRESS = 0
X_WON = 1
O_WON = 2
DRAW = 3
class Board:
width = 3
height = 3
def __init__(self):
self._on_turn = X
self.__grid = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' '],
]
@property
def state(self):
lines = deepcopy(self.__grid)
columns = zip(*self.__grid)
diagonals = (((0, 0), (1, 1), (2, 2)),
((0, 2), (1, 1), (2, 0)))
for diagonal in diagonals:
lines.append([self.__grid[x][y] for x, y in diagonal])
lines.extend(columns)
for line in lines:
if set(line) == {X}:
return X_WON
elif set(line) == {O}:
return O_WON
if not any(map(lambda line: ' ' in line, self.__grid)):
return DRAW
return IN_PROGRESS
def _convert_to_coords(self, key):
if any([len(key) != 2,
key[0] not in {'A', 'B', 'C'},
int(key[1]) not in {1, 2, 3}]):
raise IndexError
return ord(key[0]) - ord('A'), int(key[1]) - 1
def __setitem__(self, key, value):
if self.state != IN_PROGRESS:
raise IllegalMoveError("Game over")
x, y = self._convert_to_coords(key)
if self.__grid[x][y] != ' ':
raise IllegalMoveError("You can't change moves!")
if value not in {X, O}:
raise IllegalMoveError("You must place X or O")
if value != self._on_turn:
raise WrongTurnError("{} is on turn".format(self._on_turn))
self._on_turn = X if self._on_turn == O else O
self.__grid[x][y] = value
def __getitem__(self, key):
x, y = self._convert_to_coords(key)
return self.__grid[x][y]
class IllegalMoveError(Exception):
pass
class WrongTurnError(Exception):
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment