OrifjonKenjayev commited on
Commit
c81092d
Β·
verified Β·
1 Parent(s): 739fe80

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -185
app.py CHANGED
@@ -1,246 +1,200 @@
1
  import gradio as gr
2
  import numpy as np
3
- from tictactoe import X, O, EMPTY, initial_state, result, terminal, winner, minimax
4
 
5
- class GameState:
 
 
 
 
 
6
  def __init__(self):
7
- self.board = initial_state()
8
- self.player_symbol = None
 
9
 
10
  def reset(self):
11
- self.board = initial_state()
12
- self.player_symbol = None
13
-
14
- game_state = GameState()
15
-
16
- def format_cell(cell):
17
- return cell if cell in [X, O] else " "
18
-
19
- def make_move(board, row, col, player_symbol):
20
- if board[row][col] != EMPTY:
21
- return board, "Invalid move! Cell already taken."
22
-
23
- # Make player's move
24
- new_board = result(board, (row, col))
25
-
26
- if terminal(new_board):
27
- game_winner = winner(new_board)
28
- if game_winner:
29
- return new_board, f"Game Over! {game_winner} wins! πŸŽ‰"
30
- return new_board, "Game Over! It's a tie! 🀝"
31
-
32
- # Make AI's move
33
- ai_move = minimax(new_board)
34
- if ai_move:
35
- new_board = result(new_board, ai_move)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- if terminal(new_board):
38
- game_winner = winner(new_board)
39
- if game_winner:
40
- return new_board, f"Game Over! {game_winner} wins! πŸŽ‰"
41
- return new_board, "Game Over! It's a tie! 🀝"
42
-
43
- return new_board, "Your turn!"
44
-
45
- css = """
46
  #game-container {
47
- max-width: 240px; /* Even smaller container */
48
  margin: 0 auto;
49
  padding: 20px;
 
 
50
  }
51
 
52
- .game-board {
53
- display: grid;
54
- grid-template-columns: repeat(3, 1fr); /* Force 3 columns */
55
- grid-template-rows: repeat(3, 1fr); /* Force 3 rows */
56
- gap: 3px;
57
- background-color: #ff0000; /* Red grid lines */
58
- padding: 3px;
59
- width: 180px; /* Fixed smaller width */
60
- height: 180px; /* Fixed height to match width */
61
- margin: 20px auto;
62
  }
63
 
64
- .cell-button {
65
- width: 100% !important;
66
- height: 100% !important;
67
- aspect-ratio: 1;
68
- font-size: 1.2em !important;
69
  font-weight: bold !important;
 
70
  border: none !important;
71
- background-color: #ffffff !important;
72
- color: #0066cc !important; /* Blue X and O */
73
- padding: 0 !important;
74
- margin: 0 !important;
75
  display: flex !important;
76
  align-items: center !important;
77
  justify-content: center !important;
78
- min-height: unset !important; /* Remove min-height */
 
 
79
  }
80
 
81
- .cell-button:hover {
82
- background-color: #f0f0f0 !important;
 
 
 
 
83
  }
84
 
85
- #message-box {
86
  text-align: center;
87
- padding: 10px;
88
- border-radius: 8px;
89
- background-color: #f8f9fa;
90
  margin: 15px 0;
91
- font-size: 1em !important;
92
- }
93
-
94
- .player-button {
95
- padding: 8px 16px !important;
96
- font-size: 1em !important;
97
- border-radius: 6px !important;
98
- background-color: #3498db !important;
99
- color: white !important;
100
- border: none !important;
101
- transition: all 0.3s ease !important;
102
- min-width: 80px !important;
103
- }
104
-
105
- .player-button:hover {
106
- background-color: #2980b9 !important;
107
  }
108
 
109
- .restart-button {
110
- background-color: #e74c3c !important;
 
 
 
111
  color: white !important;
112
- padding: 8px 16px !important;
113
- font-size: 1em !important;
114
- border-radius: 6px !important;
115
  border: none !important;
116
- transition: all 0.3s ease !important;
117
- width: 100% !important;
118
- max-width: 120px !important;
119
- margin: 10px auto !important;
120
- }
121
-
122
- .restart-button:hover {
123
- background-color: #c0392b !important;
124
  }
125
 
126
- .title {
127
- text-align: center;
128
- color: #2c3e50;
129
- font-size: 1.8em !important;
130
- margin-bottom: 15px !important;
131
- }
132
-
133
- /* Fix for grid layout */
134
- .game-board-row {
135
- display: contents !important;
136
  }
137
  """
138
 
139
- def create_interface():
140
- with gr.Blocks(css=css) as demo:
141
- gr.Markdown("# Tic Tac Toe", elem_classes=["title"])
142
-
143
  with gr.Column(elem_id="game-container"):
144
- # Player selection
145
- with gr.Row(visible=True) as player_select:
146
- select_x = gr.Button("Play as X", elem_classes=["player-button"])
147
- select_o = gr.Button("Play as O", elem_classes=["player-button"])
148
-
149
- # Game status
150
- message = gr.Markdown("Choose your symbol to start!", elem_id="message-box")
151
 
152
- # Game board
153
- with gr.Column(visible=False) as game_board:
154
- # Create 3x3 grid using rows
155
  buttons = [[None for _ in range(3)] for _ in range(3)]
156
  for i in range(3):
157
- with gr.Row(elem_classes=["game-board-row"]):
158
  for j in range(3):
159
  buttons[i][j] = gr.Button(
160
  " ",
161
- elem_classes=["cell-button"],
162
  elem_id=f"cell-{i}-{j}"
163
  )
164
-
165
- restart = gr.Button("New Game", elem_classes=["restart-button"])
166
-
167
- def start_game(symbol):
168
- game_state.reset()
169
- game_state.player_symbol = symbol
170
- game_state.board = initial_state()
171
-
172
- msg = "Your turn!"
173
- if symbol == O:
174
- # If player chose O, AI (X) makes the first move
175
- ai_move = minimax(game_state.board)
176
- game_state.board = result(game_state.board, ai_move)
177
 
178
- return {
179
- player_select: gr.update(visible=False),
180
- game_board: gr.update(visible=True),
181
- message: msg,
182
- **{buttons[i][j]: format_cell(game_state.board[i][j])
183
- for i in range(3) for j in range(3)}
184
- }
185
 
186
  def handle_click(i, j):
187
- if game_state.board[i][j] != EMPTY:
188
- return {
189
- message: "Invalid move! Cell already taken.",
190
- **{buttons[r][c]: format_cell(game_state.board[r][c])
191
- for r in range(3) for c in range(3)}
192
- }
193
-
194
- new_board, msg = make_move(
195
- game_state.board,
196
- i,
197
- j,
198
- game_state.player_symbol
199
- )
200
- game_state.board = new_board
 
 
 
 
 
 
 
201
 
202
- return {
203
- message: msg,
204
- **{buttons[r][c]: format_cell(new_board[r][c])
205
- for r in range(3) for c in range(3)}
206
- }
207
-
208
- def handle_restart():
209
- game_state.reset()
210
- return {
211
- player_select: gr.update(visible=True),
212
- game_board: gr.update(visible=False),
213
- message: "Choose your symbol to start!",
214
- **{buttons[i][j]: " " for i in range(3) for j in range(3)}
215
- }
216
 
217
  # Connect event handlers
218
- select_x.click(
219
- start_game,
220
- inputs=[gr.State(X)],
221
- outputs=[player_select, game_board, message, *sum(buttons, [])]
222
- )
223
-
224
- select_o.click(
225
- start_game,
226
- inputs=[gr.State(O)],
227
- outputs=[player_select, game_board, message, *sum(buttons, [])]
228
- )
229
-
230
  for i in range(3):
231
  for j in range(3):
232
  buttons[i][j].click(
233
  lambda x, y: handle_click(x, y),
234
  inputs=[gr.State(i), gr.State(j)],
235
- outputs=[message, *sum(buttons, [])]
236
  )
237
 
238
- restart.click(
239
- handle_restart,
240
- outputs=[player_select, game_board, message, *sum(buttons, [])]
241
  )
242
 
243
  return demo
244
 
245
- demo = create_interface()
 
246
  demo.launch()
 
1
  import gradio as gr
2
  import numpy as np
 
3
 
4
+ # Game constants
5
+ X = "X"
6
+ O = "O"
7
+ EMPTY = None
8
+
9
+ class TicTacToe:
10
  def __init__(self):
11
+ self.board = [[EMPTY for _ in range(3)] for _ in range(3)]
12
+ self.current_player = X
13
+ self.game_over = False
14
 
15
  def reset(self):
16
+ self.board = [[EMPTY for _ in range(3)] for _ in range(3)]
17
+ self.current_player = X
18
+ self.game_over = False
19
+
20
+ def make_move(self, row, col):
21
+ if self.board[row][col] is not None or self.game_over:
22
+ return False
23
+
24
+ self.board[row][col] = self.current_player
25
+ if self.check_winner():
26
+ self.game_over = True
27
+ return True
28
+
29
+ if self.is_board_full():
30
+ self.game_over = True
31
+ return True
32
+
33
+ self.current_player = O if self.current_player == X else X
34
+ return True
35
+
36
+ def check_winner(self):
37
+ # Check rows
38
+ for row in self.board:
39
+ if row.count(row[0]) == 3 and row[0] is not None:
40
+ return True
41
+
42
+ # Check columns
43
+ for col in range(3):
44
+ if (self.board[0][col] == self.board[1][col] == self.board[2][col]
45
+ and self.board[0][col] is not None):
46
+ return True
47
+
48
+ # Check diagonals
49
+ if (self.board[0][0] == self.board[1][1] == self.board[2][2]
50
+ and self.board[0][0] is not None):
51
+ return True
52
+ if (self.board[0][2] == self.board[1][1] == self.board[2][0]
53
+ and self.board[0][2] is not None):
54
+ return True
55
+
56
+ return False
57
 
58
+ def is_board_full(self):
59
+ return all(all(cell is not None for cell in row) for row in self.board)
60
+
61
+ # Initialize game
62
+ game = TicTacToe()
63
+
64
+ # Custom CSS
65
+ custom_css = """
 
66
  #game-container {
67
+ max-width: 300px;
68
  margin: 0 auto;
69
  padding: 20px;
70
+ background: #f5f5f5;
71
+ border-radius: 10px;
72
  }
73
 
74
+ .board-row {
75
+ display: flex !important;
76
+ justify-content: center !important;
77
+ gap: 3px !important;
78
+ margin: 3px 0 !important;
 
 
 
 
 
79
  }
80
 
81
+ .cell {
82
+ width: 60px !important;
83
+ height: 60px !important;
84
+ font-size: 24px !important;
 
85
  font-weight: bold !important;
86
+ background: white !important;
87
  border: none !important;
88
+ color: #0066cc !important;
 
 
 
89
  display: flex !important;
90
  align-items: center !important;
91
  justify-content: center !important;
92
+ cursor: pointer !important;
93
+ padding: 0 !important;
94
+ margin: 0 !important;
95
  }
96
 
97
+ .board-container {
98
+ background: #ff0000;
99
+ padding: 3px;
100
+ width: fit-content;
101
+ margin: 20px auto;
102
+ border-radius: 4px;
103
  }
104
 
105
+ #status-message {
106
  text-align: center;
 
 
 
107
  margin: 15px 0;
108
+ font-size: 18px;
109
+ color: #333;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  }
111
 
112
+ #reset-button {
113
+ display: block !important;
114
+ margin: 20px auto !important;
115
+ padding: 10px 20px !important;
116
+ background: #e74c3c !important;
117
  color: white !important;
 
 
 
118
  border: none !important;
119
+ border-radius: 5px !important;
120
+ cursor: pointer !important;
121
+ font-size: 16px !important;
 
 
 
 
 
122
  }
123
 
124
+ #reset-button:hover {
125
+ background: #c0392b !important;
 
 
 
 
 
 
 
 
126
  }
127
  """
128
 
129
+ def create_board():
130
+ with gr.Blocks(css=custom_css) as demo:
 
 
131
  with gr.Column(elem_id="game-container"):
132
+ status = gr.Markdown("Player X's turn", elem_id="status-message")
 
 
 
 
 
 
133
 
134
+ # Create board container with red background
135
+ with gr.Column(elem_classes=["board-container"]):
136
+ # Create 3x3 grid
137
  buttons = [[None for _ in range(3)] for _ in range(3)]
138
  for i in range(3):
139
+ with gr.Row(elem_classes=["board-row"]):
140
  for j in range(3):
141
  buttons[i][j] = gr.Button(
142
  " ",
143
+ elem_classes=["cell"],
144
  elem_id=f"cell-{i}-{j}"
145
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
+ reset_btn = gr.Button("New Game", elem_id="reset-button")
 
 
 
 
 
 
148
 
149
  def handle_click(i, j):
150
+ if game.make_move(i, j):
151
+ symbol = game.board[i][j]
152
+ message = ""
153
+
154
+ if game.game_over:
155
+ if game.check_winner():
156
+ message = f"Player {symbol} wins! πŸŽ‰"
157
+ else:
158
+ message = "It's a tie! 🀝"
159
+ else:
160
+ next_player = "O" if symbol == "X" else "X"
161
+ message = f"Player {next_player}'s turn"
162
+
163
+ # Update all buttons
164
+ button_updates = {}
165
+ for r in range(3):
166
+ for c in range(3):
167
+ value = game.board[r][c] if game.board[r][c] is not None else " "
168
+ button_updates[buttons[r][c]] = value
169
+
170
+ return {status: message, **button_updates}
171
 
172
+ return {status: "Invalid move!"}
173
+
174
+ def reset_game():
175
+ game.reset()
176
+ updates = {status: "Player X's turn"}
177
+ for i in range(3):
178
+ for j in range(3):
179
+ updates[buttons[i][j]] = " "
180
+ return updates
 
 
 
 
 
181
 
182
  # Connect event handlers
 
 
 
 
 
 
 
 
 
 
 
 
183
  for i in range(3):
184
  for j in range(3):
185
  buttons[i][j].click(
186
  lambda x, y: handle_click(x, y),
187
  inputs=[gr.State(i), gr.State(j)],
188
+ outputs=[status, *sum(buttons, [])]
189
  )
190
 
191
+ reset_btn.click(
192
+ reset_game,
193
+ outputs=[status, *sum(buttons, [])]
194
  )
195
 
196
  return demo
197
 
198
+ # Launch the app
199
+ demo = create_board()
200
  demo.launch()