Last active
March 28, 2016 20:37
-
-
Save vladimiroff/633dec5791d59d3a4f5b to your computer and use it in GitHub Desktop.
tictactoe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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