def is_point_an_eye(board, point, color): if board.get(point) is not None: # <1> return False for neighbor in point.neighbors(): # <2> if board.is_on_grid(neighbor): neighbor_color = board.get(neighbor) if neighbor_color != color: return False friendly_corners = 0 # <3> off_board_corners = 0 corners = [ Point(point.row - 1, point.col - 1), Point(point.row - 1, point.col + 1), Point(point.row + 1, point.col - 1), Point(point.row + 1, point.col + 1), ] for corner in corners: if board.is_on_grid(corner): corner_color = board.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 # <4> return friendly_corners >= 3 # <5> # <1> An eye is an empty point. # <2> All adjacent points must contain friendly stones. # <3> We must control 3 out of 4 corners if the point is in the middle of the board; on the edge we must control all corners. # <4> Point is on the edge or corner. # <5> Point is in the middle. # end::eye[]
def is_point_an_eye(board, point, color): if board.get(point) is not None: return False # All adjacent points must contain friendly stones. for neighbor in board.neighbors(point): neighbor_color = board.get(neighbor) if neighbor_color != color: return False # We must control 3 out of 4 corners if the point is in the middle # of the board; on the edge we must control all corners. friendly_corners = 0 off_board_corners = 0 corners = [ Point(point.row - 1, point.col - 1), Point(point.row - 1, point.col + 1), Point(point.row + 1, point.col - 1), Point(point.row + 1, point.col + 1), ] for corner in corners: if board.is_on_grid(corner): corner_color = board.get(corner) if corner_color == color: friendly_corners += 1 else: off_board_corners += 1 if off_board_corners > 0: # Point is on the edge or corner. return off_board_corners + friendly_corners == 4 # Point is in the middle. return friendly_corners >= 3
def init_neighbor_table(dim): rows, cols = dim new_table = {} for r in range(1, rows + 1): for c in range(1, cols + 1): p = Point(row=r, col=c) full_neighbors = p.neighbors() true_neighbors = [ n for n in full_neighbors if 1 <= n.row <= rows and 1 <= n.col <= cols ] new_table[p] = true_neighbors neighbor_tables[dim] = new_table
def process_zip(self, zip_file_name, data_file_name, game_list): pid_header = str(os.getpid()) + ": " print(dt.now().strftime("%H:%M:%S.%f\t") + pid_header + "working on " + zip_file_name) tar_file = self.unzip_data(zip_file_name) zip_file = tarfile.open(self.data_dir + '/' + tar_file) name_list = zip_file.getnames() total_examples = self.num_total_examples(zip_file, game_list, name_list) shape = self.encoder.shape() feature_shape = np.insert(shape, 0, np.asarray([total_examples])) features = np.zeros(feature_shape) labels = np.zeros((total_examples, )) counter = 0 for index in game_list: name = name_list[index + 1] if not name.endswith('.sgf'): raise ValueError(name + ' is not a valid sgf') sgf_content = zip_file.extractfile(name).read() sgf = Sgf_game.from_string(sgf_content) game_state, first_move_done = self.get_handicap(sgf) for item in sgf.main_sequence_iter(): color, move_tuple = item.get_move() point = None if color is not None: if move_tuple is not None: row, col = move_tuple point = Point(row + 1, col + 1) move = Move.play(point) else: move = Move.pass_turn() if first_move_done and point is not None: features[counter] = self.encoder.encode(game_state) labels[counter] = self.encoder.encode_point(point) counter += 1 game_state = game_state.apply_move(move) first_move_done = True feature_file_base = self.data_dir + '/' + data_file_name + '_features_%d' label_file_base = self.data_dir + '/' + data_file_name + '_labels_%d' chunk = 0 # Due to files with large content, split up after chunksize chunksize = 1024 while features.shape[0] >= chunksize: feature_file = feature_file_base % chunk label_file = label_file_base % chunk chunk += 1 current_features, features = features[:chunksize], features[ chunksize:] current_labels, labels = labels[:chunksize], labels[chunksize:] np.save(feature_file, current_features) np.save(label_file, current_labels) print(dt.now().strftime("%H:%M:%S.%f\t") + pid_header + "completed " + zip_file_name)
def get_handicap(sgf): # Get handicap stones go_board = Board(19, 19) first_move_done = False move = None row = col = 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)) # black gets handicap first_move_done = True move = Move(Point(row=row, col=col)) game_state = GameState(go_board, Player.white, None, move) return game_state, first_move_done
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 = Point(row=r, col=c) full_corners = [ Point(row=p.row - 1, col=p.col - 1), Point(row=p.row - 1, col=p.col + 1), Point(row=p.row + 1, col=p.col - 1), Point(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 legal_moves(self): moves = [] for row in range(1, self.board.num_rows + 1): for col in range(1, self.board.num_cols + 1): move = Move.play(Point(row, col)) if self.is_valid_move(move): moves.append(move) # These two moves are always legal. moves.append(Move.pass_turn()) moves.append(Move.resign()) return moves
def select_move(self, game_state): """Choose a random valid move that preserves our own eyes.""" candidates = [] for r in range(1, game_state.board.num_rows + 1): for c in range(1, game_state.board.num_cols + 1): candidate = Point(row=r, col=c) if game_state.is_valid_move(Move.play(candidate)) and \ not is_point_an_eye(game_state.board, candidate, game_state.next_player): candidates.append(candidate) if not candidates: return Move.pass_turn() return Move.play(random.choice(candidates)) # end::random_bot[]
def evaluate_territory(board): status = {} 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: # <1> continue stone = board.get(p) if stone is not None: # <2> status[p] = board.get(p) else: group, neighbors = _collect_region(p, board) if len(neighbors) == 1: # <3> neighbor_stone = neighbors.pop() stone_str = 'b' if neighbor_stone == Player.black else 'w' fill_with = 'territory_' + stone_str else: fill_with = 'dame' # <4> for pos in group: status[pos] = fill_with return Territory(status)
def _collect_region(start_pos, board, visited=None): if visited is None: visited = {} 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 = Point(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 encode(self, game_state): board_tensor = np.zeros( (self.num_planes, self.board_height, self.board_width)) for r in range(self.board_height): for c in range(self.board_width): point = Point(row=r + 1, col=c + 1) go_string = game_state.board.get_go_string(point) if go_string and go_string.color == game_state.next_player: board_tensor[offset("stone_color")][r][c] = 1 elif go_string and go_string.color == game_state.next_player.other: board_tensor[offset("stone_color") + 1][r][c] = 1 else: board_tensor[offset("stone_color") + 2][r][c] = 1 board_tensor[offset("ones")] = self.ones() board_tensor[offset("zeros")] = self.zeros() if not is_point_an_eye(game_state.board, point, game_state.next_player): board_tensor[offset("sensibleness")][r][c] = 1 ages = min(game_state.board.move_ages.get(r, c), 8) if ages > 0: board_tensor[int(offset("turns_since") + ages)][r][c] = 1 if game_state.board.get_go_string(point): liberties = min( game_state.board.get_go_string(point).num_liberties, 8) board_tensor[int(offset("liberties") + liberties)][r][c] = 1 move = Move(point) if game_state.is_valid_move(move): new_state = game_state.apply_move(move) liberties = min( new_state.board.get_go_string(point).num_liberties, 8) board_tensor[int(offset("liberties_after") + liberties)][r][c] = 1 adjacent_strings = [ game_state.board.get_go_string(nb) for nb in point.neighbors() ] capture_count = 0 for go_string in adjacent_strings: other_player = game_state.next_player.other if go_string and go_string.num_liberties == 1 and go_string.color == other_player: capture_count += len(go_string.stones) capture_count = min(capture_count, 8) board_tensor[int(offset("capture_size") + capture_count)][r][c] = 1 if go_string and go_string.num_liberties == 1: go_string = game_state.board.get_go_string(point) if go_string: num_atari_stones = min(len(go_string.stones), 8) board_tensor[int( offset("self_atari_size") + num_atari_stones)][r][c] = 1 if is_ladder_capture(game_state, point): board_tensor[offset("ladder_capture")][r][c] = 1 if is_ladder_escape(game_state, point): board_tensor[offset("ladder_escape")][r][c] = 1 if self.use_player_plane: if game_state.next_player == Player.black: board_tensor[offset("ones")] = self.ones() else: board_tensor[offset("zeros")] = self.zeros() return board_tensor
def decode_point_index(self, index): row = index // self.board_width col = index % self.board_width return Point(row=row + 1, col=col + 1)