def test_new_game(self): start = GameState.new_game(19) next_state = start.apply_move(Move.play(Point(16, 16))) self.assertEqual(start, next_state.previous_state) self.assertEqual(Player.white, next_state.next_player) self.assertEqual(Player.black, next_state.board.get(Point(16, 16)))
def test_move_is_hashable(self): moves = { Move.play(Point(1, 1)): 1, Move.resign(): 2, } self.assertEqual(1, moves[Move.play(Point(1, 1))]) self.assertEqual(2, moves[Move.resign()])
def test_place_stone(self): board = Board(5, 5) self.assertIsNone(board.get(Point(2, 3))) self.assertIsNone(board.get(Point(3, 3))) board.place_stone(Player.black, Point(3, 3)) self.assertIsNone(board.get(Point(2, 3))) self.assertEqual(Player.black, board.get(Point(3, 3)))
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_string(Point(2, 2)) self.assertEqual(4, white_string.num_liberties) board.place_stone(Player.black, Point(3, 2)) white_string = board.get_string(Point(2, 2)) self.assertEqual(3, white_string.num_liberties)
def test_empty_triangle(self): board = Board(5, 5) board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(1, 2)) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.white, Point(2, 1)) black_string = board.get_string(Point(1, 1)) self.assertEqual(3, black_string.num_liberties)
def test_create_game_from_board(self): board = Board(5, 5) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.black, Point(4, 4)) game = GameState.from_board(board, Player.white) self.assertEqual(Player.white, game.next_player) self.assertFalse(game.is_valid_move(Move.play(Point(2, 2)))) self.assertTrue(game.is_valid_move(Move.play(Point(3, 3))))
def test_equality(self): board1 = Board(5, 5) board2 = Board(5, 5) board1.place_stone(Player.black, Point(3, 3)) self.assertNotEqual(board1, board2) board2.place_stone(Player.black, Point(3, 3)) self.assertEqual(board1, board2)
def test_white_stones_array(self): board = Board(5, 5) board.place_stone(Player.black, Point(2, 1)) board.place_stone(Player.white, Point(3, 2)) white_array = board.white_stones_as_array() self.assertEqual((5, 5), white_array.shape) self.assertEqual(1, white_array[2, 1]) self.assertEqual(0, white_array[1, 0]) self.assertEqual(0, white_array[3, 3])
def test_capture(self): board = Board(19, 19) board.place_stone(Player.black, Point(2, 2)) board.place_stone(Player.white, Point(1, 2)) self.assertEqual(Player.black, board.get(Point(2, 2))) board.place_stone(Player.white, Point(2, 1)) self.assertEqual(Player.black, board.get(Point(2, 2))) board.place_stone(Player.white, Point(2, 3)) self.assertEqual(Player.black, board.get(Point(2, 2))) board.place_stone(Player.white, Point(3, 2)) self.assertIsNone(board.get(Point(2, 2)))
def decode_move_index(self, index): """Turn an integer index into a board point.""" if index == self._pass_idx: 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 write_board(self, board): assert board.num_cols == board.num_rows self.write_int(board.num_rows) for r in range(1, board.num_rows + 1): for c in range(1, board.num_cols + 1): p = Point(r, c) self.write_optional(board.get(p), self.write_player)
def decode_sgf_move(sgf_move, num_rows): if sgf_move == '': return Move.pass_turn() assert len(sgf_move) == 2 col = ALPHABET.index(sgf_move[0]) + 1 row = num_rows - ALPHABET.index(sgf_move[1]) return Move.play(Point(row, col))
def test_min_liberties_array(self): # ..... # .x.o. # ..... # xo... # xox.. board = Board(5, 5) board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(2, 1)) board.place_stone(Player.black, Point(1, 3)) board.place_stone(Player.black, Point(4, 2)) board.place_stone(Player.white, Point(1, 2)) board.place_stone(Player.white, Point(2, 2)) board.place_stone(Player.white, Point(4, 4)) two_lib = board.stones_with_min_liberties_as_array(Player.black, 2) # np array indexing is upside-down compared to usual board # notation np.testing.assert_array_equal( np.array([ [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0], ]), two_lib) three_lib = board.stones_with_min_liberties_as_array(Player.white, 3) np.testing.assert_array_equal( np.array([ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 0], ]), three_lib)
def read_board(self): board_size = self.read_int() board = Board(board_size, board_size) for r in range(1, board.num_rows + 1): for c in range(1, board.num_cols + 1): p = Point(r, c) stone = self.read_optional(self.read_player) if stone is not None: board.place_stone(stone, p) return board
def read_move(self): is_play = self.read_bool() is_pass = self.read_bool() is_resign = self.read_bool() if is_play: row = self.read_int() col = self.read_int() return Move.play(Point(row=row, col=col)) if is_pass: return Move.pass_turn() assert is_resign return Move.resign()
def board_from_string(board_string): rows = board_string.strip().split("\n") assert len(rows) == len(rows[0]) dim = len(rows) board = Board(dim, dim) for r, row_str in enumerate(rows): row_str = row_str.strip() for c, stone in enumerate(row_str): int_row = dim - r point = Point(int_row, c + 1) if stone == 'x': board.place_stone(Player.black, point) elif stone == 'o': board.place_stone(Player.white, point) return board
def test_get_string(self): board = Board(5, 5) # .... # .o.. # xo.. # xxo. board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(1, 2)) board.place_stone(Player.black, Point(2, 1)) board.place_stone(Player.white, Point(1, 3)) board.place_stone(Player.white, Point(2, 2)) board.place_stone(Player.white, Point(3, 2)) black_string = board.get_string(Point(1, 1)) self.assertEqual(Player.black, black_string.color) self.assertEqual(1, black_string.num_liberties) white_string = board.get_string(Point(3, 2)) self.assertEqual(Player.white, white_string.color) self.assertEqual(4, white_string.num_liberties)
def __init__(self, board_size): """ Args: board_size (int) """ self._board_size = board_size self._pass_idx = self._board_size * self._board_size # 0. our player stones # 1. opponent stones # 2. move is illegal due to ko # 3. 1 if we get komi # 4. 1 if opponent gets komi self.num_planes = 5 self._points = [] for r in range(self._board_size): for c in range(self._board_size): self._points.append(Point(row=r + 1, col=c + 1))
def test_liberties_array(self): # Board position: # ..... # .x.o. # ..... # xo... # xox.. # 1/2 liberty points: # ..... # .x.o. # **... # xo*.. # xox*. board = Board(5, 5) board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(2, 1)) board.place_stone(Player.black, Point(1, 3)) board.place_stone(Player.black, Point(4, 2)) board.place_stone(Player.white, Point(1, 2)) board.place_stone(Player.white, Point(2, 2)) board.place_stone(Player.white, Point(4, 4)) b_one_lib = board.liberties_as_array(Player.black, 1) # np array indexing is upside-down compared to usual board # notation np.testing.assert_array_equal( np.array([ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ]), b_one_lib) w_two_lib = board.liberties_as_array(Player.white, 2) np.testing.assert_array_equal( np.array([ [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ]), w_two_lib)
def test_ko_as_array(self): start = GameState.new_game(19) # .wb. # wb.b # .wb. # .... game = start.apply_move(Move.play(Point(1, 3))) game = game.apply_move(Move.play(Point(1, 2))) game = game.apply_move(Move.play(Point(2, 2))) game = game.apply_move(Move.play(Point(2, 1))) game = game.apply_move(Move.play(Point(3, 3))) game = game.apply_move(Move.play(Point(3, 2))) game = game.apply_move(Move.play(Point(2, 4))) # W takes the ko game = game.apply_move(Move.play(Point(2, 3))) ko_array = game.ko_points_as_array() self.assertEqual((19, 19), ko_array.shape) self.assertEqual(1, ko_array[1, 1]) self.assertEqual(0, ko_array[2, 1]) self.assertEqual(0, ko_array[5, 5])
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_size): for c in range(self._board_size): p = Point(row=r + 1, col=c + 1) go_string = game_state.board.get_string(p) if go_string is None: if game_state.does_move_violate_ko(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 test_legal_move_mask(self): start = GameState.new_game(19) # .wb. # wb.b # .wb. # .... game = start.apply_move(Move.play(Point(1, 3))) game = game.apply_move(Move.play(Point(1, 2))) game = game.apply_move(Move.play(Point(2, 2))) game = game.apply_move(Move.play(Point(2, 1))) game = game.apply_move(Move.play(Point(3, 3))) game = game.apply_move(Move.play(Point(3, 2))) game = game.apply_move(Move.play(Point(2, 4))) # W takes the ko game = game.apply_move(Move.play(Point(2, 3))) legal_moves = game.legal_moves_as_array() self.assertEqual((19 * 19 + 1, ), legal_moves.shape) illegal_indices = [ # Suicide 19 * 0 + 0, # Stones here 19 * 0 + 2, 19 * 0 + 1, 19 * 1 + 0, 19 * 2 + 2, 19 * 2 + 1, 19 * 1 + 3, 19 * 1 + 2, # ko 19 * 1 + 1, ] for i, val in enumerate(legal_moves): if i in illegal_indices: self.assertEqual(0, val, "{} should be illegal".format(i)) else: self.assertEqual(1, val, "{} should be legal".format(i))
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 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 __init__(self, board_size): """ Args: board_size (int) """ self._board_size = board_size self._pass_idx = self._board_size * self._board_size # 0. our player stones with 1 liberty # 1. our stones with 2 liberties # 2. our stones with 3+ liberties # 3. opponent stones with 1 liberty # 4. opponent stones with 2 liberty # 5. opponent stones with 3+ liberty # 6. move is illegal due to ko # 7. 1 if we get komi # 8. 1 if opponent gets komi self.num_planes = 9 self._points = [] for r in range(self._board_size): for c in range(self._board_size): self._points.append(Point(row=r + 1, col=c + 1))
def test_print_board(self): board = Board(5, 5) # ..... # ..... # .o... # xo... # xxo.. board.place_stone(Player.black, Point(1, 1)) board.place_stone(Player.black, Point(1, 2)) board.place_stone(Player.black, Point(2, 1)) board.place_stone(Player.white, Point(1, 3)) board.place_stone(Player.white, Point(2, 2)) board.place_stone(Player.white, Point(3, 2)) buf = io.StringIO() print_board(board, outf=buf) lines = buf.getvalue().split('\n') self.assertEqual(lines[0].strip(), '5 .....') self.assertEqual(lines[1].strip(), '4 .....') self.assertEqual(lines[2].strip(), '3 .o...') self.assertEqual(lines[3].strip(), '2 xo...') self.assertEqual(lines[4].strip(), '1 xxo..') self.assertEqual(lines[5].strip(), 'ABCDE')
def test_komi(self): start = GameState.new_game(19, 0.5) next_state = start.apply_move(Move.play(Point(16, 16))) self.assertAlmostEqual(0.5, next_state.komi())
def test_ko(self): start = GameState.new_game(19) # .wb. # wb.b # .wb. # .... game = start.apply_move(Move.play(Point(1, 3))) game = game.apply_move(Move.play(Point(1, 2))) game = game.apply_move(Move.play(Point(2, 2))) game = game.apply_move(Move.play(Point(2, 1))) game = game.apply_move(Move.play(Point(3, 3))) game = game.apply_move(Move.play(Point(3, 2))) game = game.apply_move(Move.play(Point(2, 4))) # W takes the ko game = game.apply_move(Move.play(Point(2, 3))) # B can't take back self.assertTrue(game.does_move_violate_ko(Move.play(Point(2, 2)))) self.assertFalse(game.is_valid_move(Move.play(Point(2, 2)))) # "ko threat" game = game.apply_move(Move.play(Point(19, 19))) game = game.apply_move(Move.play(Point(18, 18))) # B can take now self.assertFalse(game.does_move_violate_ko(Move.play(Point(2, 2)))) self.assertTrue(game.is_valid_move(Move.play(Point(2, 2))))
def test_last_move(self): start = GameState.new_game(19) next_move = Move.play(Point(16, 16)) state = start.apply_move(next_move) self.assertEqual(Move.play(Point(16, 16)), state.last_move)
def test_move_number(self): start = GameState.new_game(19) self.assertEqual(0, start.num_moves) game = start.apply_move(Move.play(Point(1, 3))) game = game.apply_move(Move.play(Point(1, 2))) self.assertEqual(2, game.num_moves)