Created
July 20, 2019 23:27
-
-
Save dyspop/224cd307f0e5ecee616553ee7423aec1 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
""" Tic tac toe code exercise with dataclasses. | |
Usage: | |
import tictactoe as ttt | |
game = ttt.Game() | |
game.make_move(x, y) | |
""" | |
from dataclasses import dataclass | |
import collections | |
@dataclass | |
class Game: | |
"""Class for keeping track of the game state.""" | |
rows: int = 3 | |
columns: int = 3 | |
board: str = None | |
players: str = None | |
whose_turn: str = 'X' | |
empty_char: str = '*' | |
winner = None | |
def __init__(self): | |
self.board = [] | |
for pos in range(self.rows): | |
self.board.append( | |
[self.empty_char] * self.columns) | |
self.players = ['X', 'O'] | |
self.print_board() | |
self.message_next_turn() | |
def message_next_turn(self): | |
print(f'{self.whose_turn}\'s move') | |
def is_winning_set(self, positions): | |
if (len(positions) is 1) and (self.empty_char not in positions): | |
return ''.join(positions) | |
else: | |
return None | |
def find_horizontal_winner(self, board): | |
for row in board: | |
row_set = set(row) | |
is_winner = self.is_winning_set(set(row)) | |
if is_winner is not None: | |
return is_winner | |
def evaluate_game(self): | |
# Check rows for winner | |
winner = self.find_horizontal_winner(self.board) | |
if winner is not None: | |
return winner | |
# Check columns (rotated board) for winner | |
rotated_board = ("\n".join(map( | |
"".join,zip(*self.board)))).split('\n') | |
winner = self.find_horizontal_winner(rotated_board) | |
if winner is not None: | |
return winner | |
# Check diamond for winner, only do it on an odd-sized square board | |
if ( | |
(self.rows * self.columns) % 2 == 1 | |
) and self.rows == self.columns: | |
winner = self.is_winning_set(set([ | |
# Rewrite as list comprehension? | |
self.board[0][0], | |
self.board[1][1], | |
self.board[2][2] | |
])) | |
if winner is not None: | |
return winner | |
winner = self.is_winning_set(set([ | |
# Rewrite as list comprehension? | |
self.board[2][0], | |
self.board[1][1], | |
self.board[0][2] | |
])) | |
if winner is not None: | |
return winner | |
return winner | |
def print_board(self): | |
for row in self.board: | |
print(' '.join(row)) | |
def make_move(self, x, y): | |
# Lock out making moves on a won game | |
if self.winner is None: | |
# Lock out making moves on a filled position | |
if self.board[x][y] == self.empty_char: | |
# Add the move to the position whose turn it is | |
self.board[x][y] = self.whose_turn | |
# Rotate the player whose turn it is | |
self.whose_turn = self.players[( | |
self.players.index(self.whose_turn) + 1 | |
) % len(self.players)] | |
# Show the updated board results | |
self.print_board() | |
# Find a winner | |
self.winner = self.evaluate_game() | |
# If no winner say whose turn it is next | |
if self.winner is None: | |
self.message_next_turn() | |
else: | |
print(f'{self.winner} wins!') | |
else: | |
raise ValueError(f'Board is already filled at {x}, {y}') | |
else: | |
print(f'Game completed.\n{self.winner} Won!\n\nStart a new game.') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment