Beispiel #1
0
    def test_moving_the_king_should_disallow_any_further_castling(self):
        with self.subTest('white'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                'R...K..R'  # 1
                # bcdefgh
            ])
            white_king = board[Rank.ONE][File.E]
            moves = white_king.generate_moves(board, P('e1'))
            self.assertIn(P('c1'), moves)
            self.assertIn(P('g1'), moves)

            # move the king and then return it in it's original position
            board.move(from_pos=P('e1'), to_pos=P('f1'))
            board.move(from_pos=P('f1'), to_pos=P('e1'))

            moves = white_king.generate_moves(board, P('e1'))
            self.assertNotIn(P('c1'), moves)
            self.assertNotIn(P('g1'), moves)

        with self.subTest('black'):
            board = Board.from_strings([
                # bcdefgh
                'r...k..r',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                '........'  # 1
                # bcdefgh
            ])
            black_king = board[Rank.EIGHT][File.E]
            moves = black_king.generate_moves(board, P('e8'))
            self.assertIn(P('c8'), moves)
            self.assertIn(P('g8'), moves)

            board.move(from_pos=P('e8'), to_pos=P('f8'))
            board.move(from_pos=P('f8'), to_pos=P('e8'))

            moves = black_king.generate_moves(board, P('e8'))
            self.assertNotIn(P('c8'), moves)
            self.assertNotIn(P('g8'), moves)
 def test_double_check_no_other_pieces_other_than_king_should_move(self):
     for figure, figure_name in (
         ('q', 'queen'),
         ('n', 'knight'),
         ('b', 'bishop'),
         ('p', 'pawn'),
         ('r', 'rook'),
     ):
         test_case = {
             'name':
             f'{figure_name}_is_blocking_double_check_and_should_not_be_able_to_move',
             'board':
             Board.from_strings(
                 os.linesep.join([
                     # bcdefgh
                     '....q...',  # 8
                     '.q......',  # 7
                     '..X.....',  # 6
                     '.K......',  # 5
                     '.......Q',  # 4
                     '....Q...',  # 3
                     '.....x..',  # 2
                     '....k...'  # 1
                 ]).replace('x', figure).replace('X', figure.upper()).split(
                     os.linesep)),
             'want': {
                 'white': {
                     P('c6'): {}
                 },
                 'black': {
                     P('f2'): {}
                 }
             }
         }
         self.runMoveGenerationTest(test_case)
Beispiel #3
0
    def test_get_attackers_detects_king_attacks(self):
        """The placement of this test must seem off
            The bulk of the use cases are get_attackers are
            tested inderectly in the check awareness tests

            The only use case that cannot be tested with check awareness
            is when the king attacks something
        """
        board = Board.from_strings([
            # bcdefgh
            "p.......",  # 8 
            "K.......",  # 7 
            "........",  # 6 
            "........",  # 5 
            "........",  # 4 
            "........",  # 3 
            "k.......",  # 2 
            "P......."  # 1
        ])

        with self.subTest('white pawn attacked'):
            attackers = board.get_attackers(P('a1'), Color.WHITE)
            self.assertEqual([P('a2')], list(attackers))

        with self.subTest('black pawn attacked'):
            attackers = board.get_attackers(P('a8'), Color.BLACK)
            self.assertEqual([P('a7')], list(attackers))
Beispiel #4
0
    def test_en_passant_square_is_set_on_the_board_object(self):
        board = Board.from_strings([
            # bcdefgh
            '........',  # 8
            '.p......',  # 7
            '........',  # 6
            '........',  # 5
            '........',  # 4
            '........',  # 3
            '.P......',  # 2
            '........'  # 1
        ])

        with self.subTest('white'):
            en_passant_want = Position(Rank.THREE, File.B)
            f, t = Position(Rank.TWO, File.B), Position(Rank.FOUR, File.B)
            board.move(from_pos=f, to_pos=t)

            self.assertEqual(board.en_passant_pos, en_passant_want)

        with self.subTest('black'):
            en_passant_want = Position(Rank.SIX, File.B)
            f, t = Position(Rank.SEVEN, File.B), Position(Rank.FIVE, File.B)
            board.move(from_pos=f, to_pos=t)

            self.assertEqual(board.en_passant_pos, en_passant_want)
Beispiel #5
0
    def test_promotion_callback_should_be_called(self):
        board = Board.from_strings([
            # bcdefgh
            '........',  # 8
            '.P......',  # 7
            '........',  # 6
            '........',  # 5
            '........',  # 4
            '........',  # 3
            '.p......',  # 2
            '........'  # 1
        ])
        board.promotion_cb = unittest.mock.Mock()
        mock_piece = board.promotion_cb.return_value

        with self.subTest('white'):
            f, t = Position(Rank.SEVEN, File.B), Position(Rank.EIGHT, File.B)

            board.move(from_pos=f, to_pos=t)

            board.promotion_cb.assert_called_once()
            mock_piece.assert_called_once_with(Color.WHITE)

        board.promotion_cb.reset_mock()
        mock_piece = board.promotion_cb.return_value
        with self.subTest('black'):
            f, t = Position(Rank.TWO, File.B), Position(Rank.ONE, File.B)

            board.move(from_pos=f, to_pos=t)

            board.promotion_cb.assert_called_once()
            mock_piece.assert_called_once_with(Color.BLACK)
Beispiel #6
0
    def test_en_passant_is_unavailable_after_making_another_move(self):
        with self.subTest('white'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '..p.....',  # 7
                '........',  # 6
                '...P....',  # 5
                '........',  # 4
                '........',  # 3
                '....P...',  # 2
                '........'  # 1
                # bcdefgh
            ])
            board.move(from_pos=P('c7'), to_pos=P('c5'))
            self.assertIsInstance(board[Rank.FIVE][File.D], Pawn)
            white_pawn = board[Rank.FIVE][File.D]

            self.assertIn(P('c6'), white_pawn.generate_moves(board, P('d5')))
            board.move(from_pos=P('e2'), to_pos=P('e3'))
            self.assertNotIn(P('c6'),
                             white_pawn.generate_moves(board, P('d5')))

        with self.subTest('black'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '...p....',  # 7
                '........',  # 6
                '........',  # 5
                '..p.....',  # 4
                '........',  # 3
                '...P....',  # 2
                '........'  # 1
                # bcdefgh
            ])
            board.move(from_pos=P('d2'), to_pos=P('d4'))
            self.assertIsInstance(board[Rank.FOUR][File.C], Pawn)
            black_pawn = board[Rank.FOUR][File.C]

            self.assertIn(P('d3'), black_pawn.generate_moves(board, P('c4')))
            board.move(from_pos=P('d7'), to_pos=P('d6'))
            self.assertNotIn(P('d3'),
                             black_pawn.generate_moves(board, P('c4')))
    def test_when_king_is_in_check_he_should_be_aware_of_his_own_position(
            self):
        test_table = [
            *self.all_board_rotations_of({
                'comment':
                '''
                    when a possible position is evaluated, the code should not consider
                    it's old position as a blocker of an attacker

                    In this situation:

                              v
                    a b c d e f g h
                    1 . Q . k . . . . 1

                    F1(marked with `v`) should not be a valid move
                ''',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'R..k....',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    'r..K....'  # 1
                ]),
                'want': {
                    'white': {
                        'assert': self.assertNotIn,
                        Position(Rank.ONE, File.D): Position(Rank.ONE, File.E),
                    },
                    'black': {
                        'assert': self.assertNotIn,
                        Position(Rank.EIGHT, File.D): Position(
                            Rank.EIGHT, File.E),
                    },
                },
                'name':
                '',
            }),
        ]

        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #8
0
    def test_board_constructor_works_for_rooks(self):
        board = Board.from_strings([
            # bcdefgh
            '........',  # 8
            '.r......',  # 7
            '........',  # 6
            '........',  # 5
            '........',  # 4
            '........',  # 3
            '.R......',  # 2
            '........'  # 1
        ])
        self.assertEqual(board[Rank.TWO][File.B].type, Type.ROOK)
        self.assertEqual(board[Rank.TWO][File.B].color, Color.WHITE)

        self.assertEqual(board[Rank.SEVEN][File.B].type, Type.ROOK)
        self.assertEqual(board[Rank.SEVEN][File.B].color, Color.BLACK)
Beispiel #9
0
    def test_board_constructor_works_for_queen(self):
        board = Board.from_strings([
            # bcdefgh
            '........',  # 8
            '.q......',  # 7
            '........',  # 6
            '........',  # 5
            '........',  # 4
            '........',  # 3
            '.Q......',  # 2
            '........'  # 1
        ])

        self.assertEqual(board[Rank.TWO][File.B].figure_type, Type.QUEEN)
        self.assertEqual(board[Rank.TWO][File.B].color, Color.WHITE)

        self.assertEqual(board[Rank.SEVEN][File.B].figure_type, Type.QUEEN)
        self.assertEqual(board[Rank.SEVEN][File.B].color, Color.BLACK)
    def test_king_should_not_be_able_to_step_on_attacked_square(self):
        test_table = [
            *self.all_board_rotations_of({
                'name':
                'should_not_be_able_to_step_on_attacked_squares',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '...k....',  # 8
                    'R.......',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    'r.......',  # 2
                    '...K....'  # 1
                ]),
                'want': {
                    'white': {
                        Position(Rank.ONE, File.D): {
                            Position(Rank.TWO, File.C),
                            Position(Rank.TWO, File.D),
                            Position(Rank.TWO, File.E),
                        },
                        'assert':
                        lambda want, actual, **_:
                        [self.assertNotIn(p, actual) for p in want]
                    },
                    'black': {
                        Position(Rank.EIGHT, File.D): {
                            Position(Rank.SEVEN, File.C),
                            Position(Rank.SEVEN, File.D),
                            Position(Rank.SEVEN, File.E),
                        },
                        'assert':
                        lambda want, actual, **_:
                        [self.assertNotIn(p, actual) for p in want]
                    },
                }
            })
        ]

        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #11
0
    def test_last_rank_should_be_with_changed_piece_type(self):
        board = Board.from_strings([
            # bcdefgh
            '........',  # 8
            '.P......',  # 7
            '........',  # 6
            '........',  # 5
            '........',  # 4
            '........',  # 3
            '........',  # 2
            '........'  # 1
        ])

        f, t = Position(Rank.SEVEN, File.B), Position(Rank.EIGHT, File.B)
        board.promotion_cb = unittest.mock.Mock()
        piece_cls_mock = board.promotion_cb.return_value

        board.move(from_pos=f, to_pos=t)
        self.assertEqual(board[t.rank][t.file], piece_cls_mock.return_value)
Beispiel #12
0
    def test_move_generation(self):
        test_table = [
            {
                'name':
                'friendly_on_diagonals_should_not_be_capturable',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'b.b.....',  # 8
                    '.b......',  # 7
                    'b.b.....',  # 6
                    '........',  # 5
                    '........',  # 4
                    'B.B.....',  # 3
                    '.B......',  # 2
                    'B.B.....'  # 1
                ]),
                'want': {
                    'white': {
                        Position(Rank.TWO, File.B): {}
                    },
                    'black': {
                        Position(Rank.TWO, File.B): {}
                    },
                }
            },
            {
                'name':
                'enemies_on_diagonals_should_be_capturable',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '..B...B.',  # 8
                    '........',  # 7
                    '....b...',  # 6
                    'b...b...',  # 5
                    '..B...B.',  # 4
                    '..B.....',  # 3
                    '........',  # 2
                    'b...b...'  # 1
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        '........',  # 8
                        '........',  # 7
                        '........',  # 6
                        'X...X...',  # 5
                        '.x.x....',  # 4
                        '..T.....',  # 3
                        '.x.x....',  # 2
                        'X...X...'  # 1
                    ]),
                    'black':
                    target_board([
                        # bcdefgh
                        '..X...X.',  # 8
                        '...x.x..',  # 7
                        '....T...',  # 6
                        '...x.x..',  # 5
                        '..X...X.',  # 4
                        '........',  # 3
                        '........',  # 2
                        '........'  # 1
                    ])
                }
            },
            {
                'name':
                'should_not_be_able_to_go_over_pieces',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '........',  # 8
                    '........',  # 7
                    '........',  # 6
                    '...bB...',  # 5
                    '........',  # 4
                    '..b..B..',  # 3
                    '........',  # 2
                    'B......b'  # 1
                ]),
                'want': {
                    'white': {
                        Position(Rank.ONE, File.A): {
                            (+1, +1),
                            (+2, +2),  # up right
                        }
                    },
                    'black': {
                        Position(Rank.ONE, File.H): {
                            (+1, -1),
                            (+2, -2),  # up left diagonal
                        }
                    }
                }
            },
        ]

        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #13
0
    def test_pawn_en_passant_legal_scenarios(self):
        test_table = [
            {
                # white captures
                'name':
                'en_passant_square_is_legal_move',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '........',  # 8
                    '.p......',  # 7
                    '........',  # 6
                    'P.P.....',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    '........'  # 1
                ]),
                'move_before': {
                    'from': P('b7'),
                    'to': P('b5')
                },
                'want': {
                    'white': {
                        # given: {want...}
                        P('c5'): {P('c6'), P('b6')},
                        P('a5'): {P('a6'), P('b6')}
                    }
                }
            },
            {
                # black captures
                'name':
                'en_passant_position_is_in_legal_moves',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '........',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    'p.p.....',  # 4
                    '........',  # 3
                    '.P......',  # 2
                    '........'  # 1
                ]),
                'move_before': {
                    'from': P('b2'),
                    'to': P('b4')
                },
                'want': {
                    'black': {
                        P('c4'): {P('c3'), P('b3')},
                        P('a4'): {P('a3'), P('b3')}
                    }
                }
            }
        ]

        for test_case in test_table:
            board = test_case['board']
            f, t = test_case['move_before']['from'], test_case['move_before'][
                'to']
            board.move(from_pos=f, to_pos=t)

            self.assertEqual(board[t.rank][t.file].figure_type, Type.PAWN)
            self.runMoveGenerationTest(test_case)
Beispiel #14
0
    def test_move_generation(self):
        test_table = [
            *self.all_board_rotations_of({
                'name':
                'friendly_on_diagonals_should_not_be_capturable',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '....q..q',  # 8
                    '........',  # 7
                    '........',  # 6
                    '....q..q',  # 5
                    'Q..Q....',  # 4
                    '........',  # 3
                    '........',  # 2
                    'Q..Q....'  # 1
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        '........',  # 8
                        '........',  # 7
                        '........',  # 6
                        '........',  # 5
                        'Q..Q....',  # 4
                        'x.x.....',  # 3
                        'xx......',  # 2
                        'TxxQ....'  # 1
                        # bcdefgh
                    ]),
                    'black':
                    target_board([
                        # bcdefgh
                        '....qxxT',  # 8
                        '......xx',  # 7
                        '.....x.x',  # 6
                        '....q..q',  # 5
                        '........',  # 4
                        '........',  # 3
                        '........',  # 2
                        '........'  # 1
                        # bcdefgh
                    ]),
                }
            }),
            *self.all_board_rotations_of({
                'name':
                'should_go_no_further_than_the_enemy',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '....Q..q',  # 8
                    '........',  # 7
                    '........',  # 6
                    '....Q..Q',  # 5
                    'q..q....',  # 4
                    '........',  # 3
                    '........',  # 2
                    'Q..q....'  # 1
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        '........',  # 8
                        '........',  # 7
                        '........',  # 6
                        '........',  # 5
                        'x..x....',  # 4
                        'x.x.....',  # 3
                        'xx......',  # 2
                        'Txxx....'  # 1
                        # bcdefgh
                    ]),
                    'black':
                    target_board([
                        # bcdefgh
                        '....xxxT',  # 8
                        '......xx',  # 7
                        '.....x.x',  # 6
                        '....x..x',  # 5
                        '........',  # 4
                        '........',  # 3
                        '........',  # 2
                        '........'  # 1
                        # bcdefgh
                    ]),
                }
            }),
            {
                'name':
                'clear_board_all_positions',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '.......K',  # 8
                    '........',  # 7
                    '........',  # 6
                    '...Q....',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    '........'  # 1
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        'x..x..x.',  # 8
                        '.x.x.x..',  # 7
                        '..xxx...',  # 6
                        'xxxTxxxx',  # 5
                        '..xxx...',  # 4
                        '.x.x.x..',  # 3
                        'x..x..x.',  # 2
                        '...x...x'  # 1
                    ]),
                }
            },
            {
                'name':
                'clear_board_all_positions',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '........',  # 8
                    '........',  # 7
                    '........',  # 6
                    '...q....',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    '........'  # 1
                ]),
                'want': {
                    'black':
                    target_board([
                        # bcdefgh
                        'x..x..x.',  # 8
                        '.x.x.x..',  # 7
                        '..xxx...',  # 6
                        'xxxTxxxx',  # 5
                        '..xxx...',  # 4
                        '.x.x.x..',  # 3
                        'x..x..x.',  # 2
                        '...x...x'  # 1
                    ]),
                }
            },
        ]

        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #15
0
    def test_en_passant_should_capture_opposing_pawn(self):
        with self.subTest('black_captures_left'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '..p.....',  # 4
                '........',  # 3
                '.P......',  # 2
                '........'  # 1
                # bcdefgh
            ])
            board.move(from_pos=P('b2'), to_pos=P('b4'))
            self.assertIsInstance(board[Rank.FOUR][File.C], Pawn)
            black_pawn = board[Rank.FOUR][File.C]

            self.assertIn(P('b3'), black_pawn.generate_moves(board, P('c4')))

            self.assertIsInstance(board[Rank.FOUR][File.B], Pawn)
            board.move(from_pos=P('c4'), to_pos=P('b3'))
            self.assertIsNone(board[Rank.FOUR][File.B])

        with self.subTest('white_captures_left'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '..p.....',  # 7
                '........',  # 6
                '.P......',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                '........'  # 1
            ])
            board.move(from_pos=P('c7'), to_pos=P('c5'))
            self.assertIsInstance(board[Rank.FIVE][File.B], Pawn)
            white_pawn = board[Rank.FIVE][File.B]

            self.assertIn(P('c6'), white_pawn.generate_moves(board, P('b5')))
            board.move(from_pos=P('b5'), to_pos=P('c6'))
            self.assertIsNone(board[Rank.FIVE][File.C])

        with self.subTest('black_captures_right'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '..p.....',  # 4
                '........',  # 3
                '...P....',  # 2
                '........'  # 1
                # bcdefgh
            ])
            board.move(from_pos=P('d2'), to_pos=P('d4'))
            self.assertIsInstance(board[Rank.FOUR][File.C], Pawn)
            black_pawn = board[Rank.FOUR][File.C]

            self.assertIn(P('d3'), black_pawn.generate_moves(board, P('c4')))
            self.assertIsInstance(board[Rank.FOUR][File.D], Pawn)
            board.move(from_pos=P('c4'), to_pos=P('d3'))
            self.assertIsNone(board[Rank.FOUR][File.D])

        with self.subTest('white_captures_right'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '..p.....',  # 7
                '........',  # 6
                '...P....',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                '........'  # 1
            ])
            board.move(from_pos=P('c7'), to_pos=P('c5'))
            self.assertIsInstance(board[Rank.FIVE][File.D], Pawn)
            white_pawn = board[Rank.FIVE][File.D]

            self.assertIn(P('c6'), white_pawn.generate_moves(board, P('d5')))
            board.move(from_pos=P('d5'), to_pos=P('c6'))
            self.assertIsNone(board[Rank.FIVE][File.C])
Beispiel #16
0
    def test_castling_scenarios(self):
        test_table = [
            {
                'name':
                'should_be_able_to_castle_both_sides',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'r...k..r',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    'R...K..R'  # 1
                ]),
                'want': {
                    'white_queen_side': {
                        'assert': self.assertIn,
                        P('e1'): P('c1'),
                    },
                    'white_king_side': {
                        'assert': self.assertIn,
                        P('e1'): P('g1'),
                    },
                    'black_queen_side': {
                        'assert': self.assertIn,
                        P('e8'): P('c8'),
                    },
                    'black_king_side': {
                        'assert': self.assertIn,
                        P('e8'): P('g8'),
                    }
                }
            },
            {
                'name':
                'should_be_able_to_castle_queen_side',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'r...k...',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    'R...K...'  # 1
                ]),
                'want': {
                    'white': {
                        'assert': self.assertIn,
                        P('e1'): P('c1'),
                    },
                    'black': {
                        'assert': self.assertIn,
                        P('e8'): P('c8'),
                    },
                }
            },
            {
                'name':
                'should_be_able_to_castle_king_side',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '....k..r',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    '....K..R'  # 1
                ]),
                'want': {
                    'white': {
                        'assert': self.assertIn,
                        P('e1'): P('g1'),
                    },
                    'black': {
                        'assert': self.assertIn,
                        P('e8'): P('g8'),
                    },
                }
            },
            {
                'name':
                'standard_configuration_should_not_be_able_to_castle_because_of_blockers',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'rnbqkbnr',  # 8
                    'pppppppp',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    'PPPPPPPP',  # 2
                    'RNBQKBNR'  # 1
                ]),
                'want': {
                    'white': {
                        P('e1'): {}
                    },
                    'black': {
                        P('e8'): {}
                    },
                }
            },
            {
                'name':
                'should_not_castle_if_file_is_blocked_by_friendly',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'rn..k.nr',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    'RN..K.NR'  # 1
                ]),
                'want': {
                    'white_queen_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('c1'),
                    },
                    'white_king_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('g1'),
                    },
                    'black_queen_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('c8'),
                    },
                    'black_king_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('g8'),
                    }
                }
            },
            {
                'name':
                'should_not_be_able_to_castle_if_king_is_in_check',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'r...k..r',  # 8
                    '........',  # 7
                    '....R...',  # 6
                    '........',  # 5
                    '........',  # 4
                    '....r...',  # 3
                    '........',  # 2
                    'R...K..R'  # 1
                ]),
                'want': {
                    'white_queen_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('c1'),
                    },
                    'white_king_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('g1'),
                    },
                    'black_queen_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('c8'),
                    },
                    'black_king_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('g8'),
                    }
                }
            },
            {
                'name':
                'should_not_be_able_to_castle_if_king_will_be_in_check_if_he_castles',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'r...k..r',  # 8
                    '........',  # 7
                    '..R...R.',  # 6
                    '........',  # 5
                    '........',  # 4
                    '..r...r.',  # 3
                    '........',  # 2
                    'R...K..R'  # 1
                ]),
                'want': {
                    'white_queen_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('c1'),
                    },
                    'white_king_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('g1'),
                    },
                    'black_queen_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('c8'),
                    },
                    'black_king_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('g8'),
                    }
                }
            },
            {
                'name':
                'should_not_be_able_to_castle_if_last_files_are_not_rooks',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'b...k..b',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    'B...K..B'  # 1
                ]),
                'want': {
                    'white_queen_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('c1'),
                    },
                    'white_king_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('g1'),
                    },
                    'black_queen_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('c8'),
                    },
                    'black_king_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('g8'),
                    }
                }
            },
            {
                'name':
                'should_not_be_able_to_castle_if_the_king_passes_through_a_check',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'b...k..b',  # 8
                    '........',  # 7
                    '...R.R..',  # 6
                    '........',  # 5
                    '........',  # 4
                    '...r.r..',  # 3
                    '........',  # 2
                    'B...K..B'  # 1
                ]),
                'want': {
                    'white_queen_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('c1'),
                    },
                    'white_king_side': {
                        'assert': self.assertNotIn,
                        P('e1'): P('g1'),
                    },
                    'black_queen_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('c8'),
                    },
                    'black_king_side': {
                        'assert': self.assertNotIn,
                        P('e8'): P('g8'),
                    }
                }
            },
        ]

        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #17
0
    def test_moving_rooks_should_disallow_future_castling_only_on_that_side(
            self):
        with self.subTest('white queen side'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                'R...K..R'  # 1
                # bcdefgh
            ])
            white_king = board[Rank.ONE][File.E]

            moves = white_king.generate_moves(board, P('e1'))
            self.assertIn(P('c1'), moves)
            self.assertIn(P('g1'), moves)

            # move the rook and then return it in it's original position
            board.move(from_pos=P('h1'), to_pos=P('g1'))
            board.move(from_pos=P('g1'), to_pos=P('h1'))

            moves = white_king.generate_moves(board, P('e1'))
            self.assertNotIn(P('g1'), moves)
            self.assertIn(P('c1'), moves)

        with self.subTest('white king side'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                'R...K..R'  # 1
                # bcdefgh
            ])
            white_king = board[Rank.ONE][File.E]
            moves = white_king.generate_moves(board, P('e1'))
            self.assertIn(P('g1'), moves)
            self.assertIn(P('c1'), moves)

            # move the right rook and then return it in it's original position
            board.move(from_pos=P('a1'), to_pos=P('b1'))
            board.move(from_pos=P('b1'), to_pos=P('a1'))

            moves = white_king.generate_moves(board, P('e1'))
            self.assertNotIn(P('c1'), moves)
            self.assertIn(P('g1'), moves)

        with self.subTest('black queen side'):
            board = Board.from_strings([
                # bcdefgh
                'r...k..r',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                '........'  # 1
                # bcdefgh
            ])
            white_king = board[Rank.EIGHT][File.E]
            moves = white_king.generate_moves(board, P('e8'))
            self.assertIn(P('c8'), moves)

            # move the rook and then return it in it's original position
            board.move(from_pos=P('a8'), to_pos=P('b8'))
            board.move(from_pos=P('b8'), to_pos=P('a8'))

            moves = white_king.generate_moves(board, P('e8'))
            self.assertNotIn(P('c8'), moves)
            self.assertIn(P('g8'), moves)

        with self.subTest('black king side'):
            board = Board.from_strings([
                # bcdefgh
                'r...k..r',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                '........'  # 1
                # bcdefgh
            ])
            white_king = board[Rank.EIGHT][File.E]
            moves = white_king.generate_moves(board, P('e8'))
            self.assertIn(P('g8'), moves)
            self.assertIn(P('c8'), moves)

            # move the rook and then return it in it's original position
            board.move(from_pos=P('h8'), to_pos=P('g8'))
            board.move(from_pos=P('g8'), to_pos=P('h8'))

            moves = white_king.generate_moves(board, P('e8'))
            self.assertNotIn(P('g8'), moves)
            self.assertIn(P('c8'), moves)
Beispiel #18
0
    def test_knight_move_geneneration(self):
        test_table = [
            {
                'name': 'clear_board_should_have_all_surrounding_positions_white',
                'board': Board.from_strings([
                    # bcdefgh
                    '........',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '....N...',  # 4
                    '........',  # 3
                    '........',  # 2
                    '........'   # 1
                ]),
                'want': {
                    'white': target_board([
                        # bcdefgh
                        '........',  # 8
                        '........',  # 7
                        '...x.x..',  # 6
                        '..x...x.',  # 5
                        '....T...',  # 4
                        '..x...x.',  # 3
                        '...x.x..',  # 2
                        '........'   # 1
                    ]),
                },
            },
            {
                'name': 'clear_board_should_have_all_surrounding_positions_black',
                'board': Board.from_strings([
                    # bcdefgh
                    '........',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '....n...',  # 4
                    '........',  # 3
                    '........',  # 2
                    '........'   # 1
                ]),
                'want': {
                    'white': target_board([
                        # bcdefgh
                        '........',  # 8
                        '........',  # 7
                        '...x.x..',  # 6
                        '..x...x.',  # 5
                        '....T...',  # 4
                        '..x...x.',  # 3
                        '...x.x..',  # 2
                        '........'   # 1
                    ]),
                },
            },
            *self.all_board_rotations_of({
                'name': 'should_be_bounds_aware',
                'board': Board.from_strings([
                    # bcdefgh
                    '.......N',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    'n.......'   # 1
                ]),
                'want': {
                    'white': target_board([
                        # bcdefgh
                        '.......T',  # 8
                        '.....x..',  # 7
                        '......x.',  # 6
                        '........',  # 5
                        '........',  # 4
                        '........',  # 3
                        '........',  # 2
                        'n.......'   # 1
                    ]),
                    'black': target_board([
                        # bcdefgh
                        '.......N',  # 8
                        '........',  # 7
                        '........',  # 6
                        '........',  # 5
                        '........',  # 4
                        '.x......',  # 3
                        '..x.....',  # 2
                        'T.......'   # 1
                    ]),
                },
            }),
            *self.all_board_rotations_of({
                'name': 'should_not_be_able_to_capture_friendlies',
                'board': Board.from_strings([
                    # bcdefgh
                    '.......N',  # 8
                    '.....N..',  # 7
                    '......N.',  # 6
                    '........',  # 5
                    '........',  # 4
                    '.n......',  # 3
                    '..n.....',  # 2
                    'n.......'   # 1
                ]),
                'want': {
                    'white': target_board([
                        # bcdefgh
                        '.......T',  # 8
                        '........',  # 7
                        '........',  # 6
                        '........',  # 5
                        '........',  # 4
                        '........',  # 3
                        '........',  # 2
                        'n.......'   # 1
                    ]),
                    'black': target_board([
                        # bcdefgh
                        '.......N',  # 8
                        '........',  # 7
                        '........',  # 6
                        '........',  # 5
                        '........',  # 4
                        '........',  # 3
                        '........',  # 2
                        'T.......'   # 1
                    ]),
                },
            }),
            *self.all_board_rotations_of({
                'name': 'should_be_able_to_capture_enemies',
                'board': Board.from_strings([
                    # bcdefgh
                    '.......N',  # 8
                    '.....n..',  # 7
                    '......n.',  # 6
                    '........',  # 5
                    '........',  # 4
                    '.N......',  # 3
                    '..N.....',  # 2
                    'n.......'   # 1
                ]),
                'want': {
                    'white': target_board([
                        # bcdefgh
                        '.......T',  # 8
                        '.....x..',  # 7
                        '......x.',  # 6
                        '........',  # 5
                        '........',  # 4
                        '........',  # 3
                        '........',  # 2
                        'n.......'   # 1
                    ]),
                    'black': target_board([
                        # bcdefgh
                        '.......N',  # 8
                        '........',  # 7
                        '........',  # 6
                        '........',  # 5
                        '........',  # 4
                        '.x......',  # 3
                        '..x.....',  # 2
                        'T.......'   # 1
                    ]),
                },
            }),
        ]

        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #19
0
    def test_should_move_rook_when_king_castles(self):
        with self.subTest('black king side'):
            board = Board.from_strings([
                # bcdefgh
                'r...k..r',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                '........'  # 1
                # bcdefgh
            ])
            black_king = board[Rank.EIGHT][File.E]
            self.assertIn(P('g8'), black_king.generate_moves(board, P('e8')))

            board.move(from_pos=P('e8'), to_pos=P('g8'))
            self.assertIsInstance(board[Rank.EIGHT][File.F],
                                  Rook)  # rook has moved

        with self.subTest('black queen side'):
            board = Board.from_strings([
                # bcdefgh
                'r...k..r',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                '........'  # 1
            ])
            black_king = board[Rank.EIGHT][File.E]
            self.assertIn(P('c8'), black_king.generate_moves(board, P('e8')))

            board.move(from_pos=P('e8'), to_pos=P('c8'))
            self.assertIsInstance(board[Rank.EIGHT][File.D],
                                  Rook)  # rook has moved

        with self.subTest('white king side'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                'R...K..R'  # 1
            ])
            white_king = board[Rank.ONE][File.E]
            self.assertIn(P('c1'), white_king.generate_moves(board, P('e1')))

            board.move(from_pos=P('e1'), to_pos=P('g1'))
            self.assertIsInstance(board[Rank.ONE][File.F],
                                  Rook)  # rook has moved

        with self.subTest('white queen side'):
            board = Board.from_strings([
                # bcdefgh
                '........',  # 8
                '........',  # 7
                '........',  # 6
                '........',  # 5
                '........',  # 4
                '........',  # 3
                '........',  # 2
                'R...K..R'  # 1
            ])
            white_king = board[Rank.ONE][File.E]
            self.assertIn(P('c1'), white_king.generate_moves(board, P('e1')))

            board.move(from_pos=P('e1'), to_pos=P('c1'))
            self.assertIsInstance(board[Rank.ONE][File.D],
                                  Rook)  # rook has moved
    def test_pieces_should_body_block_checks(self):
        """
        Even though there may be other possible moves if something body blocks a check,
        it should be able to make only such moves that keep blocking the check
        """

        test_table = [
            {
                'name':
                'white_diagonal_pieces_should_not_be_able_to_move_from_diagonals',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '.b.....q',  # 8
                    '........',  # 7
                    '...Q.Q..',  # 6
                    '....K...',  # 5
                    '...Q.Q..',  # 4
                    '........',  # 3
                    '.q.....b',  # 2
                    '........'  # 1
                    # bcdefgh
                ]),
                'want': {
                    'white': {
                        P('f6'): {P('g7'), P('h8')},
                        P('f4'): {P('g3'), P('h2')},
                        P('d6'): {P('c7'), P('b8')},
                        P('d4'): {P('c3'), P('b2')},
                    }
                },
                'expect_same_behaviour_for': ['bishop'],
            },
            {
                'name':
                'black_diagonal_pieces_should_not_be_able_to_move_from_diagonals',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '.B.....Q',  # 8
                    '........',  # 7
                    '...q.q..',  # 6
                    '....k...',  # 5
                    '...b.b..',  # 4
                    '........',  # 3
                    '.Q.....B',  # 2
                    '........'  # 1
                    # bcdefgh
                ]),
                'want': {
                    'black': {
                        P('f6'): {P('g7'), P('h8')},
                        P('f4'): {P('g3'), P('h2')},
                        P('d6'): {P('c7'), P('b8')},
                        P('d4'): {P('c3'), P('b2')},
                    }
                },
                'expect_same_behaviour_for': ['bishop'],
            },
            {
                'name':
                'white_should_not_be_able_to_move_from_straight',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '....q...',  # 8
                    '........',  # 7
                    '....Q...',  # 6
                    '.q.QKQ.q',  # 5
                    '....Q...',  # 4
                    '........',  # 3
                    '....q...',  # 2
                    '........'  # 1
                ]),
                'want': {
                    'white': {
                        P('f5'): {P('g5'), P('h5')},
                        P('d5'): {P('c5'), P('b5')},
                        P('e6'): {P('e7'), P('e8')},
                        P('e4'): {P('e3'), P('e2')},
                    }
                },
                'expect_same_behaviour_for': ['rook'],
            },
            {
                'name':
                'black_figure_should_not_be_able_to_move_from_straight',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '....Q...',  # 8
                    '........',  # 7
                    '....q...',  # 6
                    '.Q.qkq.Q',  # 5
                    '....q...',  # 4
                    '........',  # 3
                    '....Q...',  # 2
                    '........'  # 1
                ]),
                'want': {
                    'black': {
                        P('f5'): {P('g5'), P('h5')},
                        P('d5'): {P('c5'), P('b5')},
                        P('e6'): {P('e7'), P('e8')},
                        P('e4'): {P('e3'), P('e2')},
                    }
                },
                'expect_same_behaviour_from': ['rook'],
            },
            {
                'name':
                'knight_should_be_allowed_only_to_block',
                'board':
                Board.from_strings([
                    # bcdefgh
                    'N.....n.',  # 8
                    '.q.....Q',  # 7
                    '........',  # 6
                    '.K.....k',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    '........'  # 1
                ]),
                'want': {
                    'white': {
                        P('a8'): {P('b6')}
                    },
                    'black': {
                        P('g8'): {P('h6')}
                    }
                }
            },
            {
                'name':
                'pawn_should_be_allowed_only_to_block',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '........',  # 8
                    '........',  # 7
                    '........',  # 6
                    '......q.',  # 5
                    '........',  # 4
                    '........',  # 3
                    '.....P..',  # 2
                    '..K.....'  # 1
                ]),
                'want': {
                    'white': {
                        P('f2'): {P('f4')}
                    },
                }
            },
            {
                'name':
                'should_only_be_able_to_capture_when_knight_checks',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '.....k..',  # 8
                    '....q..N',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    'n..Q....',  # 2
                    '..K.....'  # 1
                    # bcdefgh
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        '........',  # 8
                        '........',  # 7
                        '........',  # 6
                        '........',  # 5
                        '........',  # 4
                        '........',  # 3
                        'x..T....',  # 2
                        '..K.....'  # 1
                        # bcdefgh
                    ]),
                    'black':
                    target_board([
                        # bcdefgh
                        '.....k..',  # 8
                        '....T..x',  # 7
                        '........',  # 6
                        '........',  # 5
                        '........',  # 4
                        '........',  # 3
                        '........',  # 2
                        '........'  # 1
                    ]),
                }
            },
            {
                'name':
                'pieces_that_cannot_protect_king_should_have_no_moves',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '.....k..',  # 8
                    '.......N',  # 7
                    '...q....',  # 6
                    '........',  # 5
                    '........',  # 4
                    '...Q....',  # 3
                    'n.......',  # 2
                    '..K.....'  # 1
                    # bcdefgh
                ]),
                'want': {
                    'white': {
                        P('d3'): {}
                    },
                    'black': {
                        P('d6'): {}
                    },
                }
            },
        ]
        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #21
0
    def test_move_generation(self):
        test_table = [
            *self.all_board_rotations_of({
                'name':
                'should_have_two_straights_available',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '.......r',  # 8
                    '........',  # 7
                    '........',  # 6
                    '........',  # 5
                    '........',  # 4
                    '........',  # 3
                    '........',  # 2
                    'R.......'  # 1
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        'x......r',  # 8
                        'x.......',  # 7
                        'x.......',  # 6
                        'x.......',  # 5
                        'x.......',  # 4
                        'x.......',  # 3
                        'x.......',  # 2
                        'Txxxxxxx'  # 1
                    ]),
                    'black':
                    target_board([
                        # bcdefgh
                        'xxxxxxxT',  # 8
                        '.......x',  # 7
                        '.......x',  # 6
                        '.......x',  # 5
                        '.......x',  # 4
                        '.......x',  # 3
                        '.......x',  # 2
                        'R......x'  # 1
                    ]),
                }
            }),
            *self.all_board_rotations_of({
                'name':
                'should_stop_at_first_friendly',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '....r..r',  # 8
                    '........',  # 7
                    '........',  # 6
                    '.......r',  # 5
                    'R.......',  # 4
                    '........',  # 3
                    '........',  # 2
                    'R..R....'  # 1
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        '....r..r',  # 8
                        '........',  # 7
                        '........',  # 6
                        '.......r',  # 5
                        'R.......',  # 4
                        'x.......',  # 3
                        'x.......',  # 2
                        'TxxR....'  # 1
                    ]),
                    'black':
                    target_board([
                        # bcdefgh
                        '....rxxT',  # 8
                        '.......x',  # 7
                        '.......x',  # 6
                        '.......r',  # 5
                        'R.......',  # 4
                        '........',  # 3
                        '........',  # 2
                        'R..R....'  # 1
                    ]),
                }
            }),
            {
                'name':
                'should_stop_on_top_of_first_enemy',
                'board':
                Board.from_strings([
                    # bcdefgh
                    '....R..r',  # 8
                    '........',  # 7
                    '........',  # 6
                    '.......R',  # 5
                    'r.......',  # 4
                    '........',  # 3
                    '........',  # 2
                    'R..r....'  # 1
                ]),
                'want': {
                    'white':
                    target_board([
                        # bcdefgh
                        '....xxxT',  # 8
                        '.......x',  # 7
                        '.......x',  # 6
                        '.......x',  # 5
                        'r.......',  # 4
                        '........',  # 3
                        '........',  # 2
                        'R..r....'  # 1
                    ]),
                    'black':
                    target_board([
                        # bcdefgh
                        '....R..r',  # 8
                        '........',  # 7
                        '........',  # 6
                        '.......R',  # 5
                        'x.......',  # 4
                        'x.......',  # 3
                        'x.......',  # 2
                        'Txxx....'  # 1
                    ]),
                }
            }
        ]

        for test_case in test_table:
            self.runMoveGenerationTest(test_case)
Beispiel #22
0
 def test_pawn_move_generation(self):
     test_table = [
         {
             'name':
             'when_friendly_is_blocking',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '.p......',  # 7
                 '........',  # 6
                 '.p......',  # 5
                 '.P......',  # 4
                 '........',  # 3
                 '.P......',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.TWO, File.B):
                     {Position(Rank.THREE, File.B)}
                 },
                 'black': {
                     Position(Rank.SEVEN, File.B):
                     {Position(Rank.SIX, File.B)}
                 },
             }
         },
         {
             'name':
             'given_starting_position_enemy_is_blocking_two_squares_ahead',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '.p......',  # 7
                 '........',  # 6
                 '.P......',  # 5
                 '.p......',  # 4
                 '........',  # 3
                 '.P......',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.TWO, File.B):
                     {Position(Rank.THREE, File.B)}
                 },
                 'black': {
                     Position(Rank.SEVEN, File.B):
                     {Position(Rank.SIX, File.B)}
                 },
             }
         },
         {
             'name':
             'should_capture_left',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '........',  # 7
                 '.p......',  # 6
                 'P.......',  # 5
                 'p.......',  # 4
                 '.P......',  # 3
                 '........',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.THREE, File.B): {
                         Position(Rank.FOUR, File.A),
                         Position(Rank.FOUR, File.B),
                     }
                 },
                 'black': {
                     Position(Rank.SIX, File.B): {
                         Position(Rank.FIVE, File.A),
                         Position(Rank.FIVE, File.B),
                     }
                 },
             }
         },
         {
             'name':
             'should_not_capture_left_friendly',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '........',  # 7
                 '.p......',  # 6
                 'p.......',  # 5
                 'P.......',  # 4
                 '.P......',  # 3
                 '........',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.THREE, File.B): {
                         Position(Rank.FOUR, File.B),
                     }
                 },
                 'black': {
                     Position(Rank.SIX, File.B): {
                         Position(Rank.FIVE, File.B),
                     }
                 },
             }
         },
         {
             'name':
             'should_capture_right',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '........',  # 7
                 '.p......',  # 6
                 '..P.....',  # 5
                 '..p.....',  # 4
                 '.P......',  # 3
                 '........',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.THREE, File.B): {
                         Position(Rank.FOUR, File.B),
                         Position(Rank.FOUR, File.C),
                     }
                 },
                 'black': {
                     Position(Rank.SIX, File.B): {
                         Position(Rank.FIVE, File.B),
                         Position(Rank.FIVE, File.C),
                     }
                 },
             }
         },
         {
             'name':
             'should_not_capture_right_friendly',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '........',  # 7
                 '.p......',  # 6
                 '..p.....',  # 5
                 '..P.....',  # 4
                 '.P......',  # 3
                 '........',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.THREE, File.B): {
                         Position(Rank.FOUR, File.B),
                     }
                 },
                 'black': {
                     Position(Rank.SIX, File.B): {
                         Position(Rank.FIVE, File.B),
                     }
                 },
             }
         },
         {
             'name':
             'should_be_able_to_mode_two_ahead_from_start',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '.p......',  # 7
                 '........',  # 6
                 '........',  # 5
                 '........',  # 4
                 '........',  # 3
                 '.P......',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.TWO, File.B): {
                         Position(Rank.THREE, File.B),
                         Position(Rank.FOUR, File.B),
                     }
                 },
                 'black': {
                     Position(Rank.SEVEN, File.B): {
                         Position(Rank.SIX, File.B),
                         Position(Rank.FIVE, File.B),
                     }
                 },
             }
         },
         {
             'name':
             'should_have_all_positions',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '.p......',  # 7
                 'P.P.....',  # 6
                 '........',  # 5
                 '........',  # 4
                 'p.p.....',  # 3
                 '.P......',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.TWO, File.B): {
                         Position(Rank.THREE, File.A),
                         Position(Rank.THREE, File.B),
                         Position(Rank.THREE, File.C),
                         Position(Rank.FOUR, File.B),
                     }
                 },
                 'black': {
                     Position(Rank.SEVEN, File.B): {
                         Position(Rank.SIX, File.A),
                         Position(Rank.SIX, File.B),
                         Position(Rank.SIX, File.C),
                         Position(Rank.FIVE, File.B),
                     }
                 },
             }
         },
         {
             'name':
             'clear_file_not_starting_square_should_have_only_one_ahead',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '........',  # 7
                 '.p......',  # 6
                 '........',  # 5
                 '........',  # 4
                 '.P......',  # 3
                 '........',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.THREE, File.B): {
                         Position(Rank.FOUR, File.B),
                     }
                 },
                 'black': {
                     Position(Rank.SIX, File.B): {
                         Position(Rank.FIVE, File.B),
                     }
                 },
             }
         },
         {
             'name':
             'friendly_blocker_and_no_captures_should_have_no_moves',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '........',  # 7
                 '.p......',  # 6
                 '.p......',  # 5
                 '.P......',  # 4
                 '.P......',  # 3
                 '........',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.THREE, File.B): {}
                 },
                 'black': {
                     Position(Rank.SIX, File.B): {}
                 },
             }
         },
         {
             'name':
             'enemy_blocker_and_no_captures_should_have_no_moves',
             'board':
             Board.from_strings([
                 # bcdefgh
                 '........',  # 8
                 '........',  # 7
                 '.p......',  # 6
                 '.P......',  # 5
                 '.p......',  # 4
                 '.P......',  # 3
                 '........',  # 2
                 '........'  # 1
             ]),
             'want': {
                 'white': {
                     Position(Rank.THREE, File.B): {}
                 },
                 'black': {
                     Position(Rank.SIX, File.B): {}
                 },
             }
         },
     ]
     for test_case in test_table:
         self.runMoveGenerationTest(test_case)