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 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 encode(self, game_state): board_matrix = np.zeros(self.shape()) next_player = game_state.next_player for r in range(self.board_height): for c in range(self.board_width): p = Point(row=r + 1, col=c + 1) go_string = game_state.board.get_go_string(p) if go_string is None: continue if go_string.color == next_player: board_matrix[0, r, c] = 1 else: board_matrix[0, r, c] = -1 return board_matrix
def is_point_an_eye(board :Board, point: Point, color): # 目は空の点 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 # 点が盤の中央にある場合、4つの角のうち3つの角を支配する必要がある # 辺ではすべての角を支配する必要がある 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: # 点が角または辺にある return off_board_corners + friendly_corners == 4 # 点は中央にある return friendly_corners >= 3
def is_point_an_eye(board, point, color): # 石があれば眼じゃない 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: # Noneもだめ return False # さらに,その点の角(斜めの位置)のうち,3つ以上の角を支配する必要がある 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: return off_board_corners + friendly_corners == 4 # 点が辺または角にない(中央)とき return friendly_corners >= 3
def is_point_an_eye(board, point, color): # Occupied point if board.get(point) is not None: return False # All neighbours are friendly for neighbor in point.neighbors(): # Out of board if board.is_on_grid(neighbor): neighbor_color = board.get(neighbor) if neighbor_color != color: return False # Control 3 out of 4 corners if the point in the middle of the board # Control all corners if the point on the edge 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 the point on the edge or the corner if off_board_corners > 0: return off_board_corners + friendly_corners == 4 # Normal point return friendly_corners >= 3
def select_move(self, game_state): current_board = self.encode_game_state(game_state) current_board = torch.from_numpy(current_board).to(device) current_board = current_board.view(-1, 1, 9, 9) score = self.model(current_board) score = list(enumerate(score[0].cpu().data.numpy())) score = sorted(score, key=lambda v: v[1], reverse=True) for pos, _ in score: point = Point(pos // 9 + 1, pos % 9 + 1) if game_state.is_valid_move(goboard.Move.play(point)) and \ not is_point_an_eye(game_state.board, point, game_state.next_player): return goboard.Move.play(point) return goboard.Move.pass_turn()
def get_handicap(sgf): # Get handicap stones 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)) # black gets handicap first_move_done = True game_state = GameState(go_board, Player.white, None, move) return game_state, first_move_done
def is_point_an_eye(board, point, color): # Mot mat la mot diem trong if board.get(point) is not None: return False # Tat ca diem xung quanh mat do phai cung mau for neighbor in point.neighbors(): if board.is_on_grid(neighbor): neighbor_color = board.get(neighbor) if neighbor_color != color: return False # Kiem soat 3 tring 4 goc neu diem nam o giua bang; # nam tren canh, bat buoc kiem soat tat ca goc 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: # Diem nam tren canh hoac goc return off_board_corners + friendly_corners == 4 # Diem nam o giua return friendly_corners >= 3
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 select_move(self, game_state): # Choose a random valid move that preserves our 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 a point is empty, not a self-capture, doesn't violate ko and preserve eyes 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) # No valid moves then pass if not candidates: return Move.pass_turn() # Play a random move from the candidates return Move.play(random.choice(candidates))
def test_not_self_capture(self): # o.o.. # x.xo. board = Board(5, 5) board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(1, 3)) board.place_stone(Player.white, Point(2, 1)) board.place_stone(Player.white, Point(2, 3)) board.place_stone(Player.white, Point(1, 4)) self.assertFalse(board.is_self_capture(Player.black, Point(1, 2)))
def main(): MAX63 = 0x7fffffffffffffff table = {} empty_board = 0 for row in range(1, 20): for col in range(1, 20): for state in (Player.black, Player.white): code = random.randint(0, MAX63) table[Point(row, col), state] = code print('from .gotypes import Player, Point') print('') print("__all__ = ['HASH_CODE', 'EMPTY_BOARD']") print("") 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, ))
def select_move(self, game_state): """Choose a random valid move that preserves our own eyes""" # Get points that are a candidate for placing a stone 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 a point within the board is a valid move, save it as a # candidate 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 there are no candidates, pass if not candidates: return Move.pass_turn() # Else choose randomly among all the candidate return Move.play(random.choice(candidates))
def encode(self, game_state): board_tensor = np.zeros(self.shape()) base_plane = { game_state.next_player: 0, game_state.next_player.other: 3 } for row in range(self.board_height): for col in range(self.board_width): p = Point(row=row + 1, col=col + 1) go_string = game_state.board.get_go_string(p) if go_string is None: if game_state.does_move_violate_ko(game_state.next_player, Move.play(p)): board_tensor[6][row][col] = 1 else: liberty_plane = min(3, go_string.num_liberties) - 1 liberty_plane += base_plane[go_string.color] board_tensor[liberty_plane][row][col] = 1 return board_tensor
def get_area(point, board, visited=set()): if point in visited: return [], set() points_list = [point] player_color_borders = set() visited.add(point) current_point = board.get(point) for row_dif, col_dif in directions.values(): next_point = Point(row=point.row + row_dif, col=point.col + col_dif) if not board.is_on_grid(next_point): continue player_color = board.get(next_point) if player_color == current_point: points, borders = get_area(next_point, board, visited) points_list += points player_color_borders |= borders else: player_color_borders.add(player_color) return points_list, player_color_borders
def encode(self, game_state): board_tensor = np.zeros(self.shape()) if game_state.next_player == Player.black: board_tensor[8] = 1 else: board_tensor[9] = 1 for r in range(self.board_height): for c in range(self.board_width): p = Point(row=r + 1, col=c + 1) go_string = game_state.board.get_go_string(p) if go_string is None: if game_state.does_move_violate_ko(game_state.next_player, Move.play(p)): board_tensor[10][r][c] = 1 else: liberty_plane = min(4, go_string.num_liberties) - 1 if go_string.color == Player.white: liberty_plane += 4 board_tensor[liberty_plane][r][c] = 1 return board_tensor
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: continue stone = board.get(p) if stone is not None: status[p] = board.get(p) 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 = 'terrtory_' + stone_str else: fill_with = 'dame' for pos in group: status[pos] = fill_with return Territory(status)
def evaluate_territory(board: 'Board'): status = {} for r in range(1, board.num_rows + 1): for c in range(1, board.num_cols): point = Point(row=r, col=c) if point in status: continue stone = board.get(point) if stone is not None: status[point] = stone else: group, bordering_stones = _collect_region(point, board) if len(bordering_stones) == 1: border_stone = bordering_stones.pop() stone_str = 'b' if border_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 draw(cls, board): """Draw the board to the background and blit it to the screen. The board is drawn by first drawing the outline, then the 19x19 grid and finally by adding hoshi to the board. All these operations are done with pygame's draw functions. This method should only be called once, when initializing the board. """ """Create, initialize and draw an empty board.""" BOARD_SIZE = (board.num_rows * 45, board.num_cols * 45) screen = pygame.display.set_mode(BOARD_SIZE, 0, 32) background = pygame.image.load(BACKGROUND).convert() outline = pygame.Rect(40, 40, (board.num_rows - 1) * 40, (board.num_cols - 1) * 40) pygame.draw.rect(background, BLACK, outline, 3) # Outline is inflated here for future use as a collidebox for the mouse outline.inflate_ip(20, 20) for i in range(board.num_cols - 1): for j in range(board.num_rows - 1): rect = pygame.Rect(40 + (40 * i), 40 + (40 * j), 40, 40) pygame.draw.rect(background, BLACK, rect, 1) for i in range(1, board.num_rows + 1): for j in range(1, board.num_cols + 1): player = board.get(Point(i, j)) if player is not None: if player == Player.black: pygame.draw.circle(background, BLACK, ((40 * (j)), (40 * (board.num_cols - i + 1))), 15, 0) elif player == Player.white: pygame.draw.circle(background, WHITE, ((40 * (j)), (40 * (board.num_cols - i + 1))), 15, 0) screen.blit(background, (0, 0)) pygame.display.update()
def _collect_region(start_pos: Point, board: 'Board', visited=None): if visited == None: visited = {} if start_pos in visited: return [], set() visited[start_pos] = True all_points = [start_pos] all_borders = set() value_at_here = board.get(start_pos) deltas = [[-1, 0], [1, 0], [0, -1], [0, 1]] for delta_r, delta_c in deltas: next_point = Point(row=start_pos.row + delta_r, col=start_pos.col + delta_c) if not board.is_on_grid(next_point): continue neighbor_value = board.get(next_point) if value_at_here == neighbor_value: points, borders = _collect_region(next_point, board, visited) all_points += points all_borders |= borders else: all_borders.add(next_point) return all_points, all_borders
def get_stats(board): board_state = {} for row in range(1, board.num_rows + 1): for col in range(1, board.num_cols + 1): point = Point(row=row, col=col) if point in board_state: continue stone = board.get(point) if stone is not None: board_state[point] = stone else: group, unique_players = get_area(point, board) if len(unique_players) == 1: player_color = unique_players.pop() point_type = "b territory" if player_color == Player.black else "w territory" else: point_type = "neutral" for position in group: board_state[position] = point_type board_stats = BoardStats(board_state) return board_stats
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 Move(point)
def to_python(player_state): if player_state is None: return 'None' if player_state == Player.black: return Player.black return Player.white MAX63 = 0x7fffffffffffffff table = {} empty_board = 0 for row in range(1, 20): for col in range(1, 20): for state in (Player.black, Player.white): code = random.randint(0, MAX63) table[Point(row, col), state] = 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, )) # From a terminal call like this: # PYTHONPATH=./ python dlgo/hash_generator.py > dlgo/zobrist.py
def to_python(player_state): if player_state is None: return 'None' if player_state == Player.black: return Player.black return Player.white MAX63 = 0x7fffffffffffffff table = {} empty_board = 0 for row in range(1, 20): for col in range(1, 20): for state in (Player.black, Player.white): code = random.randint(0, MAX63) # generates hash table[Point(row, col), state] = code # stores hash in dictionary print('from dlgo.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, ))
def decode_move_index(self, index): if index == self.board_size * self.board_size: return Move.pass_turn() row = index // self.board_size col = index % self.board_size return Move.play(Point(row=row + 1, col=col + 1))
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_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)))
from dlgo.goboard import GameState, Move from dlgo.gotypes import Point from dlgo.utils import print_board from dlgo.gosgf.sgf import Sgf_game sgf_content = "(;GM[1]FF[4]SZ[9];B[ee];W[ef];B[ff];W[df];B[fe];W[fc];B[ec];W[gd];B[fb])" sgf_game = Sgf_game.from_string(sgf_content) game_state = GameState.new_game(19) for item in sgf_game.main_sequence_iter(): color, move_tuple = item.get_move() if color is not None and move_tuple is not None: row, col = move_tuple point = Point(row + 1, col + 1) move = Move.play(point) game_state = game_state.apply_move(move) print_board(game_state.board)