Created
August 21, 2016 02:16
-
-
Save hdorothea/8cc12bb6c98765071d7ffbcf62b7c741 to your computer and use it in GitHub Desktop.
A simple tic-tac-toe game in Python
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 itertools | |
class Board(object): | |
def __init__(self): | |
self.rows = [[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']] | |
@property | |
def diagonals(self): | |
return [[self.rows[0][0], self.rows[1][1], self.rows[2][2]], | |
[self.rows[0][2], self.rows[1][1], self.rows[2][0]]] | |
@property | |
def columns(self): | |
return map(list, zip(*self.rows)) | |
def __str__(self): | |
return " a b c\n0 {}\n1 {}\n2 {}".format(' '.join(self.rows[0]), | |
' '.join(self.rows[1]), | |
' '.join(self.rows[2])) | |
def update_board(board, player, coordinates): | |
board.rows[coordinates[0]][coordinates[1]] = player | |
def check_win(board): | |
lines = board.rows + board.columns + board.diagonals | |
for line in lines: | |
if (all(board_position == 'X' for board_position in line) or | |
all(board_position == 'O' for board_position in line)): | |
return True | |
def parse_coordinates(input_coordinates, board): | |
letters_to_numbers = {'a': 0, 'b': 1, 'c': 2} | |
try: | |
coordinates = (int(input_coordinates[0]), | |
letters_to_numbers[input_coordinates[1]]) | |
except (ValueError, KeyError): | |
coordinates = (int(input_coordinates[1]), | |
letters_to_numbers[input_coordinates[0]]) | |
if (coordinates[0] > (len(board.rows) - 1)): | |
raise ValueError('Out of bound coordinates') | |
if board.rows[coordinates[0]][coordinates[1]] != ' ': | |
raise ValueError('Duplicate coordinates') | |
return coordinates | |
def play(): | |
board = Board() | |
players = itertools.cycle(['X', 'O']) | |
for x in range(9): | |
player = players.next() | |
print board | |
print ('Player-{} please enter the coordinates for your move' | |
.format(player)) | |
while True: | |
try: | |
input_coordinates = raw_input() | |
coordinates = parse_coordinates(input_coordinates, board) | |
except (ValueError, IndexError, KeyError): | |
print 'The coordinates you entered are not valid. Re-enter.' | |
continue | |
break | |
update_board(board, player, coordinates) | |
if x > 5: | |
if check_win(board): | |
print 'Player-{} won!'.format(player) | |
return | |
print 'The game ended in a draw' | |
if __name__ == '__main__': | |
play() |
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 tictactoe import Board, update_board, check_win, parse_coordinates | |
class TicTacTest(unittest.TestCase): | |
def test_board_columns(self): | |
board = Board() | |
board.rows = [['00', '01', '02'], | |
['10', '11', '12'], | |
['20', '21', '22']] | |
expected_columns = [['00', '10', '20'], | |
['01', '11', '21'], | |
['02', '12', '22']] | |
self.assertEqual(expected_columns, board.columns) | |
def test_board_diagonals(self): | |
board = Board() | |
board.rows = [['00', '01', '02'], | |
['10', '11', '12'], | |
['20', '21', '22']] | |
expected_diagonals = [['00', '11', '22'], ['02', '11', '20']] | |
self.assertEqual(expected_diagonals, board.diagonals) | |
def test_update_board(self): | |
board = Board() | |
update_board(board, 'X', (1, 1)) | |
expected_rows_columns = [[' ', ' ', ' '], | |
[' ', 'X', ' '], | |
[' ', ' ', ' ']] | |
expected_diagonals = [[' ', 'X', ' '], [' ', 'X', ' ']] | |
self.assertEqual(expected_rows_columns, board.columns) | |
self.assertEqual(expected_rows_columns, board.rows) | |
self.assertEqual(expected_diagonals, board.diagonals) | |
def test_check_column_win(self): | |
board = Board() | |
board.rows = [['X', ' ', ' '], ['X', ' ', ' '], ['X', ' ', ' ']] | |
self.assertTrue(check_win(board)) | |
def test_check_row_win(self): | |
board = Board() | |
board.rows = [['X', 'X', 'X'], [' ', ' ', ' '], [' ', ' ', ' ']] | |
self.assertTrue(check_win(board)) | |
def test_check_first_diagonal_win(self): | |
board = Board() | |
board.rows = [['X', ' ', ' '], [' ', 'X', ' '], [' ', ' ', 'X']] | |
self.assertTrue(check_win(board)) | |
def test_check_second_diagonal_win(self): | |
board = Board() | |
board.rows = [[' ', ' ', 'X'], [' ', 'X', ' '], ['X', ' ', ' ']] | |
self.assertTrue(check_win(board)) | |
def test_parse_coordinates(self): | |
board = Board() | |
input_coordinates_1 = '1b' | |
input_coordinates_2 = 'b1' | |
expected_parsed_coordinates = (1, 1) | |
self.assertEqual(expected_parsed_coordinates, | |
parse_coordinates(input_coordinates_1, board)) | |
self.assertEqual(expected_parsed_coordinates, | |
parse_coordinates(input_coordinates_2, board)) | |
def test_parse_duplicate_coordinates(self): | |
board = Board() | |
board.rows = [['X', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']] | |
self.assertRaises(ValueError, parse_coordinates, '0a', board) | |
def test_parse_outofbound_coordinates(self): | |
board = Board() | |
self.assertRaises(ValueError, parse_coordinates, '0d', board) | |
if __name__ == '__main__': | |
unittest.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can we run the unit test code for testing