TicTacToe / app.py
OrifjonKenjayev's picture
Update app.py
2e19252 verified
raw
history blame
6.04 kB
import gradio as gr
import numpy as np
from typing import List, Tuple, Optional
class TicTacToe:
def __init__(self):
self.board = np.zeros((3, 3))
self.human_player = 1
self.ai_player = -1
def reset_board(self):
self.board = np.zeros((3, 3))
return self.format_board()
def check_winner(self) -> Optional[int]:
# Check rows, columns and diagonals
for player in [self.human_player, self.ai_player]:
# Rows and columns
for i in range(3):
if all(self.board[i, :] == player) or all(self.board[:, i] == player):
return player
# Diagonals
if all(np.diag(self.board) == player) or all(np.diag(np.fliplr(self.board)) == player):
return player
# Check for draw
if np.all(self.board != 0):
return 0
return None
def get_valid_moves(self) -> List[Tuple[int, int]]:
return [(i, j) for i in range(3) for j in range(3) if self.board[i, j] == 0]
def minimax(self, depth: int, is_maximizing: bool, alpha: float = float('-inf'), beta: float = float('inf')) -> Tuple[int, Optional[Tuple[int, int]]]:
winner = self.check_winner()
if winner is not None:
return winner * 100, None
if is_maximizing:
best_score = float('-inf')
best_move = None
for move in self.get_valid_moves():
self.board[move] = self.ai_player
score, _ = self.minimax(depth + 1, False, alpha, beta)
self.board[move] = 0
if score > best_score:
best_score = score
best_move = move
alpha = max(alpha, best_score)
if beta <= alpha:
break
return best_score, best_move
else:
best_score = float('inf')
best_move = None
for move in self.get_valid_moves():
self.board[move] = self.human_player
score, _ = self.minimax(depth + 1, True, alpha, beta)
self.board[move] = 0
if score < best_score:
best_score = score
best_move = move
beta = min(beta, best_score)
if beta <= alpha:
break
return best_score, best_move
def ai_move(self) -> str:
if len(self.get_valid_moves()) == 0:
return self.format_board()
_, best_move = self.minimax(0, True)
if best_move is not None:
self.board[best_move] = self.ai_player
return self.format_board()
def format_board(self) -> str:
symbols = {0: " ", 1: "X", -1: "O"}
return "\n".join([
"-------------",
f"| {symbols[self.board[0,0]]} | {symbols[self.board[0,1]]} | {symbols[self.board[0,2]]} |",
"-------------",
f"| {symbols[self.board[1,0]]} | {symbols[self.board[1,1]]} | {symbols[self.board[1,2]]} |",
"-------------",
f"| {symbols[self.board[2,0]]} | {symbols[self.board[2,1]]} | {symbols[self.board[2,2]]} |",
"-------------"
])
def make_move(self, row: int, col: int) -> Tuple[str, str]:
# Check if move is valid
if self.board[row, col] != 0:
return self.format_board(), "Invalid move! Cell already taken."
# Make human move
self.board[row, col] = self.human_player
# Check if game is over after human move
winner = self.check_winner()
if winner is not None:
if winner == self.human_player:
return self.format_board(), "You win!"
elif winner == 0:
return self.format_board(), "It's a draw!"
# Make AI move
self.ai_move()
# Check if game is over after AI move
winner = self.check_winner()
if winner is not None:
if winner == self.ai_player:
return self.format_board(), "AI wins!"
elif winner == 0:
return self.format_board(), "It's a draw!"
return self.format_board(), "Game in progress"
# Create game instance
game = TicTacToe()
def play_game(row: int, col: int, board_state: str, game_status: str) -> Tuple[str, str]:
if "win" in game_status or "draw" in game_status:
return board_state, game_status
return game.make_move(row, col)
def reset_game() -> Tuple[str, str]:
return game.reset_board(), "Game reset! Your turn (X)"
# Create Gradio interface
with gr.Blocks() as demo:
gr.Markdown("# Tic Tac Toe vs AI")
gr.Markdown("You play as X, AI plays as O. Click the buttons to make your move!")
with gr.Row():
# Game board display
board_display = gr.Textbox(value=game.format_board(), label="Game Board", lines=7)
game_status = gr.Textbox(value="Your turn (X)", label="Game Status")
# Create 3x3 grid of buttons
with gr.Row():
for i in range(3):
with gr.Column():
for j in range(3):
btn = gr.Button(f"Row {i}, Col {j}")
btn.click(
fn=play_game,
inputs=[
gr.Number(value=i, visible=False),
gr.Number(value=j, visible=False),
board_display,
game_status
],
outputs=[board_display, game_status]
)
# Reset button
reset_btn = gr.Button("Reset Game")
reset_btn.click(fn=reset_game, inputs=[], outputs=[board_display, game_status])
# Launch app
demo.launch()