def is_point_an_eye(board, point, color): # an eye is an empty point if board.get(point) is not None: return False for neighbor in point.neighbors(): if board.is_on_grid(neighbor): neighbor_color = board.get(neighbor) if neighbor_color != color: return False 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 0 < off_board_corners: # point is on the edge or corner return 4 == off_board_corners + friendly_corners # point is in the middle return 3 <= friendly_corners
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 _update_cache(self, dim): 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(Point(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 = 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 print_board(board): for row in range(board.num_rows, 0, -1): bump = " " if row <= 9 else "" line = [] for col in range(1, board.num_cols + 1): stone = board.get(Point(row=row, col=col)) line.append(STONE_TO_CHAR[stone]) print('%s%d %s' % (bump, row, ''.join(line))) print(' ' + ' '.join(COLS[:board.num_cols]))
def _encode_and_persist(self, sgf_p): sgf = SGFGame.from_string(sgf_p.read_text()) ## determine winner #winner = sgf.get_winner() #if winner is None: # print('no winner: %s' % sgf_p.name) # return # determine the initial game state by applying all handicap stones game_state, first_move_done = self._get_handicap(sgf) label = [] data = [] # iterate over all moves in the SGF (game) 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: # get coordinates of this move row, col = move_tuple point = Point(row + 1, col + 1) move = Move.play(point) # allow only valid moves if not game_state.is_valid_move(move): print('invalid move: %s' % sgf_p.name) return else: # pass move = Move.pass_turn() if first_move_done and point is not None: # use only winner's moves #if first_move_done and point is not None and winner == color: # encode the current game state as feature d = self.encoder.encode(game_state) # next move is the label for the this feature l = self.encoder.encode_point(point) data.append(d) label.append(l) # apply move to board and proceed with next one game_state = game_state.apply_move(move) first_move_done = True # create numpy compressed file size = len(data) if 0 == size: print('empty: %s' % sgf_p.name) return assert len(label) == size, 'label with invalid size' assert len(data) == size, 'data with invalid size' npz_p = self.processed_p.joinpath('%s-%s-%d' % (self.encoder.name(), sgf_p.stem, size)) label = np.array(label, dtype=np.int) data = np.array(data, dtype=np.int) np.savez_compressed(str(npz_p), d=data, l=label)
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))
def legal_moves(self): if self.is_over(): return [] 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 capture_diff(game_state): black_stones = 0 white_stones = 0 for r in range(1, game_state.board.num_rows + 1): for c in range(1, game_state.board.num_cols + 1): p = Point(r, c) color = game_state.board.get(p) if color == Player.black: black_stones += 1 elif color == Player.white: white_stones += 1 diff = black_stones - white_stones if game_state.next_player == Player.black: return diff return -1 * diff
def _get_handicap(self, sgf): board = Board(19, 19) first_move_done = False game_state = GameState.new_game(19) if sgf.get_handicap() is not None: point = None for setup in sgf.get_root().get_setup_stones(): for move in setup: row, col = move point = Point(row + 1, col + 1) board.place_stone(Player.black, point) first_move_done = True if point is not None: game_state = GameState(board, Player.white, None, Move.play(point)) return game_state, first_move_done
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 gtp_position_to_coords(gtp_position): col_str, row_str = gtp_position[0], gtp_position[1:] point = Point(int(row_str), COLS.find(col_str.upper()) + 1) return point
def point_from_coords(coords): col = COLS.index(coords[0]) + 1 row = int(coords[1:]) return Point(row=row, col=col)