def is_point_an_eye(gboard: GBoard, gpoint: GPoint, color: GPlayer): # Eye is by definition an empty point if gboard.get(gpoint) is not None: return False # It is not an eye where there is mixed stone for neighbour in gpoint.neighbours(): if gboard.is_on_grid(neighbour): neighbour_color = gboard.get(neighbour) if neighbour_color != color: return False # We have to control at least 3 corners for the eye to be settled on the middle of the board # On the edge, we must control every corner friendly_corners = 0 off_board_corners = 0 corners = [ GPoint(gpoint.row - 1, gpoint.col - 1), GPoint(gpoint.row - 1, gpoint.col + 1), GPoint(gpoint.row + 1, gpoint.col - 1), GPoint(gpoint.row + 1, gpoint.col + 1), ] for corner in corners: if gboard.is_on_grid(corner): corner_color = gboard.get(corner) if corner_color == color: friendly_corners += 1 else: off_board_corners += 1 if off_board_corners > 0: return off_board_corners + friendly_corners == 4 return friendly_corners >= 3
def init_neighbour_table(dim): rows, cols = dim new_table = {} for r in range(1, rows + 1): for c in range(1, cols + 1): p = GPoint(row=r, col=c) full_neighbours = p.neighbours() true_neighbours = [ n for n in full_neighbours if 1 <= n.row <= rows and 1 <= n.col <= cols ] new_table[p] = true_neighbours neighbour_tables[dim] = new_table
def test_capture(self): board = GBoard(19, 19) board.place_stone(GPlayer.black, GPoint(2, 2)) board.place_stone(GPlayer.white, GPoint(1, 2)) self.assertEqual(GPlayer.black, board.get(GPoint(2, 2))) board.place_stone(GPlayer.white, GPoint(2, 1)) self.assertEqual(GPlayer.black, board.get(GPoint(2, 2))) board.place_stone(GPlayer.white, GPoint(2, 3)) self.assertEqual(GPlayer.black, board.get(GPoint(2, 2))) board.place_stone(GPlayer.white, GPoint(3, 2)) self.assertIsNone(board.get(GPoint(2, 2)))
def _collect_region(start_pos: GPoint, board: GBoard, visited: bool = None): """Find the contiguous section of a board containing a point. Also identify all the boundary points. """ if visited is None: visited: Dict[GPoint, bool] = {} if start_pos in visited: return [], set() all_points = [start_pos] all_borders = set() visited[start_pos] = True here = board.get(start_pos) deltas = [(-1, 0), (1, 0), (0, -1), (0, 1)] for delta_r, delta_c in deltas: next_p = GPoint(row=start_pos.row + delta_r, col=start_pos.col + delta_c) if not board.is_on_grid(next_p): continue neighbor = board.get(next_p) if neighbor == here: points, borders = _collect_region(next_p, board, visited) all_points += points all_borders |= borders else: all_borders.add(neighbor) return all_points, all_borders
def evaluate_territory(gboard: GBoard): """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[GPoint, Union[GPlayer, str]] = {} for r in range(1, gboard.num_rows + 1): for c in range(1, gboard.num_cols + 1): p = GPoint(row=r, col=c) if p in status: # Already visited this as part of a different group. continue stone = gboard.get(p) if stone is not None: # It's a stone. status[p] = gboard.get(p) else: group, neighbors = _collect_region(p, gboard) if len(neighbors) == 1: # Completely surrounded by black or white. neighbor_stone = neighbors.pop() stone_str = 'b' if neighbor_stone == GPlayer.black else 'w' fill_with = 'territory_' + stone_str else: # Dame. fill_with = 'dame' for pos in group: status[pos] = fill_with return GTerritory(status)
def _update_cache(self, dim: (int, int)): self.dim = dim rows, cols = dim self.point_cache = [] for r in range(1, rows + 1): for c in range(1, cols + 1): self.point_cache.append(GPoint(row=r, col=c))
def init_corner_table(dim): rows, cols = dim new_table = {} for r in range(1, rows + 1): for c in range(1, cols + 1): p = GPoint(row=r, col=c) full_corners = [ GPoint(row=p.row - 1, col=p.col - 1), GPoint(row=p.row - 1, col=p.col + 1), GPoint(row=p.row + 1, col=p.col - 1), GPoint(row=p.row + 1, col=p.col + 1), ] true_corners = [ n for n in full_corners if 1 <= n.row <= rows and 1 <= n.col <= cols ] new_table[p] = true_corners corner_tables[dim] = new_table
def print_board(board: GBoard): table = [[""] + list(COLS[:board.num_cols])] for row in range(board.num_rows, 0, -1): line = [row] for col in range(1, board.num_cols + 1): stone = board.get(GPoint(row=row, col=col)) line.append(STONE_TO_CHAR[stone]) table.append(line) print(AsciiTable(table).table)
def test_empty_triangle(self): board = GBoard(5, 5) board.place_stone(GPlayer.black, GPoint(1, 1)) board.place_stone(GPlayer.black, GPoint(1, 2)) board.place_stone(GPlayer.black, GPoint(2, 2)) board.place_stone(GPlayer.white, GPoint(2, 1)) black_string = board.get_gstring(GPoint(1, 1)) six.assertCountEqual( self, [GPoint(3, 2), GPoint(2, 3), GPoint(1, 3)], black_string.liberties)
def encode(self, game_state: GState): board_matrix = np.zeros(self.shape()) next_gplayer = game_state.next_gplayer for r in range(self.board_height): for c in range(self.board_width): p = GPoint(row=r + 1, col=c + 1) gstring = game_state.gboard.get_gstring(p) if gstring is None: continue if gstring.color == next_gplayer: board_matrix[0, r, c] = 1 else: board_matrix[0, r, c] = -1 return board_matrix
def legal_moves(self): if self.is_over(): return [] moves = [] for row in range(1, self.gboard.num_rows + 1): for col in range(1, self.gboard.num_cols + 1): move = GMove.play(GPoint(row, col)) if self.is_valid_move(move): moves.append(move) # These two moves are always legal. moves.append(GMove.pass_turn()) moves.append(GMove.resign()) return moves
def decode_point_index(self, index): row = index // self.board_width col = index % self.board_width return GPoint(row=row + 1, col=col + 1)
def test_remove_liberties(self): board = GBoard(5, 5) board.place_stone(GPlayer.black, GPoint(3, 3)) board.place_stone(GPlayer.white, GPoint(2, 2)) white_string = board.get_gstring(GPoint(2, 2)) six.assertCountEqual( self, [GPoint(2, 3), GPoint(2, 1), GPoint(1, 2), GPoint(3, 2)], white_string.liberties) board.place_stone(GPlayer.black, GPoint(3, 2)) white_string = board.get_gstring(GPoint(2, 2)) six.assertCountEqual( self, [GPoint(2, 3), GPoint(2, 1), GPoint(1, 2)], white_string.liberties)
def to_python(state): if state is None: return 'None' if state == GPlayer.black: return GPlayer.black return GPlayer.white MAX63 = 0x7fffffffffffffff table = {} empty_board = 0 for row in range(1, 20): for col in range(1, 20): for state in (None, GPlayer.black, GPlayer.white): code = random.randint(0, MAX63) table[GPoint(row, col), state] = code if state is None: empty_board ^= code print('from .gotypes import Player, Point') print('') print("__all__ = ['HASH_CODE', 'EMPTY_BOARD']") print('') print('HASH_CODE = {') for (pt, state), hash_code in table.items(): print(' (%r, %s): %r,' % (pt, to_python(state), hash_code)) print('}') print('') print('EMPTY_BOARD = %d' % (empty_board,))