@@ -282,6 +282,35 @@ def pick_one(s: set[int]) -> int:
282
282
return (score [0 ], score [1 ])
283
283
284
284
285
+ def is_valid_move (self , row : int , col : int ) -> bool :
286
+ # Compute stone value
287
+ val = self .move % 2 + 1
288
+
289
+ # Pass is always allowed
290
+ if (row , col ) == (- 1 , - 1 ):
291
+ return True
292
+
293
+ # On top of another stone is never allowed
294
+ if self .grid [row , col ] != 0 :
295
+ return False
296
+
297
+ # If capturing, needs play_stone
298
+ for group in self .groups :
299
+ if group .group_type == val :
300
+ continue
301
+
302
+ if len (group - {(row , col )}) == 0 :
303
+ return self .__play_stone (row , col , False )
304
+
305
+ # Prohibit suicide
306
+ for group in self .groups :
307
+ if group .group_type == val :
308
+ continue
309
+
310
+ if len (group - {(row , col )}) == 0 :
311
+ return False
312
+
313
+
285
314
def play_stone (self , row : int , col : int , move : bool = True ) -> bool :
286
315
"""
287
316
Attempts to place a stone of value val at (row, col)
@@ -294,6 +323,23 @@ def play_stone(self, row: int, col: int, move: bool = True) -> bool:
294
323
move (optional): whether or not to update the board, default True
295
324
"""
296
325
326
+ return self .__play_stone (row , col , move )
327
+
328
+
329
+ def __play_stone (self , row : int , col : int , move : bool = True ) -> bool :
330
+ """
331
+ THIS IS A PRIVATE METHOD! DO NOT USE THIS OUTSIDE BOARD.PY
332
+
333
+ Attempts to place a stone of value val at (row, col)
334
+
335
+ Returns True if the move is valid, False if not
336
+
337
+ Args:
338
+ row: index of the row to place the stone
339
+ col: index of the column to place the stone
340
+ move (optional): whether or not to update the board, default True
341
+ """
342
+
297
343
# Compute stone value
298
344
val = self .move % 2 + 1
299
345
@@ -363,18 +409,14 @@ def play_stone(self, row: int, col: int, move: bool = True) -> bool:
363
409
if len (group .liberties ) > 0 :
364
410
new_candidate_groups .append (group )
365
411
continue
366
-
367
- # Remove captured stones from the board
368
- for i in group .intersections :
369
- candidate [i // self .size , i % self .size ] = 0
370
412
371
413
# Record captures
372
414
captured |= group .intersections
373
415
374
416
# Update for newly opened intersections
375
417
for group in candidate_groups :
376
418
group .replenish_liberties (captured )
377
-
419
+
378
420
# Prohibit suicide
379
421
for group in candidate_groups :
380
422
# Skip opposite color
@@ -386,6 +428,10 @@ def play_stone(self, row: int, col: int, move: bool = True) -> bool:
386
428
387
429
new_candidate_groups .append (group )
388
430
431
+ # Remove captured stones from the board
432
+ for i in captured :
433
+ candidate [i // self .size , i % self .size ] = 0
434
+
389
435
candidate_groups = new_candidate_groups
390
436
391
437
# Prohibit repetition
@@ -430,10 +476,9 @@ def available_moves(self) -> list[tuple[int, int]]:
430
476
431
477
for i in range (self .size ):
432
478
for j in range (self .size ):
433
- available = self .play_stone (
479
+ available = self .is_valid_move (
434
480
row = i ,
435
- col = j ,
436
- move = False
481
+ col = j
437
482
)
438
483
439
484
if available :
0 commit comments