File size: 3,815 Bytes
ca7b645
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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()