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