Пример #1
0
class LocalGameMoveActionsTest(unittest.TestCase):
    STARTING_WHITE_PAWN_CAPTURES = [
        Move(A2, B3),
        Move(B2, A3),
        Move(B2, C3),
        Move(C2, B3),
        Move(C2, D3),
        Move(D2, C3),
        Move(D2, E3),
        Move(E2, D3),
        Move(E2, F3),
        Move(F2, E3),
        Move(F2, G3),
        Move(G2, F3),
        Move(G2, H3),
        Move(H2, G3),
    ]
    BLACK_STARTING_PAWN_CAPTURES = [
        Move(A7, B6),
        Move(B7, A6),
        Move(B7, C6),
        Move(C7, B6),
        Move(C7, D6),
        Move(D7, C6),
        Move(D7, E6),
        Move(E7, D6),
        Move(E7, F6),
        Move(F7, E6),
        Move(F7, G6),
        Move(G7, F6),
        Move(G7, H6),
        Move(H7, G6),
    ]

    def setUp(self):
        self.game = LocalGame()

    def test_starting_pawn_capture_moves(self):
        move_actions = self.game.move_actions()
        for move in self.STARTING_WHITE_PAWN_CAPTURES:
            self.assertIn(move, move_actions)
        self.game.board.turn = BLACK
        move_actions = self.game.move_actions()
        for move in self.BLACK_STARTING_PAWN_CAPTURES:
            self.assertIn(move, move_actions)

    def test_pass(self):
        self.assertNotIn(None, self.game.move_actions())
        self.assertNotIn(Move.null(), self.game.move_actions())

    def test_superset_fuzz(self, max_turns=500):
        turn = 1
        while not self.game.board.is_game_over() and turn < max_turns:
            truth_moves = set(self.game.board.generate_pseudo_legal_moves())
            recon_moves = set(self.game.move_actions())
            self.assertTrue(recon_moves.issuperset(truth_moves))

            self.game.board.push(random.sample(truth_moves, 1)[0])
            turn += 1
Пример #2
0
def playback(game_history: GameHistory, player: Player, color: Color):
    game = LocalGame()

    opponent_name = game_history.get_white_player_name()
    if color == chess.WHITE:
        opponent_name = game_history.get_black_player_name()
    player.handle_game_start(color, game.board.copy(), opponent_name)
    game.start()

    turn = game_history.first_turn()

    while not game.is_over() and turn < game_history.last_turn():
        opt_capture_square = game.opponent_move_results()
        if game.turn == color:
            player.handle_opponent_move_result(opt_capture_square is not None,
                                               opt_capture_square)

        sense_actions = game.sense_actions()
        move_actions = game.move_actions()

        sense = game_history.sense(turn)
        player_sense = player.choose_sense(sense_actions, move_actions,
                                           game.get_seconds_left())
        if game.turn == color and sense != player_sense:
            print(
                'Warning: Sense action did not match history on turn {}. Using the sense action from history.'
                .format(turn))
        sense_result = game.sense(sense)
        if game.turn == color:
            player.handle_sense_result(sense_result)

        move = game_history.requested_move(turn)
        player_move = player.choose_move(move_actions, game.get_seconds_left())
        if game.turn == color and move != player_move:
            print(
                'Warning: Move action did not match history on turn {}. Using the move action from history.'
                .format(turn))
        requested_move, taken_move, opt_enemy_capture_square = game.move(move)
        if game.turn == color:
            player.handle_move_result(requested_move, taken_move,
                                      opt_enemy_capture_square is not None,
                                      opt_enemy_capture_square)

        game.end_turn()
        turn = turn.next

    game.end()
    winner_color = game.get_winner_color()
    win_reason = game.get_win_reason()
    game_history = game.get_game_history()

    player.handle_game_end(winner_color, win_reason, game_history)
Пример #3
0
class LocalGameMoveTest(unittest.TestCase):
    def setUp(self):
        self.game = LocalGame()

    def test_legal_kingside_castle(self):
        """
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        R . . . K . . R
        """
        self.game.board.set_board_fen('8/8/8/8/8/8/8/R3K2R')
        self.game.board.set_castling_fen('KQkq')
        req, taken, opt_capture = self.game.move(Move(E1, G1))
        self.assertEqual(req, taken)
        self.assertIsNone(opt_capture)
        self.assertEqual(self.game.board.board_fen(), '8/8/8/8/8/8/8/R4RK1')

    def test_legal_queenside_castle(self):
        """
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        R . . . K . . R
        """
        self.game.board.set_board_fen('8/8/8/8/8/8/8/R3K2R')
        self.game.board.set_castling_fen('KQkq')
        req, taken, opt_capture = self.game.move(Move(E1, C1))
        self.assertEqual(req, taken)
        self.assertIsNone(opt_capture)
        self.assertEqual(self.game.board.board_fen(), '8/8/8/8/8/8/8/2KR3R')

    def test_queenside_castle_piece_between(self):
        """
        r . P . k b n r     r . . P k b n r     r P . . k b n r
        p p . p p p p p     p p . p p p p p     p p . p p p p p
        . . . . . . . .     . . . . . . . .     . . . . . . . .
        . . . . . . . .     . . . . . . . .     . . . . . . . .
        . . . . . . . .     . . . . . . . .     . . . . . . . .
        . . . . . . . .     . . . . . . . .     . . . . . . . .
        P P . P P P P P     P P . P P P P P     P P . P P P P P
        R . p . K B N R     R . . p K B N R     R p . . K B N R
        """

        for fen in ['r1P1kbnr/pp1ppppp/8/8/8/8/PP1PPPPP/R1p1KBNR',
                    'r2Pkbnr/pp1ppppp/8/8/8/8/PP1PPPPP/R2pKBNR',
                    'rP2kbnr/pp1ppppp/8/8/8/8/PP1PPPPP/Rp2KBNR']:
            self.game.board.set_board_fen(fen)
            self.game.board.turn = WHITE
            self.game.turn = WHITE
            req, tak, opt_capture = self.game.move(Move(E1, C1))
            self.assertEqual(tak, None)

            self.game.board.turn = BLACK
            self.game.turn = BLACK
            req, tak, opt_capture = self.game.move(Move(E8, C8))
            self.assertEqual(tak, None)

    def test_kingside_castle_piece_between(self):
        """
        r n b q k P . r     r n b q k . P r
        p p p p p . p p     p p p p p . p p
        . . . . . . . .     . . . . . . . .
        . . . . . . . .     . . . . . . . .
        . . . . . . . .     . . . . . . . .
        . . . . . . . .     . . . . . . . .
        P P P P P . P P     P P P P P . P P
        R N B Q K p . R     R N B Q K . p R
        :return:
        """
        for fen in ['rnbqkP1r/ppppp1pp/8/8/8/8/PPPPP1PP/RNBQKp1R',
                    'rnbqk1Pr/ppppp1pp/8/8/8/8/PPPPP1PP/RNBQK1pR']:
            self.game.board.set_board_fen(fen)
            self.game.board.turn = WHITE
            self.game.turn = WHITE
            req, tak, opt_capture = self.game.move(Move(E1, G1))
            self.assertEqual(tak, None)

            self.game.board.turn = BLACK
            self.game.turn = BLACK
            req, tak, opt_capture = self.game.move(Move(E8, G8))
            self.assertEqual(tak, None)

    def test_queenside_castle_no_rights(self):
        """
        r . . . k . . r
        p p p p p p p p
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        P P P P P P P P
        R . . . K . . R
        """
        self.game.board.set_board_fen('r3k2r/pppppppp/8/8/8/8/PPPPPPPP/R3K2R')

        self.game.board.turn = WHITE
        self.game.turn = WHITE
        for castling_fen in ['-', 'k', 'q', 'kq', 'Kk', 'Kq', 'Kkq']:
            self.game.board.set_castling_fen(castling_fen)
            with self.assertRaises(ValueError):
                self.game.move(Move(E1, C1))

        self.game.board.turn = BLACK
        self.game.turn = BLACK
        for castling_fen in ['-', 'K', 'Q', 'KQ', 'Kk', 'Qk', 'KQk']:
            self.game.board.set_castling_fen(castling_fen)
            with self.assertRaises(ValueError):
                self.game.move(Move(E8, C8))

    def test_kingside_castle_no_rights(self):
        """
        r . . . k . . r
        p p p p p p p p
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        P P P P P P P P
        R . . . K . . R
        """
        self.game.board.set_board_fen('r3k2r/pppppppp/8/8/8/8/PPPPPPPP/R3K2R')

        self.game.board.turn = WHITE
        self.game.turn = WHITE
        for castling_fen in ['-', 'k', 'q', 'kq', 'Qk', 'Qq', 'Qkq']:
            self.game.board.set_castling_fen(castling_fen)
            with self.assertRaises(ValueError):
                self.game.move(Move(E1, G1))

        self.game.board.turn = BLACK
        self.game.turn = BLACK
        for castling_fen in ['-', 'K', 'Q', 'KQ', 'Kq', 'Qq', 'KQq']:
            self.game.board.set_castling_fen(castling_fen)
            with self.assertRaises(ValueError):
                self.game.move(Move(E8, G8))

    def test_castling_into_check(self):
        """
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . q .
        . . . . . . . .
        . . . . . . . .
        . . . . K . . R
        """
        self.game.board.set_board_fen('8/8/8/8/6q1/8/8/4K2R')
        self.assertFalse(self.game.board.is_check())
        move = Move(E1, G1)
        req, taken, opt_capture = self.game.move(move)
        self.assertEqual(req, taken)
        self.assertIsNone(opt_capture)
        self.game.board.turn = WHITE
        self.assertTrue(self.game.board.is_check())

    def test_castling_out_of_check(self):
        """
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        q . . . K . . R
        """
        self.game.board.set_board_fen('8/8/8/8/8/8/8/q3K2R')
        self.assertTrue(self.game.board.is_check())
        move = Move(E1, G1)
        req, taken, opt_capture = self.game.move(move)
        self.assertEqual(req, taken)
        self.assertIsNone(opt_capture)
        self.game.board.turn = WHITE
        self.assertFalse(self.game.board.is_check())

    def test_castling_stay_in_check(self):
        """
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . q .
        . . . . . . . .
        . . . . K . . R
        """
        self.game.board.set_board_fen('8/8/8/8/8/6q1/8/4K2R')
        self.assertTrue(self.game.board.is_check())
        move = Move(E1, G1)
        req, taken, opt_capture = self.game.move(move)
        self.assertEqual(req, taken)
        self.assertIsNone(opt_capture)
        self.game.board.turn = WHITE
        self.assertTrue(self.game.board.is_check())

    def test_en_passant_white(self):
        """
        r n b q k b n r
        p . p p p p p p
        . . . . . . . .
        . . . . . . . .
        P p . . . . . .
        . . . . . . . .
        . P P P P P P P
        R N B Q K B N R
        """
        # test that en passant captures result in the correct capture square
        self.game.board.set_board_fen('rnbqkbnr/p1pppppp/8/8/1p6/8/PPPPPPPP/RNBQKBNR')

        req, taken, opt_capture = self.game.move(Move(A2, A4))
        self.assertEqual(req, taken)
        self.assertIsNone(opt_capture)

        req, taken, opt_capture = self.game.move(Move(B4, A3))
        self.assertEqual(req, taken)
        self.assertIsNotNone(opt_capture)
        self.assertEqual(opt_capture, A4)

    def test_en_passant_black(self):
        """
        r n b q k b n r
        p p p p p . p p
        . . . . . . . .
        . . . . . p P .
        . . . . . . . .
        . . . . . . . .
        P P P P P P . P
        R N B Q K B N R
        """
        # test that en passant captures result in the correct capture square
        self.game.board.set_board_fen('rnbqkbnr/pppppppp/8/6P1/8/8/PPPPPP1P/RNBQKBNR')
        self.game.turn = BLACK
        self.game.board.turn = BLACK

        req, taken, opt_capture = self.game.move(Move(F7, F5))
        self.assertEqual(req, taken)
        self.assertIsNone(opt_capture)

        req, taken, opt_capture = self.game.move(Move(G5, F6))
        self.assertEqual(req, taken)
        self.assertIsNotNone(opt_capture)
        self.assertEqual(opt_capture, F5)

    def test_move_opponent_piece(self):
        # test moving opponent pieces
        b = Board()
        b.turn = BLACK

        for move in b.generate_pseudo_legal_moves():
            with self.assertRaises(ValueError):
                self.game.move(move)

    def test_move_no_piece(self):
        # test a move from a square with no piece
        for from_square in SquareSet(BB_RANK_3 | BB_RANK_4 | BB_RANK_5 | BB_RANK_6):
            for to_square in SQUARES:
                with self.assertRaises(ValueError):
                    m = Move(from_square, to_square)
                    self.game.move(m)

    def test_move_illegal(self):
        for from_square in SquareSet(BB_RANK_1 | BB_RANK_2):
            for to_square in SQUARES:
                move = Move(from_square, to_square)
                if move not in self.game.move_actions():
                    with self.assertRaises(ValueError):
                        self.game.move(move)

    def test_sliding_straight_capture(self):
        """
        . . . . . . . .
        . . . p . . . .
        . . . . . . . .
        . p . R . p . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        """

        result_by_move = {
            Move(D5, C5): (Move(D5, C5), None),
            Move(D5, B5): (Move(D5, B5), B5),
            Move(D5, A5): (Move(D5, B5), B5),
            Move(D5, D6): (Move(D5, D6), None),
            Move(D5, D7): (Move(D5, D7), D7),
            Move(D5, D8): (Move(D5, D7), D7),
            Move(D5, E5): (Move(D5, E5), None),
            Move(D5, F5): (Move(D5, F5), F5),
            Move(D5, G5): (Move(D5, F5), F5),
            Move(D5, H5): (Move(D5, F5), F5),
            Move(D5, D4): (Move(D5, D4), None),
            Move(D5, D3): (Move(D5, D3), None),
            Move(D5, D2): (Move(D5, D2), None),
            Move(D5, D1): (Move(D5, D1), None),
        }
        for expected_req, (expected_taken, expected_capture) in result_by_move.items():
            self.game.board.set_board_fen('8/3p4/8/1p1R1p2/8/8/8/8')
            self.game.board.turn = WHITE
            self.game.turn = WHITE
            req, taken, opt_capture = self.game.move(expected_req)
            self.assertEqual(req, expected_req)
            self.assertEqual(taken, expected_taken)
            self.assertEqual(opt_capture, expected_capture)

    def test_sliding_straight_into_ally(self):
        """
        . . . . . . . .
        . . . p . . . .
        . . . . . . . .
        . p . R . p . .
        . . . . . . . .
        . . . . . . . .
        . . . P . . . .
        . . . . . . . .
        """
        for move in [Move(D5, D2), Move(D5, D1)]:
            self.game.board.set_board_fen('8/3p4/8/1p1R1p2/8/8/3P4/8')
            self.game.board.turn = WHITE
            self.game.turn = WHITE
            with self.assertRaises(ValueError):
                req, taken, opt_capture = self.game.move(move)

    def test_sliding_diagonal_capture(self):
        """
        p . . . . . p .
        . . . . . . . .
        . . . . . . . .
        . . . X . . . .
        . . . . . . . .
        . . . . . . . .
        p . . . . . p .
        . . . . . . . .
        """
        result_by_move = {
            Move(D5, C6): (Move(D5, C6), None),
            Move(D5, B7): (Move(D5, B7), None),
            Move(D5, A8): (Move(D5, A8), A8),
            Move(D5, E6): (Move(D5, E6), None),
            Move(D5, F7): (Move(D5, F7), None),
            Move(D5, G8): (Move(D5, G8), G8),
            Move(D5, E4): (Move(D5, E4), None),
            Move(D5, F3): (Move(D5, F3), None),
            Move(D5, G2): (Move(D5, G2), G2),
            Move(D5, H1): (Move(D5, G2), G2),
            Move(D5, C4): (Move(D5, C4), None),
            Move(D5, B3): (Move(D5, B3), None),
            Move(D5, A2): (Move(D5, A2), A2),
        }

        for expected_req, (expected_taken, expected_capture) in result_by_move.items():
            self.game.board.set_board_fen('p5p1/8/8/3B4/8/8/p5p1/8')
            self.game.board.turn = WHITE
            self.game.turn = WHITE
            req, taken, opt_capture = self.game.move(expected_req)
            self.assertEqual(req, expected_req)
            self.assertEqual(taken, expected_taken)
            self.assertEqual(opt_capture, expected_capture)

    def test_sliding_diagonal_into_ally(self):
        """
        p . . . . . p .
        . . . . . . . .
        . . . . . . . .
        . . . X . . . .
        . . . . . . . .
        . . . . . . . .
        p . . . . . P .
        . . . . . . . .
        """
        for move in [Move(D5, G2), Move(D5, H1)]:
            self.game.board.set_board_fen('p5p1/8/8/3B4/8/8/p5P1/8')
            self.game.board.turn = WHITE
            self.game.turn = WHITE
            with self.assertRaises(ValueError):
                req, taken, opt_capture = self.game.move(move)

    def test_pawn_auto_promotion(self):
        """
        . . . . . . . .
        . . . P . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        . . . . . . . .
        """
        self.game.board.set_board_fen('8/3P4/8/8/8/8/8/8')
        req, taken, opt_capture = self.game.move(Move(D7, D8))
        self.assertEqual(Move(D7, D8), req)
        self.assertNotEqual(req, taken)
        self.assertEqual(req.to_square, taken.to_square)
        self.assertEqual(req.from_square, taken.from_square)
        self.assertIsNone(req.promotion)
        self.assertEqual(taken.promotion, QUEEN)

    def test_pass(self):
        req, taken, opt_capture = self.game.move(None)
        self.assertEqual(req, None)
        self.assertEqual(taken, None)
        self.assertIsNone(opt_capture)

        self.game.board.turn = BLACK
        req, taken, opt_capture = self.game.move(None)
        self.assertEqual(req, None)
        self.assertEqual(taken, None)
        self.assertIsNone(opt_capture)

        self.game.board.turn = WHITE
        self.game.board.remove_piece_at(0)
        req, taken, opt_capture = self.game.move(None)
        self.assertEqual(req, None)
        self.assertEqual(taken, None)
        self.assertIsNone(opt_capture)

    def test_legal_fuzz(self, max_turns=500):
        board = Board()

        turn = 1
        while not board.is_game_over() and turn < max_turns:
            move = random.choice(list(board.generate_pseudo_legal_moves()) + [None])

            req, taken, opt_square = self.game.move(move)
            self.assertEqual(req, taken)
            if move is not None and board.is_capture(move):
                self.assertIsNotNone(opt_square)

            board.push(move if move is not None else Move.null())
            self.assertEqual(self.game.board, board)

            turn += 1