def __init__(self, num_rows, num_cols): self.num_rows = num_rows self.num_cols = num_cols self._grid = {} self._hash = zobrist.EMPTY_BOARD global neighbor_tables dim = (num_rows, num_cols) if dim not in neighbor_tables: init_neighbor_table(dim) if dim not in corner_tables: init_corner_table(dim) self.neighbor_table = neighbor_tables[dim] self.corner_table = corner_tables[dim] self.move_ages = MoveAge(self)
class Board(): def __init__(self, num_rows, num_cols): self.num_rows = num_rows self.num_cols = num_cols self._grid = {} self._hash = zobrist.EMPTY_BOARD global neighbor_tables dim = (num_rows, num_cols) if dim not in neighbor_tables: init_neighbor_table(dim) if dim not in corner_tables: init_corner_table(dim) self.neighbor_table = neighbor_tables[dim] self.corner_table = corner_tables[dim] self.move_ages = MoveAge(self) def neighbors(self, point): return self.neighbor_table[point] def corners(self, point): return self.corner_table[point] def place_stone(self, player, point): assert self.is_on_grid(point) if self._grid.get(point) is not None: print('Illegal play on %s' % str(point)) assert self._grid.get(point) is None # 0. Examine the adjacent points. adjacent_same_color = [] adjacent_opposite_color = [] liberties = [] self.move_ages.increment_all() self.move_ages.add(point) for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: liberties.append(neighbor) elif neighbor_string.color == player: if neighbor_string not in adjacent_same_color: adjacent_same_color.append(neighbor_string) else: if neighbor_string not in adjacent_opposite_color: adjacent_opposite_color.append(neighbor_string) new_string = GoString(player, [point], liberties) # tag::apply_zobrist[] # 1. Merge any adjacent strings of the same color. for same_color_string in adjacent_same_color: new_string = new_string.merged_with(same_color_string) for new_string_point in new_string.stones: self._grid[new_string_point] = new_string # Remove empty-point hash code. self._hash ^= zobrist.HASH_CODE[point, None] # Add filled point hash code. self._hash ^= zobrist.HASH_CODE[point, player] # end::apply_zobrist[] # 2. Reduce liberties of any adjacent strings of the opposite # color. # 3. If any opposite color strings now have zero liberties, # remove them. for other_color_string in adjacent_opposite_color: replacement = other_color_string.without_liberty(point) if replacement.num_liberties: self._replace_string(other_color_string.without_liberty(point)) else: self._remove_string(other_color_string) def _replace_string(self, new_string): for point in new_string.stones: self._grid[point] = new_string def _remove_string(self, string): for point in string.stones: self.move_ages.reset_age(point) # Removing a string can create liberties for other strings. for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: continue if neighbor_string is not string: self._replace_string(neighbor_string.with_liberty(point)) self._grid[point] = None # Remove filled point hash code. self._hash ^= zobrist.HASH_CODE[point, string.color] # Add empty point hash code. self._hash ^= zobrist.HASH_CODE[point, None] def is_self_capture(self, player, point): friendly_strings = [] for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: # This point has a liberty. Can't be self capture. return False elif neighbor_string.color == player: # Gather for later analysis. friendly_strings.append(neighbor_string) else: if neighbor_string.num_liberties == 1: # This move is real capture, not a self capture. return False if all(neighbor.num_liberties == 1 for neighbor in friendly_strings): return True return False def will_capture(self, player, point): for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: continue elif neighbor_string.color == player: continue else: if neighbor_string.num_liberties == 1: # This move would capture. return True return False def is_on_grid(self, point): return 1 <= point.row <= self.num_rows and \ 1 <= point.col <= self.num_cols def get(self, point): """Return the content of a point on the board. Returns None if the point is empty, or a Player if there is a stone on that point. """ string = self._grid.get(point) if string is None: return None return string.color def get_go_string(self, point): """Return the entire string of stones at a point. Returns None if the point is empty, or a GoString if there is a stone on that point. """ string = self._grid.get(point) if string is None: return None return string def __eq__(self, other): return isinstance(other, Board) and \ self.num_rows == other.num_rows and \ self.num_cols == other.num_cols and \ self._hash() == other._hash() def __deepcopy__(self, memodict={}): copied = Board(self.num_rows, self.num_cols) # Can do a shallow copy b/c the dictionary maps tuples # (immutable) to GoStrings (also immutable) copied._grid = copy.copy(self._grid) copied._hash = self._hash return copied # tag::return_zobrist[] def zobrist_hash(self): return self._hash
class Board: def __init__(self, num_rows, num_cols): self.num_rows = num_rows self.num_cols = num_cols self._grid = {} self._hash = zobrist.EMPTY_BOARD global neighbor_tables dim = (num_rows, num_cols) if dim not in neighbor_tables: init_neighbor_table(dim) if dim not in corner_tables: init_corner_table(dim) self.neighbor_table = neighbor_tables[dim] self.corner_table = corner_tables[dim] self.move_ages = MoveAge(self) def neighbors(self, point): return self.neighbor_table[point] def corners(self, point): return self.corner_table[point] def place_stone(self, player, point): assert self.is_on_grid(point) if self._grid.get(point) is not None: print('Illegal play on %s' % str(point)) assert self._grid.get(point) is None adjacent_same_color = [] adjacent_opposite_color = [] liberties = [] self.move_ages.increment_all() self.move_ages.add(point) for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: liberties.append(neighbor) elif neighbor_string.color == player: if neighbor_string not in adjacent_same_color: adjacent_same_color.append(neighbor_string) else: if neighbor_string not in adjacent_opposite_color: adjacent_opposite_color.append(neighbor_string) new_string = GoString(player, [point], liberties) for same_color_string in adjacent_same_color: new_string = new_string.merged_with(same_color_string) for new_string_point in new_string.stones: self._grid[new_string_point] = new_string self._hash ^= zobrist.HASH_CODE[point, None] self._hash ^= zobrist.HASH_CODE[point, player] for other_color_string in adjacent_opposite_color: replacement = other_color_string.without_liberty(point) if replacement.num_liberties: self._replace_string(other_color_string.without_liberty(point)) else: self._remove_string(other_color_string) def _replace_string(self, new_string): for point in new_string.stones: self._grid[point] = new_string def _remove_string(self, string): for point in string.stones: self.move_ages.reset_age(point) for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: continue if neighbor_string is not string: self._replace_string(neighbor_string.with_liberty(point)) self._grid[point] = None self._hash ^= zobrist.HASH_CODE[point, string.color] self._hash ^= zobrist.HASH_CODE[point, None] def is_self_capture(self, player, point): friendly_strings = [] for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: return False elif neighbor_string.color == player: friendly_strings.append(neighbor_string) else: if neighbor_string.num_liberties == 1: return False if all(neighbor.num_liberties == 1 for neighbor in friendly_strings): return True return False def will_capture(self, player, point): for neighbor in self.neighbor_table[point]: neighbor_string = self._grid.get(neighbor) if neighbor_string is None: continue elif neighbor_string.color == player: continue else: if neighbor_string.num_liberties == 1: return True return False def is_on_grid(self, point): return 1 <= point.row <= self.num_rows and \ 1 <= point.col <= self.num_cols def get(self, point): string = self._grid.get(point) if string is None: return None return string.color def get_go_string(self, point): string = self._grid.get(point) if string is None: return None return string def __eq__(self, other): return isinstance(other, Board) and \ self.num_rows == other.num_rows and \ self.num_cols == other.num_cols and \ self._hash() == other._hash() def __deepcopy__(self, memodict=None): if memodict is None: memodict = {} copied = Board(self.num_rows, self.num_cols) copied._grid = copy.copy(self._grid) copied._hash = self._hash return copied def zobrist_hash(self): return self._hash