Skip to content

Instantly share code, notes, and snippets.

@T-Dimov
Last active March 30, 2016 17:31
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 T-Dimov/261ed1a9e244025d84dc8ad00674b827 to your computer and use it in GitHub Desktop.
Save T-Dimov/261ed1a9e244025d84dc8ad00674b827 to your computer and use it in GitHub Desktop.
import unittest
from tic_tac_toe import (
Board, IllegalMoveError, WrongTurnError, ChangeMoveError,
GameEndError,
IN_PROGRESS, X_WON, O_WON, DRAW, X, O, EMPTY as E)
class TestBoard(unittest.TestCase):
def setUp(self):
self.board = Board()
self.big_board = Board(5)
def test_input_format(self):
with self.assertRaises(ValueError):
self.board["1A"] = X
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'], E)
def test_change_move(self):
self.board['A1'] = X
with self.assertRaises(ChangeMoveError):
self.board['A1'] = O
def test_place_illegal_chars(self):
with self.assertRaises(ValueError):
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._grid = [
[X, X, X],
[O, O, E],
[E, E, E],
]
self.assertEqual(self.board.state, X_WON)
self.board._grid = [
[X, O, O],
[X, E, E],
[X, E, E],
]
self.assertEqual(self.board.state, X_WON)
self.board._grid = [
[X, O, O],
[E, X, E],
[E, E, X],
]
self.assertEqual(self.board.state, X_WON)
def test_game_o_won(self):
self.board._grid = [
[O, O, O],
[X, X, E],
[E, E, E],
]
self.assertEqual(self.board.state, O_WON)
self.board._grid = [
[O, X, X],
[O, E, E],
[O, E, E],
]
self.assertEqual(self.board.state, O_WON)
self.board._grid = [
[O, X, X],
[E, O, E],
[E, E, O],
]
self.assertEqual(self.board.state, O_WON)
def test_draw(self):
self.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._grid = [
[O, X, X],
[E, O, E],
[E, E, O],
]
with self.assertRaises(GameEndError):
self.board['B1'] = X
def test_to_string(self):
self.board._grid = [
[O, E, O],
[E, X, E],
[O, E, O],
]
expected = """
1 2 3
A O | | O
---|---|---
B | X |
---|---|---
C O | | O
"""
self.assertEqual(str(self.board), expected)
def test_create_bigger(self):
test_board = [
[E, E, E, E, E],
[E, E, E, E, E],
[E, E, E, E, E],
[E, E, E, E, E],
[E, E, E, E, E]
]
self.assertEqual(self.big_board._grid, test_board)
def test_import(self):
grid = [
[O, E, O],
[E, X, E],
[O, E, O],
]
self.board.import_board(grid)
self.assertEqual(self.board._grid, grid)
def test_export(self):
grid = [
[O, E, O],
[E, X, E],
[O, E, O],
]
self.board.import_board(grid)
self.assertEqual(self.board.export_board(), grid)
def test_invalid_board_size(self):
with self.assertRaises(ValueError):
Board(2)
if __name__ == '__main__':
unittest.main()
from copy import deepcopy
X = 'X'
O = 'O'
EMPTY = ' '
IN_PROGRESS = 0
X_WON = 1
O_WON = 2
DRAW = 3
class Board:
def __init__(self, size=3):
self._on_turn = X
self.__size = int(size)
if self.__size < 3 or self.__size > 9:
raise ValueError("Invalid game board size!")
self.__valid_fst = set(map(lambda a: chr(a+65), range(self.__size)))
self.__valid_snd = set(map(lambda a: a + 1, range(self.__size)))
self._grid = [[EMPTY] * self.__size for _ in range(self.__size)]
def import_board(self, board):
self._grid = board
def export_board(self):
return self._grid
@property
def state(self):
lines = deepcopy(self._grid)
columns = zip(*self._grid)
diagonals = ([(i, i) for i in range(self.__size)],
[(i, self.__size - i - 1) for i in range(self.__size)])
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: EMPTY in line, self._grid)):
return DRAW
return IN_PROGRESS
def _convert_to_coords(self, key):
if any([len(key) != 2,
key[0] not in self.__valid_fst,
int(key[1]) not in self.__valid_snd]):
raise IndexError("Invalid board coordinates!")
return ord(key[0]) - ord('A'), int(key[1]) - 1
def __setitem__(self, key, value):
if self.state != IN_PROGRESS:
raise GameEndError("Game over!")
x, y = self._convert_to_coords(key)
if self._grid[x][y] != EMPTY:
raise ChangeMoveError("You can't change moves!")
if value not in {X, O}:
raise ValueError("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]
def __str__(self):
valid_fst = sorted(self.__valid_fst)
valid_snd = map(lambda a: str(a), sorted(self.__valid_snd))
result = "\n {} \n\n".format(" ".join(valid_snd))
ind = 0
for row in self._grid[:-1]:
result += "{} {} \n".format(valid_fst[ind], " | ".join(row))
result += " {}---\n".format("---|" * (self.__size - 1))
ind += 1
result += "{} {}\n".format(valid_fst[ind], " | ".join(self._grid[-1]))
return result
class IllegalMoveError(Exception):
pass
class WrongTurnError(IllegalMoveError):
pass
class ChangeMoveError(IllegalMoveError):
pass
class GameEndError(IllegalMoveError):
pass
def main():
player = "one"
next_mark = X
board_size = input("Please enter the size of the board: ")
try:
game = Board(board_size)
except ValueError as error:
print("{}\nThe game will now end.".format(error))
else:
while not game.state:
try:
print(game)
move_addr = input("Player {} enter your move: ".format(player))
game[str(move_addr)] = next_mark
except ValueError:
print("Invalid input type or format!\nValid format is: A1")
except ChangeMoveError as error:
print("{}\nPlease try again.".format(error))
except IndexError as error:
print("{}\nPlease try again.".format(error))
else:
next_mark = X if next_mark == O else O
player = "one" if player == "two" else "two"
print(game)
if game.state == 1:
print("Player one won!")
elif game.state == 2:
print("Player two won!")
else:
print("The game ended in a draw!")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment