Skip to content

Instantly share code, notes, and snippets.

@PiotrJander
Last active July 19, 2022 19:04
Show Gist options
  • Save PiotrJander/115c4dba96a11ccbd5bacb98ce597519 to your computer and use it in GitHub Desktop.
Save PiotrJander/115c4dba96a11ccbd5bacb98ce597519 to your computer and use it in GitHub Desktop.
## helper functions
"""
Constructs a board from a string.
s: a string representation of the board
Returns: a parsed board
E.g.:
b("X__|_O_|__X")
will produce
X | |
| O |
| | X
"""
def b(s):
string_rows = s.split("|")
rows = []
for string_row in string_rows:
rows.append([None if char == "_" else char for char in list(string_row)])
return rows
"""
Stringifies a board.
board: a 3x3 array
Returns: a string representing the board
E.g. when `board` is
X | |
| O |
| | X
s(board) will produce "X__|_O_|__X"
"""
def s(board):
rows = []
for row in board:
rows.append("".join(["_" if cell is None else cell for cell in row]))
return "|".join(rows)
# actual program
def _repr_cell(cell):
return " " if cell is None else cell
def _print_row(row):
print(f"{_repr_cell(row[0])} | {_repr_cell(row[1])} | {_repr_cell(row[2])}")
def _print_row_delimiter():
print("--+---+---")
def print_board(board):
"""Print a pretty representation of the given board state.
board: a 3x3 array of X/O/None
"""
_print_row(board[0])
_print_row_delimiter()
_print_row(board[1])
_print_row_delimiter()
_print_row(board[2])
def is_won(board, player):
"""Checks if the board is won for the given player.
board: a 3x3 array
player: X or O
Returns: boolean
>>> is_won(b('XXX|OO_|_OO'), 'X')
True
>>> is_won(b('XXX|OO_|_OO'), 'O')
False
"""
return (board[0][0] == board[1][1] == board[2][2] == player
or board[0][2] == board[1][1] == board[2][0] == player
or board[0][0] == board[0][1] == board[0][2] == player
or board[1][0] == board[1][1] == board[1][2] == player
or board[2][0] == board[2][1] == board[2][2] == player
or board[0][0] == board[1][0] == board[2][0] == player
or board[0][1] == board[1][1] == board[2][1] == player
or board[0][2] == board[1][2] == board[2][2] == player)
def is_draw(board):
for row in board:
for cell in row:
if cell is None:
return False
else:
return True
def read_coordinate(prompt):
"""Reads and validates a coordinate from user's input.
E.g.
`read_coordinate("X's turn. Please choose row: ")`
would print
`X's turn. Please choose row: _`
and then read user's input.
"""
while True:
coor = int(input(prompt))
if coor == 0 or coor == 1 or coor == 2:
return coor
else:
print("The coordinate must be a number: 0 or 1 or 2")
def read_coordinates(player):
"""Reads and validates row and column coordinates from user's input.
E.g.
`read_coordinates('O')`
would print and read
`O's turn. Please choose row: _`
and then
`O's turn. Please choose column: _`
"""
x = read_coordinate(f"{player}'s turn. Please choose row: ")
y = read_coordinate(f"{player}'s turn. Please choose column: ")
return x, y
def play_turn(board, player):
"""Plays a turn. Reads a valid user input and checks whether user won
after the turn.
board: a 3x3 array of X/O/None
player: X or O
Returns: boolean, true when player won after this turn
"""
while True:
print_board(board)
x, y = read_coordinates(player)
if board[x][y] is None:
board[x][y] = player
break
else:
print("The cell is taken. Please choose a free cell.")
return is_won(board, player)
def play():
"""Plays a game of Tic-Tac-Toe"""
board = [[None] * 3 for _ in range(3)]
while True:
x_won = play_turn(board, 'X')
if x_won:
print("X wins!")
print_board(board)
break
if is_draw(board):
print('Draw!')
break;
o_won = play_turn(board, 'O')
if o_won:
print("O wins!")
print_board(board)
break
if is_draw(board):
print('Draw!')
break;
if __name__ == "__main__":
import doctest
doctest.testmod()
play()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment