OrifjonKenjayev commited on
Commit
2027e1d
·
verified ·
1 Parent(s): 2e19252

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +178 -156
app.py CHANGED
@@ -1,169 +1,191 @@
1
  import gradio as gr
2
- import numpy as np
3
- from typing import List, Tuple, Optional
4
 
5
  class TicTacToe:
6
  def __init__(self):
7
- self.board = np.zeros((3, 3))
8
- self.human_player = 1
9
- self.ai_player = -1
10
-
11
- def reset_board(self):
12
- self.board = np.zeros((3, 3))
13
- return self.format_board()
14
-
15
- def check_winner(self) -> Optional[int]:
16
- # Check rows, columns and diagonals
17
- for player in [self.human_player, self.ai_player]:
18
- # Rows and columns
19
- for i in range(3):
20
- if all(self.board[i, :] == player) or all(self.board[:, i] == player):
21
- return player
22
- # Diagonals
23
- if all(np.diag(self.board) == player) or all(np.diag(np.fliplr(self.board)) == player):
24
- return player
25
-
26
- # Check for draw
27
- if np.all(self.board != 0):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  return 0
29
-
30
- return None
31
-
32
- def get_valid_moves(self) -> List[Tuple[int, int]]:
33
- return [(i, j) for i in range(3) for j in range(3) if self.board[i, j] == 0]
34
-
35
- def minimax(self, depth: int, is_maximizing: bool, alpha: float = float('-inf'), beta: float = float('inf')) -> Tuple[int, Optional[Tuple[int, int]]]:
36
- winner = self.check_winner()
37
- if winner is not None:
38
- return winner * 100, None
39
-
40
  if is_maximizing:
41
  best_score = float('-inf')
42
- best_move = None
43
- for move in self.get_valid_moves():
44
- self.board[move] = self.ai_player
45
- score, _ = self.minimax(depth + 1, False, alpha, beta)
46
- self.board[move] = 0
47
-
48
- if score > best_score:
49
- best_score = score
50
- best_move = move
51
-
52
- alpha = max(alpha, best_score)
53
- if beta <= alpha:
54
- break
55
-
56
- return best_score, best_move
57
  else:
58
  best_score = float('inf')
59
- best_move = None
60
- for move in self.get_valid_moves():
61
- self.board[move] = self.human_player
62
- score, _ = self.minimax(depth + 1, True, alpha, beta)
63
- self.board[move] = 0
64
-
65
- if score < best_score:
 
 
 
 
 
 
 
 
 
 
66
  best_score = score
67
- best_move = move
68
-
69
- beta = min(beta, best_score)
70
- if beta <= alpha:
71
- break
72
-
73
- return best_score, best_move
74
-
75
- def ai_move(self) -> str:
76
- if len(self.get_valid_moves()) == 0:
77
- return self.format_board()
78
-
79
- _, best_move = self.minimax(0, True)
80
- if best_move is not None:
81
- self.board[best_move] = self.ai_player
82
-
83
- return self.format_board()
84
-
85
- def format_board(self) -> str:
86
- symbols = {0: " ", 1: "X", -1: "O"}
87
- return "\n".join([
88
- "-------------",
89
- f"| {symbols[self.board[0,0]]} | {symbols[self.board[0,1]]} | {symbols[self.board[0,2]]} |",
90
- "-------------",
91
- f"| {symbols[self.board[1,0]]} | {symbols[self.board[1,1]]} | {symbols[self.board[1,2]]} |",
92
- "-------------",
93
- f"| {symbols[self.board[2,0]]} | {symbols[self.board[2,1]]} | {symbols[self.board[2,2]]} |",
94
- "-------------"
95
- ])
96
-
97
- def make_move(self, row: int, col: int) -> Tuple[str, str]:
98
- # Check if move is valid
99
- if self.board[row, col] != 0:
100
- return self.format_board(), "Invalid move! Cell already taken."
101
-
102
- # Make human move
103
- self.board[row, col] = self.human_player
104
-
105
- # Check if game is over after human move
106
- winner = self.check_winner()
107
- if winner is not None:
108
- if winner == self.human_player:
109
- return self.format_board(), "You win!"
110
- elif winner == 0:
111
- return self.format_board(), "It's a draw!"
112
-
113
- # Make AI move
114
- self.ai_move()
115
-
116
- # Check if game is over after AI move
117
- winner = self.check_winner()
118
- if winner is not None:
119
- if winner == self.ai_player:
120
- return self.format_board(), "AI wins!"
121
- elif winner == 0:
122
- return self.format_board(), "It's a draw!"
123
-
124
- return self.format_board(), "Game in progress"
125
-
126
- # Create game instance
127
  game = TicTacToe()
128
 
129
- def play_game(row: int, col: int, board_state: str, game_status: str) -> Tuple[str, str]:
130
- if "win" in game_status or "draw" in game_status:
131
- return board_state, game_status
132
- return game.make_move(row, col)
133
-
134
- def reset_game() -> Tuple[str, str]:
135
- return game.reset_board(), "Game reset! Your turn (X)"
136
-
137
- # Create Gradio interface
138
- with gr.Blocks() as demo:
139
- gr.Markdown("# Tic Tac Toe vs AI")
140
- gr.Markdown("You play as X, AI plays as O. Click the buttons to make your move!")
141
-
142
- with gr.Row():
143
- # Game board display
144
- board_display = gr.Textbox(value=game.format_board(), label="Game Board", lines=7)
145
- game_status = gr.Textbox(value="Your turn (X)", label="Game Status")
146
-
147
- # Create 3x3 grid of buttons
148
- with gr.Row():
149
- for i in range(3):
150
- with gr.Column():
151
- for j in range(3):
152
- btn = gr.Button(f"Row {i}, Col {j}")
153
- btn.click(
154
- fn=play_game,
155
- inputs=[
156
- gr.Number(value=i, visible=False),
157
- gr.Number(value=j, visible=False),
158
- board_display,
159
- game_status
160
- ],
161
- outputs=[board_display, game_status]
162
- )
163
-
164
- # Reset button
165
- reset_btn = gr.Button("Reset Game")
166
- reset_btn.click(fn=reset_game, inputs=[], outputs=[board_display, game_status])
167
-
168
- # Launch app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  demo.launch()
 
1
  import gradio as gr
2
+ import random
 
3
 
4
  class TicTacToe:
5
  def __init__(self):
6
+ self.board = [" " for _ in range(9)]
7
+ self.winning_combinations = [
8
+ [0, 1, 2], [3, 4, 5], [6, 7, 8], # Rows
9
+ [0, 3, 6], [1, 4, 7], [2, 5, 8], # Columns
10
+ [0, 4, 8], [2, 4, 6] # Diagonals
11
+ ]
12
+ self.human = "X"
13
+ self.ai = "O"
14
+ self.current_player = self.human
15
+
16
+ def reset(self):
17
+ self.board = [" " for _ in range(9)]
18
+ self.current_player = self.human
19
+ return self.board
20
+
21
+ def make_move(self, position):
22
+ if self.board[position] == " " and not self.is_game_over():
23
+ self.board[position] = self.current_player
24
+ if self.current_player == self.human:
25
+ self.current_player = self.ai
26
+ # AI makes its move after human
27
+ if not self.is_game_over():
28
+ ai_move = self.get_best_move()
29
+ self.board[ai_move] = self.ai
30
+ self.current_player = self.human
31
+ return True
32
+ return False
33
+
34
+ def is_winner(self, player):
35
+ for combo in self.winning_combinations:
36
+ if all(self.board[i] == player for i in combo):
37
+ return True
38
+ return False
39
+
40
+ def is_game_over(self):
41
+ return self.is_winner(self.human) or self.is_winner(self.ai) or " " not in self.board
42
+
43
+ def get_status(self):
44
+ if self.is_winner(self.human):
45
+ return "You win! 🎉"
46
+ elif self.is_winner(self.ai):
47
+ return "AI wins! 🤖"
48
+ elif " " not in self.board:
49
+ return "It's a tie! 🤝"
50
+ return "Your turn!"
51
+
52
+ def minimax(self, depth, is_maximizing):
53
+ if self.is_winner(self.ai):
54
+ return 1
55
+ if self.is_winner(self.human):
56
+ return -1
57
+ if " " not in self.board:
58
  return 0
59
+
 
 
 
 
 
 
 
 
 
 
60
  if is_maximizing:
61
  best_score = float('-inf')
62
+ for i in range(9):
63
+ if self.board[i] == " ":
64
+ self.board[i] = self.ai
65
+ score = self.minimax(depth + 1, False)
66
+ self.board[i] = " "
67
+ best_score = max(score, best_score)
68
+ return best_score
 
 
 
 
 
 
 
 
69
  else:
70
  best_score = float('inf')
71
+ for i in range(9):
72
+ if self.board[i] == " ":
73
+ self.board[i] = self.human
74
+ score = self.minimax(depth + 1, True)
75
+ self.board[i] = " "
76
+ best_score = min(score, best_score)
77
+ return best_score
78
+
79
+ def get_best_move(self):
80
+ best_score = float('-inf')
81
+ best_move = None
82
+ for i in range(9):
83
+ if self.board[i] == " ":
84
+ self.board[i] = self.ai
85
+ score = self.minimax(0, False)
86
+ self.board[i] = " "
87
+ if score > best_score:
88
  best_score = score
89
+ best_move = i
90
+ return best_move
91
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  game = TicTacToe()
93
 
94
+ css = """
95
+ #game-container {
96
+ max-width: 300px;
97
+ margin: 0 auto;
98
+ padding: 15px;
99
+ }
100
+
101
+ .board {
102
+ display: grid;
103
+ grid-template-columns: repeat(3, 1fr);
104
+ gap: 4px;
105
+ background: #ff0000;
106
+ padding: 4px;
107
+ width: 240px;
108
+ margin: 0 auto;
109
+ }
110
+
111
+ .cell {
112
+ width: 100% !important;
113
+ height: 75px !important;
114
+ font-size: 24px !important;
115
+ font-weight: bold !important;
116
+ background: white !important;
117
+ color: #0066cc !important;
118
+ border: none !important;
119
+ display: flex !important;
120
+ align-items: center !important;
121
+ justify-content: center !important;
122
+ cursor: pointer !important;
123
+ }
124
+
125
+ .cell:hover {
126
+ background: #f0f0f0 !important;
127
+ }
128
+
129
+ #message {
130
+ text-align: center;
131
+ margin: 15px 0;
132
+ font-size: 18px;
133
+ color: #333;
134
+ }
135
+
136
+ #reset-btn {
137
+ background: #e74c3c !important;
138
+ color: white !important;
139
+ border: none !important;
140
+ padding: 10px 20px !important;
141
+ border-radius: 5px !important;
142
+ cursor: pointer !important;
143
+ margin: 10px auto !important;
144
+ display: block !important;
145
+ width: 120px !important;
146
+ }
147
+ """
148
+
149
+ def create_interface():
150
+ with gr.Blocks(css=css) as demo:
151
+ with gr.Column(elem_id="game-container"):
152
+ status = gr.Markdown("Your turn!", elem_id="message")
153
+
154
+ with gr.Column(elem_classes=["board"]):
155
+ cells = []
156
+ for i in range(9):
157
+ cells.append(gr.Button(" ", elem_classes=["cell"]))
158
+
159
+ reset = gr.Button("New Game", elem_id="reset-btn")
160
+
161
+ def handle_click(idx):
162
+ if game.make_move(idx):
163
+ return {
164
+ status: game.get_status(),
165
+ **{cell: game.board[i] for i, cell in enumerate(cells)}
166
+ }
167
+ return {status: "Invalid move!"}
168
+
169
+ def reset_game():
170
+ game.reset()
171
+ return {
172
+ status: "Your turn!",
173
+ **{cell: " " for cell in cells}
174
+ }
175
+
176
+ for i, cell in enumerate(cells):
177
+ cell.click(
178
+ handle_click,
179
+ inputs=[gr.State(i)],
180
+ outputs=[status, *cells]
181
+ )
182
+
183
+ reset.click(
184
+ reset_game,
185
+ outputs=[status, *cells]
186
+ )
187
+
188
+ return demo
189
+
190
+ demo = create_interface()
191
  demo.launch()