diff --git a/code/dlgo/goboard_slow.py b/code/dlgo/goboard_slow.py index fb7f9cac..13417122 100644 --- a/code/dlgo/goboard_slow.py +++ b/code/dlgo/goboard_slow.py @@ -213,10 +213,29 @@ def does_move_violate_ko(self, player, move): next_board.place_stone(player, move.point) next_situation = (player.other, next_board) past_state = self.previous_state + while past_state is not None: - if past_state.situation == next_situation: + # Assume ko is violated. + ko_violated = True + + past_board = past_state.situation[1] + next_board = next_situation[1] + + for row in range(self.board.num_rows, 0, -1): + for col in range(1, self.board.num_cols + 1): + past_stone = past_board.get(Point(row=row, col=col)) + next_stone = next_board.get(Point(row=row, col=col)) + + # If a point/player between the boards does not match, ko is + # not violated. + if past_stone != next_stone: + ko_violated = False + + if ko_violated: return True + past_state = past_state.previous_state + return False # end::is_ko[] diff --git a/code/dlgo/goboard_test.py b/code/dlgo/goboard_test.py index feb4f2b0..2bcfada5 100644 --- a/code/dlgo/goboard_test.py +++ b/code/dlgo/goboard_test.py @@ -76,6 +76,67 @@ def test_empty_triangle(self): [Point(3, 2), Point(2, 3), Point(1, 3)], black_string.liberties) + def test_GameState_does_move_violate_ko(self): + # Testing Figures 3.5-3.7. + game = GameState.new_game(6) + board = game.board + board.place_stone(Player.black, Point(1, 2)) + board.place_stone(Player.black, Point(1, 3)) + board.place_stone(Player.white, Point(1, 4)) + board.place_stone(Player.white, Point(1, 6)) + board.place_stone(Player.black, Point(2, 2)) + board.place_stone(Player.white, Point(2, 3)) + board.place_stone(Player.black, Point(2, 4)) + board.place_stone(Player.black, Point(2, 5)) + board.place_stone(Player.white, Point(2, 6)) + board.place_stone(Player.black, Point(3, 2)) + board.place_stone(Player.white, Point(3, 3)) + board.place_stone(Player.white, Point(3, 4)) + board.place_stone(Player.white, Point(3, 5)) + + next_player, _ = game.situation + self.assertTrue(next_player, Player.black) + + move = Move(Point(1, 5), is_pass=False, is_resign=False) + self.assertFalse(game.does_move_violate_ko(Player.black, move)) + move = move.play(Point(1, 5)) + game = game.apply_move(move) + + next_player, _ = game.situation + self.assertTrue(next_player, Player.white) + + # Verify white can play at 1,4. + move = Move(Point(1, 4), is_pass=False, is_resign=False) + self.assertFalse(game.does_move_violate_ko(Player.white, move)) + move = move.play(Point(1, 4)) + game = game.apply_move(move) + + # Testing a real Ko. Figure 2.5 + game = GameState.new_game(5) + board = game.board + board.place_stone(Player.black, Point(2, 2)) + board.place_stone(Player.black, Point(3, 1)) + board.place_stone(Player.white, Point(3, 2)) + board.place_stone(Player.black, Point(3, 3)) + board.place_stone(Player.white, Point(4, 1)) + board.place_stone(Player.white, Point(4, 3)) + board.place_stone(Player.white, Point(5, 2)) + + # Have black capture 4,2. + next_player, _ = game.situation + self.assertTrue(next_player, Player.black) + + move = Move(Point(4, 2), is_pass=False, is_resign=False) + self.assertFalse(game.does_move_violate_ko(Player.black, move)) + move = move.play(Point(4, 2)) + game = game.apply_move(move) + + # Have white break Ko rule. + next_player, _ = game.situation + self.assertTrue(next_player, Player.white) + move = Move(Point(3, 2), is_pass=False, is_resign=False) + move = move.play(Point(3, 2)) + self.assertTrue(game.does_move_violate_ko(Player.white, move)) class GameTest(unittest.TestCase): def test_new_game(self):