Skip to content

Instantly share code, notes, and snippets.

@dyspop
Created July 20, 2019 23:27
Show Gist options
  • Save dyspop/224cd307f0e5ecee616553ee7423aec1 to your computer and use it in GitHub Desktop.
Save dyspop/224cd307f0e5ecee616553ee7423aec1 to your computer and use it in GitHub Desktop.
""" 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