Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| # Game constants | |
| PLAYER = "X" | |
| AI = "O" | |
| EMPTY = "" | |
| def check_winner(board): | |
| # Standard Tic-Tac-Toe win conditions | |
| win_states = [ | |
| [0, 1, 2], [3, 4, 5], [6, 7, 8], # Rows | |
| [0, 3, 6], [1, 4, 7], [2, 5, 8], # Cols | |
| [0, 4, 8], [2, 4, 6] # Diagonals | |
| ] | |
| for line in win_states: | |
| if board[line[0]] == board[line[1]] == board[line[2]] != EMPTY: | |
| return board[line[0]] | |
| if EMPTY not in board: | |
| return "Tie" | |
| return None | |
| def minimax(board, depth, is_maximizing): | |
| res = check_winner(board) | |
| if res == AI: return 10 - depth | |
| if res == PLAYER: return depth - 10 | |
| if res == "Tie": return 0 | |
| if is_maximizing: | |
| best_score = -float('inf') | |
| for i in range(9): | |
| if board[i] == EMPTY: | |
| board[i] = AI | |
| score = minimax(board, depth + 1, False) | |
| board[i] = EMPTY | |
| best_score = max(score, best_score) | |
| return best_score | |
| else: | |
| best_score = float('inf') | |
| for i in range(9): | |
| if board[i] == EMPTY: | |
| board[i] = PLAYER | |
| score = minimax(board, depth + 1, True) | |
| board[i] = EMPTY | |
| best_score = min(score, best_score) | |
| return best_score | |
| def ai_move(board): | |
| best_score = -float('inf') | |
| move = -1 | |
| for i in range(9): | |
| if board[i] == EMPTY: | |
| board[i] = AI | |
| score = minimax(board, 0, False) | |
| board[i] = EMPTY | |
| if score > best_score: | |
| best_score = score | |
| move = i | |
| return move | |
| def play_game(board, idx): | |
| # Convert state to list | |
| board = list(board) | |
| # Player Move | |
| if board[idx] == EMPTY: | |
| board[idx] = PLAYER | |
| else: | |
| return board, "Cell already taken!" | |
| # Check if Player won | |
| status = check_winner(board) | |
| if status: | |
| return board, f"Game Over: {status} wins!" if status != "Tie" else "It's a Tie!" | |
| # AI Move | |
| ai_idx = ai_move(board) | |
| if ai_idx != -1: | |
| board[ai_idx] = AI | |
| # Check if AI won | |
| status = check_winner(board) | |
| if status: | |
| return board, f"Game Over: {status} wins!" if status != "Tie" else "It's a Tie!" | |
| return board, "Your turn, Player X" | |
| def reset_game(): | |
| return [EMPTY] * 9, "New Game! You are X." | |
| # UI Construction | |
| with gr.Blocks(css=".square {height: 100px !important; font-size: 2rem !important;}") as demo: | |
| gr.Markdown("# 🤖 AI Tic-Tac-Toe") | |
| gr.Markdown("Try to beat the unbeatable Minimax AI!") | |
| board_state = gr.State([EMPTY] * 9) | |
| status_msg = gr.Textbox(value="Your turn, Player X", label="Status") | |
| with gr.Column(elem_id="board"): | |
| buttons = [] | |
| for i in range(3): | |
| with gr.Row(): | |
| for j in range(3): | |
| idx = i * 3 + j | |
| btn = gr.Button(value=EMPTY, elem_classes="square") | |
| buttons.append(btn) | |
| reset_btn = gr.Button("Reset Game", variant="primary") | |
| # Click Logic | |
| for i, btn in enumerate(buttons): | |
| btn.click( | |
| play_game, | |
| inputs=[board_state, gr.Number(i, visible=False)], | |
| outputs=[board_state, status_msg] | |
| ) | |
| # Update UI buttons when state changes | |
| board_state.change( | |
| lambda b: [gr.update(value=val) for val in b], | |
| inputs=board_state, | |
| outputs=buttons | |
| ) | |
| reset_btn.click(reset_game, outputs=[board_state, status_msg]) | |
| if __name__ == "__main__": | |
| demo.launch() |