|
from IPython.display import clear_output |
|
|
|
|
|
def make_board(size: int) -> list: |
|
''' |
|
Function generates a board of size * size (kind of a 2D matrix) |
|
''' |
|
return list(range(size * size)) |
|
|
|
|
|
def make_rows(game_board: list, size: int) -> list: |
|
''' |
|
Create a matrix from the flat game_board list |
|
''' |
|
return [game_board[i:i + size] for i in range(0, size * size, size)] |
|
|
|
|
|
def is_valid_symbol(player_symbol: str) -> tuple[bool, str]: |
|
''' |
|
Check for the symbol to be on the valid options X or O |
|
''' |
|
symbol = str(player_symbol) |
|
|
|
is_valid = True if symbol.upper() == 'O' or \ |
|
symbol.upper() == 'X' else False |
|
|
|
return is_valid, symbol.upper() |
|
|
|
|
|
def spot_taken(game_board: list, position: int) -> bool: |
|
''' |
|
Check if spot was already take |
|
''' |
|
return game_board[position] == 'X' or game_board[position] == 'O' |
|
|
|
|
|
def place_symbol_in_to_position( |
|
game_board: list, |
|
user_symbol: str, |
|
position: int) -> list: |
|
''' |
|
Stores the player_symbol in a position of the game_board |
|
''' |
|
game_board[position] = user_symbol |
|
|
|
return game_board |
|
|
|
|
|
def full_board(game_board: list): |
|
''' |
|
Check if all spots on the board are taken |
|
''' |
|
full_board = len(game_board) |
|
taken_spots = 0 |
|
for spot in game_board: |
|
if spot == 'O' or spot == 'X': |
|
taken_spots += 1 |
|
|
|
return full_board == taken_spots |
|
|
|
|
|
def make_win_combiantions(game_board: list, size: int) -> list: |
|
''' |
|
Iterate over the board looking for every possible winner combination. |
|
|
|
To calculate the rows list the function uses the size as length of each |
|
To calculate the columns the zip function merge the elements of the rows |
|
|
|
The diagonals are generated using list comprehensions |
|
''' |
|
|
|
rows = make_rows(game_board, size) |
|
columns = list(zip(*rows)) |
|
|
|
left_to_right = [item[idx] for idx, item in enumerate(rows)] |
|
right_to_left = [item[(size - 1) - idx] for idx, item in enumerate(rows)] |
|
|
|
return rows + columns + [left_to_right] + [right_to_left] |
|
|
|
|
|
def three_in_a_row( |
|
win_combinations_matrix: list, |
|
player_symbol: str, size: int) -> bool: |
|
|
|
''' |
|
Check for every row in the win_combinations_matrix |
|
has the size number of the player_symbol |
|
''' |
|
for row in win_combinations_matrix: |
|
player_set = [str(char) for char in row] |
|
if ''.join(player_set) == player_symbol.upper() * size: |
|
return True |
|
|
|
return False |
|
|
|
|
|
def draw_board(game_board: list, size: int) -> str: |
|
''' |
|
generates a visual representation of the game_board |
|
to print it out to the console |
|
''' |
|
clear_output() |
|
board_matrix = make_rows(game_board, size) |
|
line_separator = '---+' * (size - 1) |
|
line_separator += '---\n' |
|
board_draw = '' |
|
|
|
for line_index, line in enumerate(board_matrix): |
|
for index, spot in enumerate(line): |
|
this_spot = f' {spot} |'\ |
|
if not index == (size - 1)\ |
|
else f' {spot} \n' |
|
board_draw += this_spot |
|
board_draw += line_separator if not line_index == (size - 1) else '\n' |
|
|
|
return board_draw |
|
|
|
|
|
if __name__ == "__main__": |
|
print('Welcome to Tic-Tac-Toe Game', end='\n') |
|
|
|
# setup players |
|
is_player_ready = False |
|
player1 = '' |
|
|
|
while not is_player_ready: |
|
print('Player 1: Please chose a symbol to use in the game X or O') |
|
is_player_ready, player1 = is_valid_symbol( |
|
input('> ')) |
|
|
|
player2 = 'X' if player1.upper() == 'O' else 'O' |
|
|
|
print(f'Player 1 will use {player1}') |
|
print(f'Player 2 will use {player2}') |
|
|
|
# setup the game board |
|
size = 3 |
|
board = make_board(3) |
|
winner = False |
|
|
|
# start the game |
|
print(draw_board(board, size)) |
|
while not winner: |
|
print( |
|
'Player 1 turn: ', |
|
'Please mark a spot in the board: ' |
|
) |
|
player1_move = int(input('> ')) |
|
|
|
while spot_taken(board, player1_move): |
|
print( |
|
'Player 1:', |
|
'Spot taken already, please chose a different one' |
|
) |
|
player1_move = int(input('> ')) |
|
else: |
|
board = place_symbol_in_to_position( |
|
board, |
|
player1, |
|
player1_move |
|
) |
|
|
|
if not three_in_a_row( |
|
make_win_combiantions(board, size), |
|
player1, |
|
size |
|
): |
|
if not full_board(board): |
|
print(draw_board(board, size)) |
|
else: |
|
print( |
|
'Board full, No winner\n', |
|
draw_board(board, size), |
|
sep='\n' |
|
) |
|
break |
|
|
|
else: |
|
print('Player 1 won the game') |
|
winner = True |
|
print(draw_board(board, size)) |
|
break |
|
|
|
print( |
|
'Player 2 turn: ', |
|
'Please mark a spot in the board: ' |
|
) |
|
player2_move = int(input('> ')) |
|
|
|
while spot_taken(board, player2_move): |
|
print( |
|
'Player 2:', |
|
'Spot taken already, please chose a different one' |
|
) |
|
player2_move = int(input('> ')) |
|
else: |
|
board = place_symbol_in_to_position( |
|
board, |
|
player2, |
|
player2_move |
|
) |
|
if not three_in_a_row( |
|
make_win_combiantions(board, size), |
|
player2, |
|
size |
|
): |
|
if not full_board(board): |
|
print(draw_board(board, size)) |
|
else: |
|
print( |
|
'Board full, No winner', |
|
draw_board(board, size), |
|
sep='\n' |
|
) |
|
break |
|
|
|
else: |
|
print('Player 2 won the game') |
|
winner = True |
|
print(draw_board(board, size)) |
|
break |