import gradio as gr def check_winner(board): # Check rows, columns, and diagonals for a win for i in range(3): if board[i][0] == board[i][1] == board[i][2] != '': return board[i][0] if board[0][i] == board[1][i] == board[2][i] != '': return board[0][i] if board[0][0] == board[1][1] == board[2][2] != '': return board[0][0] if board[0][2] == board[1][1] == board[2][0] != '': return board[0][2] # Check for tie if all(cell != '' for row in board for cell in row): return 'Tie' return None def handle_move(cell_index, board_state, current_player_state, game_over_state): try: print(f"Handle move called: cell_index={cell_index}, board_state={board_state}, current_player={current_player_state}, game_over={game_over_state}") board = [row[:] for row in board_state] # Deep copy of the board current_player = current_player_state row = cell_index // 3 col = cell_index % 3 if board[row][col] != '' or game_over_state: status = f"Invalid move. Player {current_player}'s turn." return (board, status, current_player, game_over_state, *update_buttons(board, not game_over_state)) # Update the board board[row][col] = current_player winner = check_winner(board) if winner: if winner == 'Tie': status = "It's a tie! Game over." else: status = f"Player {winner} wins! Game over." game_over = True else: # Switch player current_player = 'O' if current_player == 'X' else 'X' status = f"Player {current_player}'s turn." game_over = False # Update buttons based on the new board state btn_updates = update_buttons(board, not game_over) print(f"Game over: {game_over}") print(f"Returning: board={board}, status={status}, current_player={current_player}") return (board, status, current_player, game_over, *btn_updates) except Exception as e: print(f"An error occurred: {str(e)}") return (board_state, "An error occurred. Please try again.", current_player_state, game_over_state, *update_buttons(board_state, not game_over_state)) def update_buttons(board, game_active): updates = [] for i in range(9): row = i // 3 col = i % 3 cell_value = board[row][col] if cell_value == '': updates.append(gr.update(value='', interactive=game_active)) else: updates.append(gr.update(value=cell_value, interactive=False)) return updates def reset_game(): board = [['', '', ''], ['', '', ''], ['', '', '']] # Corrected the board initialization return (board, "Player X's turn", 'X', False, *update_buttons(board, True)) with gr.Blocks(css=""" .tic-btn { width: 100px !important; height: 100px !important; font-size: 48px !important; } """) as demo: board_state = gr.State([['', '', ''], ['', '', ''], ['', '', '']]) current_player_state = gr.State('X') game_over_state = gr.State(False) status = gr.Markdown(value="Player X's turn") buttons = [] # Arrange buttons in a 3x3 grid with gr.Column(): for i in range(0, 9, 3): with gr.Row(): for j in range(3): btn = gr.Button(value='', interactive=True, elem_classes='tic-btn') buttons.append(btn) # Set up click events for each button for idx, btn in enumerate(buttons): btn.click( fn=handle_move, inputs=[gr.State(idx), board_state, current_player_state, game_over_state], outputs=[board_state, status, current_player_state, game_over_state] + buttons ) new_game_btn = gr.Button("New Game") new_game_btn.click( fn=reset_game, inputs=[], outputs=[board_state, status, current_player_state, game_over_state] + buttons ) if __name__ == "__main__": print("Starting Gradio app...") demo.launch() print("Gradio app launched.")