Spaces:
Running
Running
import numpy as np | |
import gradio as gr | |
class TicTacToeAI: | |
def __init__(self): | |
self.board = np.full((3, 3), "", dtype=str) | |
self.human = "X" | |
self.ai = "O" | |
def is_winner(self, board, player): | |
return any([ | |
np.all(row == player) for row in board | |
]) or any([ | |
np.all(board[:, i] == player) for i in range(3) | |
]) or np.all(np.diag(board) == player) or np.all(np.diag(np.fliplr(board)) == player) | |
def is_draw(self, board): | |
return "" not in board and not self.is_winner(board, self.human) and not self.is_winner(board, self.ai) | |
def available_moves(self, board): | |
return [(r, c) for r in range(3) for c in range(3) if board[r, c] == ""] | |
def minimax(self, board, depth, is_maximizing): | |
if self.is_winner(board, self.ai): | |
return 10 - depth | |
if self.is_winner(board, self.human): | |
return depth - 10 | |
if self.is_draw(board): | |
return 0 | |
if is_maximizing: | |
best_score = -np.inf | |
for (r, c) in self.available_moves(board): | |
board[r, c] = self.ai | |
score = self.minimax(board, depth + 1, False) | |
board[r, c] = "" | |
best_score = max(best_score, score) | |
return best_score | |
else: | |
best_score = np.inf | |
for (r, c) in self.available_moves(board): | |
board[r, c] = self.human | |
score = self.minimax(board, depth + 1, True) | |
board[r, c] = "" | |
best_score = min(best_score, score) | |
return best_score | |
def best_move(self): | |
best_score = -np.inf | |
move = None | |
for (r, c) in self.available_moves(self.board): | |
self.board[r, c] = self.ai | |
score = self.minimax(self.board, 0, False) | |
self.board[r, c] = "" | |
if score > best_score: | |
best_score = score | |
move = (r, c) | |
return move | |
game = TicTacToeAI() | |
status = "Your Turn (X)" | |
def play(row, col): | |
global status, game | |
if game.board[row, col] != "": | |
return game.board.tolist(), status, "Invalid move." | |
game.board[row, col] = game.human | |
if game.is_winner(game.board, game.human): | |
status = "You Win! ๐" | |
return game.board.tolist(), status, "Try again?" | |
elif game.is_draw(game.board): | |
status = "Draw! ๐ค" | |
return game.board.tolist(), status, "Try again?" | |
ai_r, ai_c = game.best_move() | |
if ai_r is not None: | |
game.board[ai_r, ai_c] = game.ai | |
if game.is_winner(game.board, game.ai): | |
status = "AI Wins! ๐ค" | |
return game.board.tolist(), status, "Try again?" | |
elif game.is_draw(game.board): | |
status = "Draw! ๐ค" | |
return game.board.tolist(), status, "Try again?" | |
status = "Your Turn (X)" | |
return game.board.tolist(), status, "" | |
def reset(): | |
global game, status | |
game = TicTacToeAI() | |
status = "Your Turn (X)" | |
return game.board.tolist(), status, "" | |
with gr.Blocks() as demo: | |
gr.Markdown("## ๐ฎ Smart Tic-Tac-Toe vs AI") | |
gr.Markdown("Click a cell to make your move. You are X, AI is O.") | |
board = gr.Dataframe(value=game.board.tolist(), row_count=3, col_count=3, interactive=False) | |
status_text = gr.Textbox(value=status, interactive=False, label="Game Status") | |
tips = gr.Textbox(label="Tip", interactive=False) | |
with gr.Row(): | |
for r in range(3): | |
for c in range(3): | |
gr.Button(f"{r},{c}").click( | |
play, inputs=[gr.Number(value=r), gr.Number(value=c)], | |
outputs=[board, status_text, tips] | |
) | |
gr.Button("Reset Game ๐").click(reset, outputs=[board, status_text, tips]) | |
demo.launch() | |