SmokeyBandit commited on
Commit
ecd7e7e
·
verified ·
1 Parent(s): 312a8aa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -97
app.py CHANGED
@@ -33,7 +33,7 @@ class GoGame:
33
  if color == 0:
34
  return set()
35
 
36
- group = set([(x, y)])
37
  frontier = [(x, y)]
38
 
39
  while frontier:
@@ -66,18 +66,15 @@ class GoGame:
66
  def is_valid_move(self, x, y):
67
  if self.board[x, y] != 0:
68
  return False
69
-
70
- # Make temporary move
71
  self.board[x, y] = self.current_player
72
-
73
- # Check for suicide rule
74
- has_liberties = self.has_liberties(x, y)
75
  captures_enemy = self.capture_stones() > 0
76
-
77
- # Undo temporary move and captures
78
  self.board[x, y] = 0
79
-
80
- return has_liberties or captures_enemy
81
 
82
  def make_move(self, x, y):
83
  if not self.is_valid_move(x, y):
@@ -115,7 +112,6 @@ class GoGame:
115
  return move
116
 
117
  def medium_ai(self, valid_moves):
118
- # Prioritize moves near the last human move
119
  if self.last_move:
120
  lx, ly = self.last_move
121
  valid_moves.sort(key=lambda p: abs(p[0] - lx) + abs(p[1] - ly))
@@ -128,7 +124,6 @@ class GoGame:
128
  return valid_moves[0]
129
 
130
  def hard_ai(self, valid_moves):
131
- # Check for capturing moves
132
  for move in valid_moves:
133
  self.board[move] = self.current_player
134
  if self.capture_stones() > 0:
@@ -136,7 +131,6 @@ class GoGame:
136
  return move
137
  self.board[move] = 0
138
 
139
- # Check for moves that prevent capture
140
  opponent = -self.current_player
141
  self.current_player = opponent
142
  for move in valid_moves:
@@ -156,10 +150,10 @@ def create_board_image(board, last_move=None, hover_pos=None):
156
  margin = 40
157
  total_size = board.shape[0] * cell_size + 2 * margin
158
 
159
- # Create wooden background
160
  image = np.full((total_size, total_size, 3), [219, 179, 119], dtype=np.uint8)
161
 
162
- # Draw grid with thicker lines
163
  for i in range(board.shape[0]):
164
  cv2.line(image,
165
  (margin + i * cell_size, margin),
@@ -172,7 +166,7 @@ def create_board_image(board, last_move=None, hover_pos=None):
172
  (0, 0, 0),
173
  2)
174
 
175
- # Draw star points (hoshi)
176
  star_points = [(2, 2), (2, 6), (4, 4), (6, 2), (6, 6)]
177
  for point in star_points:
178
  cv2.circle(image,
@@ -182,59 +176,55 @@ def create_board_image(board, last_move=None, hover_pos=None):
182
  -1,
183
  cv2.LINE_AA)
184
 
185
- # Draw hover position indicator
186
  if hover_pos:
187
- hover_x, hover_y = hover_pos
188
- center = (margin + hover_y * cell_size, margin + hover_x * cell_size)
189
- # Draw semi-transparent stone preview
190
- color = (0, 0, 0) if board.sum() == 0 or board.sum() == 1 else (255, 255, 255)
191
- cv2.circle(image, center, 23, color, -1, cv2.LINE_AA)
192
- cv2.circle(image, center, 23, (255, 255, 255), 1, cv2.LINE_AA)
193
- # Add transparency
194
  overlay = image.copy()
195
- cv2.circle(overlay, center, 23, color, -1, cv2.LINE_AA)
 
196
  image = cv2.addWeighted(overlay, 0.5, image, 0.5, 0)
 
197
 
198
- # Draw stones with enhanced 3D effect
199
  for i in range(board.shape[0]):
200
  for j in range(board.shape[1]):
201
  if board[i, j] != 0:
202
  center = (margin + j * cell_size, margin + i * cell_size)
203
 
204
- # Shadow effect
205
  cv2.circle(image,
206
- (center[0] + 2, center[1] + 2),
207
- 23,
208
- (0, 0, 0, 128),
209
- -1,
210
- cv2.LINE_AA)
211
 
212
- # Stone
213
- color = (0, 0, 0) if board[i, j] == 1 else (255, 255, 255)
214
- cv2.circle(image, center, 23, color, -1, cv2.LINE_AA)
215
 
216
- # Highlight for 3D effect
217
- if board[i, j] == -1: # White stones
218
  cv2.circle(image,
219
- (center[0] - 5, center[1] - 5),
220
- 8,
221
- (240, 240, 240),
222
- -1,
223
- cv2.LINE_AA)
224
- else: # Black stones
225
  cv2.circle(image,
226
- (center[0] - 5, center[1] - 5),
227
- 8,
228
- (40, 40, 40),
229
- -1,
230
- cv2.LINE_AA)
231
 
232
- # Highlight last move
233
  if last_move:
234
- x, y = last_move
235
- center = (margin + y * cell_size, margin + x * cell_size)
236
- color = (255, 0, 0) # Red marker
237
- cv2.circle(image, center, 5, color, -1, cv2.LINE_AA)
238
 
239
  return Image.fromarray(image)
240
 
@@ -247,42 +237,38 @@ class GradioGoGame:
247
  def process_click(self, evt: gr.SelectData, difficulty):
248
  cell_size = 60
249
  margin = 40
250
-
251
- # Calculate board coordinates from click position
252
- y = round((evt.index[1] - margin) / cell_size)
253
- x = round((evt.index[0] - margin) / cell_size)
254
-
255
- # Validate coordinates
256
- if not (0 <= x < self.game.size and 0 <= y < self.game.size):
257
  return create_board_image(self.game.board, self.game.last_move), "Invalid click position"
258
-
259
  self.difficulty = Difficulty(difficulty)
260
-
261
- if not self.game.is_valid_move(x, y):
262
- return create_board_image(self.game.board, self.game.last_move), "Invalid move"
263
-
264
- # Make player move
265
- self.game.make_move(x, y)
266
-
267
- # AI Move (if enabled)
268
- if self.difficulty != Difficulty.EASY:
269
- ai_move = self.game.ai_move(self.difficulty)
270
- if ai_move:
271
- print(f"AI moved to: {ai_move}")
272
-
273
- return create_board_image(self.game.board, self.game.last_move), "Move registered"
274
-
275
 
276
  def update_hover(self, evt: gr.SelectData):
277
- # Convert mouse position to board coordinates
278
  cell_size = 60
279
  margin = 40
 
 
 
 
280
 
281
- x = round((evt.index[1] - margin) / cell_size)
282
- y = round((evt.index[0] - margin) / cell_size)
283
-
284
- if 0 <= x < self.game.size and 0 <= y < self.game.size:
285
- self.hover_pos = (x, y)
286
  else:
287
  self.hover_pos = None
288
 
@@ -298,13 +284,13 @@ def create_interface():
298
 
299
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
300
  gr.Markdown("""
301
- # Go Game vs AI
302
  Play the ancient game of Go against an AI opponent. Black plays first.
303
 
304
- Rules:
305
- - Click on any intersection to place a stone
306
- - Capture enemy stones by surrounding them
307
- - Stones must have liberties (empty adjacent points) to survive
308
  """)
309
 
310
  with gr.Row():
@@ -324,21 +310,21 @@ def create_interface():
324
  )
325
 
326
  with gr.Column(scale=1):
327
- with gr.Group():
328
- difficulty = gr.Radio(
329
- choices=[d.value for d in Difficulty],
330
- value=Difficulty.EASY.value,
331
- label="AI Difficulty"
332
- )
333
- reset_btn = gr.Button("Reset Game", variant="secondary")
334
 
335
- # Handle clicks and hover
336
- board_output.click(
337
  game.process_click,
338
  inputs=[board_output, difficulty],
339
  outputs=[board_output, msg_output]
340
  )
341
 
 
342
  board_output.mousemove(
343
  game.update_hover,
344
  inputs=board_output,
@@ -354,4 +340,4 @@ def create_interface():
354
 
355
  if __name__ == "__main__":
356
  interface = create_interface()
357
- interface.launch()
 
33
  if color == 0:
34
  return set()
35
 
36
+ group = {(x, y)}
37
  frontier = [(x, y)]
38
 
39
  while frontier:
 
66
  def is_valid_move(self, x, y):
67
  if self.board[x, y] != 0:
68
  return False
69
+
70
+ # Make a temporary move.
71
  self.board[x, y] = self.current_player
72
+ valid = self.has_liberties(x, y)
 
 
73
  captures_enemy = self.capture_stones() > 0
74
+ # Undo temporary move.
 
75
  self.board[x, y] = 0
76
+
77
+ return valid or captures_enemy
78
 
79
  def make_move(self, x, y):
80
  if not self.is_valid_move(x, y):
 
112
  return move
113
 
114
  def medium_ai(self, valid_moves):
 
115
  if self.last_move:
116
  lx, ly = self.last_move
117
  valid_moves.sort(key=lambda p: abs(p[0] - lx) + abs(p[1] - ly))
 
124
  return valid_moves[0]
125
 
126
  def hard_ai(self, valid_moves):
 
127
  for move in valid_moves:
128
  self.board[move] = self.current_player
129
  if self.capture_stones() > 0:
 
131
  return move
132
  self.board[move] = 0
133
 
 
134
  opponent = -self.current_player
135
  self.current_player = opponent
136
  for move in valid_moves:
 
150
  margin = 40
151
  total_size = board.shape[0] * cell_size + 2 * margin
152
 
153
+ # Create wooden background.
154
  image = np.full((total_size, total_size, 3), [219, 179, 119], dtype=np.uint8)
155
 
156
+ # Draw grid with thicker lines.
157
  for i in range(board.shape[0]):
158
  cv2.line(image,
159
  (margin + i * cell_size, margin),
 
166
  (0, 0, 0),
167
  2)
168
 
169
+ # Draw star points (hoshi).
170
  star_points = [(2, 2), (2, 6), (4, 4), (6, 2), (6, 6)]
171
  for point in star_points:
172
  cv2.circle(image,
 
176
  -1,
177
  cv2.LINE_AA)
178
 
179
+ # Draw hover position indicator.
180
  if hover_pos:
181
+ hover_row, hover_col = hover_pos
182
+ center = (margin + hover_col * cell_size, margin + hover_row * cell_size)
 
 
 
 
 
183
  overlay = image.copy()
184
+ # Draw a semi-transparent preview.
185
+ cv2.circle(overlay, center, 23, (0, 0, 0), -1, cv2.LINE_AA)
186
  image = cv2.addWeighted(overlay, 0.5, image, 0.5, 0)
187
+ cv2.circle(image, center, 23, (255, 255, 255), 1, cv2.LINE_AA)
188
 
189
+ # Draw stones with enhanced 3D effect.
190
  for i in range(board.shape[0]):
191
  for j in range(board.shape[1]):
192
  if board[i, j] != 0:
193
  center = (margin + j * cell_size, margin + i * cell_size)
194
 
195
+ # Shadow effect.
196
  cv2.circle(image,
197
+ (center[0] + 2, center[1] + 2),
198
+ 23,
199
+ (0, 0, 0),
200
+ -1,
201
+ cv2.LINE_AA)
202
 
203
+ # Stone.
204
+ stone_color = (0, 0, 0) if board[i, j] == 1 else (255, 255, 255)
205
+ cv2.circle(image, center, 23, stone_color, -1, cv2.LINE_AA)
206
 
207
+ # Highlight for 3D effect.
208
+ if board[i, j] == -1: # White stone highlight.
209
  cv2.circle(image,
210
+ (center[0] - 5, center[1] - 5),
211
+ 8,
212
+ (240, 240, 240),
213
+ -1,
214
+ cv2.LINE_AA)
215
+ else: # Black stone highlight.
216
  cv2.circle(image,
217
+ (center[0] - 5, center[1] - 5),
218
+ 8,
219
+ (40, 40, 40),
220
+ -1,
221
+ cv2.LINE_AA)
222
 
223
+ # Highlight last move.
224
  if last_move:
225
+ row, col = last_move
226
+ center = (margin + col * cell_size, margin + row * cell_size)
227
+ cv2.circle(image, center, 5, (255, 0, 0), -1, cv2.LINE_AA)
 
228
 
229
  return Image.fromarray(image)
230
 
 
237
  def process_click(self, evt: gr.SelectData, difficulty):
238
  cell_size = 60
239
  margin = 40
240
+
241
+ # evt.index returns pixel coordinates as (x, y).
242
+ # Convert to board coordinates:
243
+ col = round((evt.index[0] - margin) / cell_size)
244
+ row = round((evt.index[1] - margin) / cell_size)
245
+
246
+ if not (0 <= row < self.game.size and 0 <= col < self.game.size):
247
  return create_board_image(self.game.board, self.game.last_move), "Invalid click position"
248
+
249
  self.difficulty = Difficulty(difficulty)
250
+
251
+ if not self.game.make_move(row, col):
252
+ return create_board_image(self.game.board, self.game.last_move), "Invalid move (occupied or suicide)"
253
+
254
+ # AI Move.
255
+ ai_move = self.game.ai_move(self.difficulty)
256
+ if ai_move is None:
257
+ return create_board_image(self.game.board, self.game.last_move), "Game Over"
258
+
259
+ status = f"Black captures: {self.game.captured_white} | White captures: {self.game.captured_black}"
260
+ return create_board_image(self.game.board, self.game.last_move), f"AI moved to: {ai_move}\n{status}"
 
 
 
 
261
 
262
  def update_hover(self, evt: gr.SelectData):
 
263
  cell_size = 60
264
  margin = 40
265
+
266
+ # Convert pixel position to board coordinates.
267
+ col = round((evt.index[0] - margin) / cell_size)
268
+ row = round((evt.index[1] - margin) / cell_size)
269
 
270
+ if 0 <= row < self.game.size and 0 <= col < self.game.size:
271
+ self.hover_pos = (row, col)
 
 
 
272
  else:
273
  self.hover_pos = None
274
 
 
284
 
285
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
286
  gr.Markdown("""
287
+ # Go Game vs AI
288
  Play the ancient game of Go against an AI opponent. Black plays first.
289
 
290
+ **Rules:**
291
+ - Click on any intersection to place a stone.
292
+ - Capture enemy stones by surrounding them.
293
+ - Stones must have liberties (empty adjacent points) to survive.
294
  """)
295
 
296
  with gr.Row():
 
310
  )
311
 
312
  with gr.Column(scale=1):
313
+ difficulty = gr.Radio(
314
+ choices=[d.value for d in Difficulty],
315
+ value=Difficulty.EASY.value,
316
+ label="AI Difficulty"
317
+ )
318
+ reset_btn = gr.Button("Reset Game", variant="secondary")
 
319
 
320
+ # Use .select() for click events on the interactive image.
321
+ board_output.select(
322
  game.process_click,
323
  inputs=[board_output, difficulty],
324
  outputs=[board_output, msg_output]
325
  )
326
 
327
+ # Use .mousemove() for hover updates (if supported by your Gradio version).
328
  board_output.mousemove(
329
  game.update_hover,
330
  inputs=board_output,
 
340
 
341
  if __name__ == "__main__":
342
  interface = create_interface()
343
+ interface.launch()