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() |