def _collect_region(start_pos: Point, board: goboard.Board, visited: Set[Point] = None) -> \ Tuple[List[Point], Set[Optional[Player]]]: """ Find the contiguous section of a board containing a point. Also identify all the boundary points. start_pos can be empty or it can have a player (black or white) Returns List of contiguous points (empty points, usually) and set of bordering Players For example, if start_pos is empty, the bordering player set can be {White}, {Black} or {White, Black}. But also, if start_pos has White Player, the bordering player set can be {None}, {Black} or {None, Black} """ if visited is None: visited = set() if start_pos in visited: return [], set() all_points = [start_pos] all_borders: Set[Optional[Player]] = set() visited.add(start_pos) player_at_start_pos: Optional[Player] = board.get(start_pos) next_points = board.neighbors(start_pos) for next_p in next_points: player_neighbor: Optional[Player] = board.get(next_p) if player_neighbor == player_at_start_pos: points, borders = _collect_region(next_p, board, visited) all_points += points all_borders |= borders else: all_borders.add(player_neighbor) return all_points, all_borders
def is_point_an_eye(board: Board, point: Point, color: Player): """ For our purposes, an eye is an empty point where all adjacent points and at least three out of four diagonally adjacent points are filled with friendly stones. NOTE Experienced Go players may notice that the preceding definition of eye will miss a valid eye in some cases. We’ll accept those errors to keep the implementation simple. """ if board.get(point) is not None: return False for neighbor in board.neighbors(point): neighbor_color = board.get(neighbor) if neighbor_color != color: return False corners: List[Point] = board.corners(point) off_board_corners: int = 4 - len(corners) friendly_corners: int = 0 for corner in corners: corner_color = board.get(corner) if corner_color == color: friendly_corners += 1 if off_board_corners > 0: return off_board_corners + friendly_corners == 4 else: return friendly_corners >= 3
def test_capture_is_not_suicide(self): board = Board(19, 19) board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.black, Point(1, 3)) board.place_stone(Player.white, Point(2, 1)) board.place_stone(Player.white, Point(1, 2)) self.assertIsNone(board.get(Point(1, 1))) self.assertEqual(Player.white, board.get(Point(2, 1))) self.assertEqual(Player.white, board.get(Point(1, 2)))
def test_middle(self): board = Board(19, 19) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.black, Point(3, 2)) board.place_stone(Player.black, Point(4, 2)) board.place_stone(Player.black, Point(4, 3)) board.place_stone(Player.white, Point(4, 4)) board.place_stone(Player.black, Point(3, 4)) board.place_stone(Player.black, Point(2, 4)) board.place_stone(Player.black, Point(2, 3)) self.assertTrue(is_point_an_eye(board, Point(3, 3), Player.black))
def get_handicap(sgf): go_board = Board(19, 19) first_move_done = False move = None game_state = GameState.new_game(19) if sgf.get_handicap() is not None and sgf.get_handicap() != 0: for setup in sgf.get_root().get_setup_stones(): for move in setup: row, col = move go_board.place_stone(Player.black, Point(row + 1, col + 1)) first_move_done = True game_state = GameState(go_board, Player.white, None, move) return game_state, first_move_done
def evaluate_territory(board: goboard.Board) -> Territory: """ Map a board into territory and dame. Any points that are completely surrounded by a single color are counted as territory; it makes no attempt to identify even trivially dead groups. """ status: Dict[Point, Union[Player, str]] = {} for r in range(1, board.num_rows + 1): for c in range(1, board.num_cols + 1): p = Point(row=r, col=c) if p in status: continue stone = board.get(p) if stone is not None: status[p] = stone else: group, neighbors = _collect_region(p, board) if len(neighbors) == 1: neighbor_stone = neighbors.pop() stone_str = 'b' if neighbor_stone == Player.black else 'w' fill_with = 'territory_' + stone_str else: fill_with = 'dame' for pos in group: status[pos] = fill_with return Territory(status)
def test_remove_liberties(self): board = Board(5, 5) board.place_stone(Player.black, Point(3, 3)) board.place_stone(Player.white, Point(2, 2)) white_string = board.get_go_string(Point(2, 2)) six.assertCountEqual( self, [Point(2, 3), Point(2, 1), Point(1, 2), Point(3, 2)], white_string.liberties) board.place_stone(Player.black, Point(3, 2)) white_string = board.get_go_string(Point(2, 2)) six.assertCountEqual( self, [Point(2, 3), Point(2, 1), Point(1, 2)], white_string.liberties)
def test_corner(self): board = Board(19, 19) board.place_stone(Player.black, Point(1, 2)) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.black, Point(2, 1)) self.assertTrue(is_point_an_eye(board, Point(1, 1), Player.black)) self.assertFalse(is_point_an_eye(board, Point(1, 1), Player.white))
def test_empty_triangle(self): board = Board(5, 5) board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(1, 2)) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.white, Point(2, 1)) black_string = board.get_go_string(Point(1, 1)) six.assertCountEqual( self, [Point(3, 2), Point(2, 3), Point(1, 3)], black_string.liberties)
def test_capture_two_stones(self): board = Board(19, 19) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.black, Point(2, 3)) board.place_stone(Player.white, Point(1, 2)) board.place_stone(Player.white, Point(1, 3)) self.assertEqual(Player.black, board.get(Point(2, 2))) self.assertEqual(Player.black, board.get(Point(2, 3))) board.place_stone(Player.white, Point(3, 2)) board.place_stone(Player.white, Point(3, 3)) self.assertEqual(Player.black, board.get(Point(2, 2))) self.assertEqual(Player.black, board.get(Point(2, 3))) board.place_stone(Player.white, Point(2, 1)) board.place_stone(Player.white, Point(2, 4)) self.assertIsNone(board.get(Point(2, 2))) self.assertIsNone(board.get(Point(2, 3)))
def test_scoring(self): # .w.ww # wwww. # bbbww # .bbbb # .b.b. board = Board(5, 5) board.place_stone(Player.black, Point(1, 2)) board.place_stone(Player.black, Point(1, 4)) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.black, Point(2, 3)) board.place_stone(Player.black, Point(2, 4)) board.place_stone(Player.black, Point(2, 5)) board.place_stone(Player.black, Point(3, 1)) board.place_stone(Player.black, Point(3, 2)) board.place_stone(Player.black, Point(3, 3)) board.place_stone(Player.white, Point(3, 4)) board.place_stone(Player.white, Point(3, 5)) board.place_stone(Player.white, Point(4, 1)) board.place_stone(Player.white, Point(4, 2)) board.place_stone(Player.white, Point(4, 3)) board.place_stone(Player.white, Point(4, 4)) board.place_stone(Player.white, Point(5, 2)) board.place_stone(Player.white, Point(5, 4)) board.place_stone(Player.white, Point(5, 5)) territory = scoring.evaluate_territory(board) self.assertEqual(9, territory.num_black_stones) self.assertEqual(4, territory.num_black_territory) self.assertEqual(9, territory.num_white_stones) self.assertEqual(3, territory.num_white_territory) self.assertEqual(0, territory.num_dame)
def new_game(cls, board_size): if isinstance(board_size, int): board_size = (board_size, board_size) board = Board(*board_size) return GameState(board, Player.black, None, None)