Spaces:
Sleeping
Sleeping
| import numpy as np | |
| import random | |
| import gradio as gr | |
| from PIL import Image, ImageDraw | |
| def ai_move(board): | |
| best_score = -np.inf | |
| best_move = None | |
| for r, c in available_moves(board): | |
| board[r][c] = "X" | |
| score = minimax(board, 0, False) # AI 使用最大化策略,深度從 0 開始 | |
| board[r][c] = "" | |
| if score > best_score: | |
| best_score = score | |
| best_move = (r, c) | |
| if best_move: | |
| board[best_move[0]][best_move[1]] = "X" | |
| return board | |
| def initialize_board(): | |
| return [["", "", ""] for _ in range(3)] | |
| def draw_board(board): | |
| img_size = 300 | |
| cell_size = img_size // 3 | |
| img = Image.new("RGB", (img_size, img_size), "white") | |
| draw = ImageDraw.Draw(img) | |
| # Draw grid lines | |
| for i in range(1, 3): | |
| draw.line([(0, i * cell_size), (img_size, i * cell_size)], fill="black", width=3) | |
| draw.line([(i * cell_size, 0), (i * cell_size, img_size)], fill="black", width=3) | |
| # Draw ⨉ and 𐤏 | |
| for r in range(3): | |
| for c in range(3): | |
| if board[r][c] == "X": | |
| draw.line([(c * cell_size + 10, r * cell_size + 10), ((c + 1) * cell_size - 10, (r + 1) * cell_size - 10)], fill="red", width=3) | |
| draw.line([((c + 1) * cell_size - 10, r * cell_size + 10), (c * cell_size + 10, (r + 1) * cell_size - 10)], fill="red", width=3) | |
| elif board[r][c] == "O": | |
| draw.ellipse([(c * cell_size + 10, r * cell_size + 10), ((c + 1) * cell_size - 10, (r + 1) * cell_size - 10)], outline="blue", width=3) | |
| return img | |
| def check_winner(board): | |
| for i in range(3): | |
| if board[i][0] == board[i][1] == board[i][2] and board[i][0] != "": | |
| return board[i][0] | |
| if board[0][i] == board[1][i] == board[2][i] and board[0][i] != "": | |
| return board[0][i] | |
| if board[0][0] == board[1][1] == board[2][2] and board[0][0] != "": | |
| return board[0][0] | |
| if board[0][2] == board[1][1] == board[2][0] and board[0][2] != "": | |
| return board[0][2] | |
| if all(cell != "" for row in board for cell in row): | |
| return "Tie" | |
| return None | |
| def available_moves(board): | |
| return [(r, c) for r in range(3) for c in range(3) if board[r][c] == ""] | |
| def minimax(board, depth, is_maximizing): | |
| result = check_winner(board) | |
| if result == "O": | |
| return -10 + depth | |
| elif result == "X": | |
| return 10 - depth | |
| elif result == "Tie": | |
| return 0 | |
| if is_maximizing: | |
| best_score = -np.inf | |
| for r, c in available_moves(board): | |
| board[r][c] = "X" | |
| score = minimax(board, depth + 1, False) | |
| board[r][c] = "" | |
| best_score = max(score, best_score) | |
| return best_score | |
| else: | |
| best_score = np.inf | |
| for r, c in available_moves(board): | |
| board[r][c] = "O" | |
| score = minimax(board, depth + 1, True) | |
| board[r][c] = "" | |
| best_score = min(score, best_score) | |
| return best_score | |
| def play_tic_tac_toe(evt: gr.SelectData, board, game_over): | |
| # 確認 evt 是否有效 | |
| if not evt or not hasattr(evt, "index") or not evt.index: | |
| return draw_board(board), "Invalid move! Please select a valid square.", False | |
| if game_over: | |
| return draw_board(board), "Game already finished! Please reset to play again.", True | |
| try: | |
| r, c = evt.index[1] // 100, evt.index[0] // 100 | |
| except (TypeError, IndexError): | |
| return draw_board(board), "Invalid selection! Please try again.", False | |
| if board[r][c] != "": | |
| return draw_board(board), "Invalid move! This spot is already taken. Please select an empty square.", False | |
| board[r][c] = "O" | |
| result = check_winner(board) | |
| if result: | |
| return draw_board(board), f"Game Over! Player {result} wins!" if result != "Tie" else "It's a tie!", True | |
| board = ai_move(board) | |
| result = check_winner(board) | |
| if result: | |
| return draw_board(board), f"Game Over! Player {result} wins!" if result != "Tie" else "It's a tie!", True | |
| return draw_board(board), "Game in progress", False | |
| def reset_game(): | |
| board = initialize_board() | |
| return draw_board(board), board, "New game started!", False | |
| with gr.Blocks() as app: | |
| gr.Markdown("# Tic-Tac-Toe AI Game") | |
| board = initialize_board() | |
| board_image = gr.Image(value=draw_board(board), interactive=False, label="Board", show_download_button=False, show_fullscreen_button=False) | |
| message_display = gr.Textbox(label="Game Status", value="Game in progress") | |
| reset_button = gr.Button("Reset Game") | |
| board_state = gr.State(board) | |
| game_over_state = gr.State(False) | |
| board_image.select(play_tic_tac_toe, inputs=[board_state, game_over_state], outputs=[board_image, message_display, game_over_state]) | |
| reset_button.click(reset_game, inputs=[], outputs=[board_image, board_state, message_display, game_over_state]) | |
| app.launch() |