Skip to content

Instantly share code, notes, and snippets.

@braised-babbage
Created May 7, 2019 04:12
Show Gist options
  • Save braised-babbage/4aeba698b6128146cb1c084243c4f7bc to your computer and use it in GitHub Desktop.
Save braised-babbage/4aeba698b6128146cb1c084243c4f7bc to your computer and use it in GitHub Desktop.
a simple game of tic-tac-toe
from dataclasses import dataclass
from typing import Tuple
PLAYER_X = 'X'
PLAYER_O = 'O'
EMPTY = ' '
def other(player):
return PLAYER_O if player == PLAYER_X else PLAYER_X
@dataclass
class GameState:
board: Tuple[str]
to_move: str
MOVES = "A0 B0 C0 A1 B1 C1 A2 B2 C2".split()
def initial_state():
"The state at the beginning of a game."
return GameState(board=tuple([EMPTY]*9),
to_move=PLAYER_X)
LINES = [
[0,1,2],
[3,4,5],
[6,7,8],
[0,3,6],
[1,4,7],
[2,5,8],
[0,4,8],
[2,4,6]
]
def game_over(state):
"""Is the game over?
If so, return the winning player.
"""
board = state.board
for x,y,z in LINES:
if board[x] == EMPTY:
continue
elif board[x] == board[y] == board[z]:
return board[x]
return None
def render(state):
"Draw the game board associated with this state."
border = " +---+---+---+"
row = lambda i: "{} | {} | {} | {} |".\
format(i, *(state.board[3*i:3*(i+1)]))
print(f" A B C")
for i in range(3):
print(border)
print(row(i))
print(border, "\n")
def prompt_move(state):
"Primpt the current player for a move."
while True:
try:
move = input(f"Please enter a move (Player {state.to_move}): ")
pos = MOVES.index(move.upper())
if state.board[pos] == EMPTY:
return pos
print("That square is already occupied!")
except ValueError:
print("Valid moves must be from [A-C][0-2].")
def do_move(state, pos):
"Apply a move, returning an updated state."
if state.board[pos] != EMPTY:
raise ValueError(f"Expected an empty square at {pos}, \
but found {state.board[pos]}")
updated = state.board[:pos] + (state.to_move,) + state.board[pos+1:]
return GameState(board=updated,
to_move=other(state.to_move))
def play():
"Play a game from start to finish."
state = initial_state()
while True:
render(state)
pos = prompt_move(state)
state = do_move(state, pos)
winner = game_over(state)
if winner is not None:
render(state)
print(f"Player {winner} is the winner!")
break
if __name__ == "__main__":
play()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment