File size: 3,569 Bytes
4283ca6
df47e01
 
 
0b8cc1e
 
 
 
 
 
 
 
df47e01
 
0b8cc1e
 
 
 
 
df47e01
 
0b8cc1e
df47e01
0b8cc1e
 
 
 
 
 
 
 
df47e01
0b8cc1e
df47e01
0b8cc1e
 
 
 
 
 
 
 
df47e01
 
0b8cc1e
df47e01
 
 
0b8cc1e
 
 
 
df47e01
 
 
0b8cc1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df47e01
0b8cc1e
df47e01
 
0b8cc1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df47e01
 
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
113
114
115
116
117
118
119
120
121
122
import gradio as gr
import math

# Check winner
def check_winner(board, player):
    wins = [[0,1,2],[3,4,5],[6,7,8],
            [0,3,6],[1,4,7],[2,5,8],
            [0,4,8],[2,4,6]]
    return any(board[a]==board[b]==board[c]==player for a,b,c in wins)

# Check draw
def is_full(board):
    return ' ' not in board

# Minimax with alpha-beta pruning
def minimax(board, is_max, alpha, beta):
    if check_winner(board,'O'): return 1
    if check_winner(board,'X'): return -1
    if is_full(board): return 0

    if is_max:
        best = -math.inf
        for i in range(9):
            if board[i]==' ':
                board[i]='O'
                val = minimax(board, False, alpha, beta)
                board[i]=' '
                best = max(best, val)
                alpha = max(alpha, val)
                if beta<=alpha: break
        return best
    else:
        best = math.inf
        for i in range(9):
            if board[i]==' ':
                board[i]='X'
                val = minimax(board, True, alpha, beta)
                board[i]=' '
                best = min(best, val)
                beta = min(beta, val)
                if beta<=alpha: break
        return best

# AI move
def ai_move(board):
    best_score = -math.inf
    move = None
    for i in range(9):
        if board[i]==' ':
            board[i]='O'
            score = minimax(board, False, -math.inf, math.inf)
            board[i]=' '
            if score > best_score:
                best_score = score
                move = i
    if move is not None:
        board[move]='O'
    return board

# Player move
def player_move(cell, board):
    board = board.copy()  # work on a copy

    if board[cell] != ' ':
        return board, "โŒ Spot taken!", board

    board[cell] = 'X'
    if check_winner(board,'X'):
        return board, "๐ŸŽ‰ You win!", board
    if is_full(board):
        return board, "๐Ÿค Draw!", board

    board = ai_move(board)
    if check_winner(board,'O'):
        return board, "๐Ÿ’ป AI wins!", board
    if is_full(board):
        return board, "๐Ÿค Draw!", board

    return board, "Your move!", board

# Reset board
def reset():
    new_board = [' ' for _ in range(9)]
    return new_board, "New Game! You are X.", new_board

# Update buttons
def update_buttons(board):
    return [board[i] if board[i] != ' ' else " " for i in range(9)]

# Build GUI
with gr.Blocks(css="""
    .grid {display:grid;grid-template-columns:repeat(3,100px);grid-gap:5px;justify-content:center;}
    .grid button {height:100px;width:100px;font-size:2em;font-weight:bold;}
    """) as demo:

    gr.Markdown("<h1 style='text-align:center'>๐ŸŽฎ Tic Tac Toe AI</h1>")
    status = gr.Label("New Game! You are X.")

    board_state = gr.State([' ' for _ in range(9)])  # ๐Ÿ”‘ persistent board state

    with gr.Column():
        game_buttons = []
        with gr.Row(elem_classes="grid"):
            for i in range(9):
                btn = gr.Button(" ")
                game_buttons.append(btn)

    reset_btn = gr.Button("๐Ÿ”„ Reset Game")

    # Wire buttons to player_move with state
    for idx, btn in enumerate(game_buttons):
        btn.click(player_move, 
                  inputs=[gr.Number(value=idx, visible=False), board_state],
                  outputs=[gr.State(), status, board_state]) \
           .then(update_buttons, inputs=board_state, outputs=game_buttons)

    # Reset game
    reset_btn.click(reset, outputs=[gr.State(), status, board_state]) \
              .then(update_buttons, inputs=board_state, outputs=game_buttons)

demo.launch()