コード例 #1
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_king_cant_capture(self):
        """
        Test a few scenarios where the king cannot capture another piece.
        Expected result is piece next to king cannot be captured and will not be in legal moves list.
        :return:
        """
        # Test scenario where opponent piece backing up other opponent piece.
        board = ChessBoard()
        start_position = 'd4'
        capture_position = 'd5'
        board[start_position] = King(Color.WHITE)
        board['e4'] = Pawn(Color.BLACK)
        board[capture_position] = Pawn(Color.BLACK)

        expected_legal_moves = ['c3', 'c5', 'd5', 'e3', 'e5']
        legal_moves = board.get_legal_moves(start_position)
        legal_moves.sort()

        self.assertListEqual(
            expected_legal_moves, legal_moves,
            'Expected move list does not match actual move list')

        # Test king has piece of same color directly in front of it
        board = ChessBoard()
        board['d4'] = King(Color.WHITE)
        board['d5'] = Pawn(Color.WHITE)

        expected_legal_moves = ['c3', 'c4', 'c5', 'd3', 'e3', 'e4', 'e5']
        legal_moves = board.get_legal_moves('d4')
        legal_moves.sort()

        self.assertListEqual(
            expected_legal_moves, legal_moves,
            'Expected move list does not match actual move list')
コード例 #2
0
    def test_piece_pinned(self):
        """
        Test moving a piece of every type that is the same color as king but pinned by opponents piece.
        Expected result is legal move list for piece should be empty.
        :return:
        """
        # Pawn pined
        board = ChessBoard()
        board['c3'] = King(Color.WHITE)
        board['d4'] = Pawn(Color.WHITE)
        board['f6'] = Bishop(Color.BLACK)

        legal_moves = board.get_legal_moves('d4')
        self.assertListEqual([], legal_moves,
                             'Piece should not have any legal moves.')

        # Rook pined
        board = ChessBoard()
        board['c3'] = King(Color.WHITE)
        board['d4'] = Rook(Color.WHITE)
        board['f6'] = Bishop(Color.BLACK)

        legal_moves = board.get_legal_moves('d4')
        self.assertListEqual([], legal_moves,
                             'Piece should not have any legal moves.')

        # Knight pined
        board = ChessBoard()
        board['c3'] = King(Color.WHITE)
        board['d4'] = Knight(Color.WHITE)
        board['f6'] = Bishop(Color.BLACK)

        legal_moves = board.get_legal_moves('d4')
        self.assertListEqual([], legal_moves,
                             'Piece should not have any legal moves.')

        # Bishop pined
        board = ChessBoard()
        board['c3'] = King(Color.WHITE)
        board['c5'] = Bishop(Color.WHITE)
        board['c6'] = Rook(Color.BLACK)

        legal_moves = board.get_legal_moves('c5')
        self.assertListEqual([], legal_moves,
                             'Piece should not have any legal moves.')

        # Queen kinda pined
        board = ChessBoard()
        board['c3'] = King(Color.WHITE)
        board['c4'] = Queen(Color.WHITE)
        board['c6'] = Rook(Color.BLACK)

        legal_moves = board.get_legal_moves('c4')
        self.assertListEqual(['c5', 'c6'], legal_moves,
                             'Legal moves dont match expected moves.')
コード例 #3
0
    def test_pawn_legal_moves_piece_blocking(self):
        """
        Place a pawn on a square and another piece 2 positions in front of it.
        Expected result is there are is one legal move for the pawn that is blocked.
        :return:
        """
        opposing_colors = [[Color.BLACK, Color.WHITE],
                           [Color.WHITE, Color.BLACK]]
        for opposing_color in opposing_colors:
            start_positions = ['b2', 'g7']
            blocking_positions = ['b4', 'g5']
            expected_moves = [['b3'], ['g6']]
            pawn_colors = [Color.WHITE, Color.BLACK]
            for start, blocking, expected, pawn_color, opposing in zip(
                    start_positions, blocking_positions, expected_moves,
                    pawn_colors, opposing_color):
                with self.subTest(start=start,
                                  blocking=blocking,
                                  expected=expected,
                                  pawn_color=pawn_color,
                                  opposing=opposing):
                    board = ChessBoard()
                    board[start] = Pawn(pawn_color)
                    board[blocking] = Pawn(opposing)

                    legal_moves = board.get_legal_moves(start)
                    legal_moves.sort()

                    message = 'Pawn should only have one legal move'
                    self.assertListEqual(expected, legal_moves, message)
コード例 #4
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_queen_capture(self):
        """
        Move queen to position where an opponents piece is in the capture path.
        Expected result is opponents piece is in legal move list and piece is captured when queen moves to that
        position.
        :return:
        """
        board = ChessBoard()
        start_position = 'd4'
        capture_position = 'e4'
        board[start_position] = Queen(Color.WHITE)
        board['d5'] = Pawn(Color.BLACK)
        board[capture_position] = Pawn(Color.BLACK)
        expected_possible_moves = [
            'a1', 'a4', 'a7', 'b2', 'b4', 'b6', 'c3', 'c4', 'c5', 'd1', 'd2',
            'd3', 'd5', 'e3', 'e4', 'e5', 'f2', 'f6', 'g1', 'g7', 'h8'
        ]
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        message = 'Expected move list does not match actual move list'
        self.assertListEqual(expected_possible_moves, possible_moves, message)

        # Move queen to capture a piece
        move_result = board.move_piece(start_position, capture_position)
        message = 'Queen should have captured piece on ' + capture_position + ' square'
        self.assertIsInstance(board[capture_position], Queen, message)

        # Test move result
        expected_move_result = {
            start_position: None,
            capture_position: Queen(Color.WHITE)
        }
        self.assertDictEqual(expected_move_result, move_result,
                             'Expected move result does not match actual')
コード例 #5
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_king_capture(self):
        """
        Move king to square right next to piece of opposing color with nothing backing it up.
        Expected result is position with opponent piece is in legal move list and piece is captured
        when king moves to that position.
        :return:
        """
        board = ChessBoard()
        start_position = 'd4'
        capture_position = 'e4'
        board[start_position] = King(Color.WHITE)
        board[capture_position] = Pawn(Color.BLACK)

        expected_legal_moves = ['c3', 'c4', 'c5', 'd5', 'e3', 'e4', 'e5']
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        self.assertListEqual(
            expected_legal_moves, possible_moves,
            'Expected move list does not match actual move list')

        # Move king to capture a piece
        move_result = board.move_piece(start_position, capture_position)
        message = 'King should have captured piece on ' + capture_position + ' square'
        self.assertIsInstance(board[capture_position], King, message)

        # Test move result
        expected_move_result = {
            start_position: None,
            capture_position: King(Color.WHITE)
        }
        self.assertDictEqual(expected_move_result, move_result,
                             'Expected move result does not match actual')
コード例 #6
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_bishop_capture(self):
        """
        Move a bishop to square where there is a piece of the opposite color on capture diagonal.
        Expected result is position with opponent piece is in legal move list and piece is captured
        when bishop moves to that position.
        :return:
        """
        board = ChessBoard()
        start_position = 'd4'
        capture_position = 'h8'
        board[start_position] = Bishop(Color.WHITE)
        board['c5'] = Queen(Color.BLACK)
        board[capture_position] = Pawn(Color.BLACK)
        expected_possible_moves = [
            'a1', 'b2', 'c3', 'c5', 'e3', 'e5', 'f2', 'f6', 'g1', 'g7', 'h8'
        ]
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        message = 'Expected move list does not match actual move list'
        self.assertListEqual(expected_possible_moves, possible_moves, message)

        # Move bishop to capture a piece
        move_result = board.move_piece(start_position, capture_position)
        message = 'Bishop should have captured piece on ' + capture_position + ' square'
        self.assertIsInstance(board[capture_position], Bishop, message)

        # Test move result
        expected_move_result = {
            start_position: None,
            capture_position: Bishop(Color.WHITE)
        }
        self.assertDictEqual(expected_move_result, move_result,
                             'Expected move result does not match actual')
コード例 #7
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_knight_capture(self):
        """
        Move knight to a middle square with a piece on a capture square.
        Expected result is position with opponent piece is in legal move list and piece is captured
        when knight moves to that position.
        :return:
        """
        board = ChessBoard()
        start_position = 'd4'
        capture_position = 'f5'
        board[start_position] = Knight(Color.WHITE)
        board[capture_position] = Bishop(Color.BLACK)
        expected_possible_moves = [
            'b3', 'b5', 'c2', 'c6', 'e2', 'e6', 'f3', 'f5'
        ]
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        message = 'Expected move list does not match actual move list'
        self.assertListEqual(expected_possible_moves, possible_moves, message)

        # Move knight to capture a piece
        move_result = board.move_piece(start_position, capture_position)
        message = 'Knight should have captured piece on ' + capture_position + ' square'
        self.assertIsInstance(board[capture_position], Knight, message)

        # Test move result
        expected_move_result = {
            start_position: None,
            capture_position: Knight(Color.WHITE)
        }
        self.assertDictEqual(expected_move_result, move_result,
                             'Expected move result does not match actual')
コード例 #8
0
    def test_king_legal_moves(self):
        """
        Move a king to each corner and one middle square.
        Expected result is that all the possible moves match the expected list.
        :return:
        """
        start_positions = {
            Color.WHITE: {
                'a1': ['a2', 'b1', 'b2'],
                'a8': ['a7', 'b7', 'b8'],
                'h1': ['g1', 'g2', 'h2'],
                'h8': ['g7', 'g8', 'h7'],
                'd4': ['c3', 'c4', 'c5', 'd3', 'd5', 'e3', 'e4', 'e5']
            },
            Color.BLACK: {
                'a1': ['a2', 'b1', 'b2'],
                'a8': ['a7', 'b7', 'b8'],
                'h1': ['g1', 'g2', 'h2'],
                'h8': ['g7', 'g8', 'h7'],
                'd4': ['c3', 'c4', 'c5', 'd3', 'd5', 'e3', 'e4', 'e5']
            }
        }
        for color, positions in start_positions.items():
            for start_position, expected_moves in positions.items():
                with self.subTest(color=color,
                                  start_position=start_position,
                                  expected_moves=expected_moves):
                    board = ChessBoard()
                    board[start_position] = King(color)
                    possible_moves = board.get_legal_moves(start_position)
                    possible_moves.sort()

                    message = 'Expected move list does not match actual move list'
                    self.assertListEqual(expected_moves, possible_moves,
                                         message)
コード例 #9
0
    def test_pawn_legal_moves(self):
        """
        Move a pawn to each corner and one middle square.
        Expected result is that all the possible moves match the expected list.
        :return:
        """
        start_positions = {
            Color.WHITE: {
                'a1': ['a2', 'a3'],
                'a8': [],
                'h1': ['h2', 'h3'],
                'h8': [],
                'd4': ['d5', 'd6']
            },
            Color.BLACK: {
                'a1': [],
                'a8': ['a6', 'a7'],
                'h1': [],
                'h8': ['h6', 'h7'],
                'd4': ['d2', 'd3']
            }
        }
        for color, positions in start_positions.items():
            for start_position, expected_moves in positions.items():
                with self.subTest(color=color,
                                  start_position=start_position,
                                  expected_moves=expected_moves):
                    board = ChessBoard()
                    board[start_position] = Pawn(color)
                    possible_moves = board.get_legal_moves(start_position)
                    possible_moves.sort()

                    message = 'Expected move list does not match actual move list'
                    self.assertListEqual(expected_moves, possible_moves,
                                         message)

        # Confirm pawn can only move one square after it is moved
        board = ChessBoard()
        board['a1'] = Pawn(Color.WHITE)
        board.move_piece('a1', 'a3')
        possible_moves = board.get_legal_moves('a3')
        expected_possible_moves = ['a4']

        self.assertListEqual(expected_possible_moves, possible_moves,
                             'Pawn should not be able to ')
コード例 #10
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_pawn_capture(self):
        """
        Move a pawn to a square where there is a piece of the opposite color on one of the most immediate diagonal
        squares.
        Expected result is that the square that contains the piece of the opposite color is in the list of possible
        moves for the pawn. Opposing piece is also successfully captured by pawn.
        :return:
        """
        # Test diagonal move when a piece of the opposite color is present
        board = ChessBoard()
        start_position = 'b1'
        capture_position = 'c2'
        board[start_position] = Pawn(Color.WHITE)
        board['c2'] = Bishop(Color.BLACK)
        expected_possible_moves = ['b2', 'b3', 'c2']
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        message = 'Expected pawn to be able to move diagonally'
        self.assertListEqual(expected_possible_moves, possible_moves, message)

        # place a second piece and confirm both diagonals show as possible moves
        board['a2'] = Rook(Color.BLACK)
        expected_possible_moves = ['a2', 'b2', 'b3', 'c2']
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        message = 'Expected pawn to be able to move diagonally in both directions'
        self.assertListEqual(expected_possible_moves, possible_moves, message)

        # Move pawn to capture a piece
        move_result = board.move_piece(start_position, capture_position)
        message = 'Pawn should have captured piece on ' + capture_position + ' square'
        self.assertIsInstance(board[capture_position], Pawn, message)

        # Test move result
        expected_move_result = {
            start_position: None,
            capture_position: Pawn(Color.WHITE)
        }
        self.assertDictEqual(expected_move_result, move_result,
                             'Expected move result does not match actual')
コード例 #11
0
    def test_king_castle_legal_move(self):
        """
        Place king on starting square and rooks of the same color on their starting squares.
        Expected result is that queen side and king side castling is listed in legal moves list.
        :return:
        """
        board = ChessBoard()
        board['a1'] = Rook(Color.WHITE)
        board['e1'] = King(Color.WHITE)
        board['a8'] = Rook(Color.BLACK)
        board['e8'] = King(Color.BLACK)

        # Try with just one rook.
        expected_legal_moves = {
            'e1': ['c1', 'd1', 'd2', 'e2', 'f1', 'f2'],
            'e8': ['c8', 'd7', 'd8', 'e7', 'f7', 'f8'],
        }
        for position, expected_moves in expected_legal_moves.items():
            with self.subTest(position=position,
                              expected_moves=expected_moves):
                legal_moves = board.get_legal_moves(position)
                legal_moves.sort()
                self.assertListEqual(
                    expected_moves, legal_moves,
                    'Castle move should be in legal move list')

        # Try with both rooks.
        board['h1'] = Rook(Color.WHITE)
        board['h8'] = Rook(Color.BLACK)
        expected_legal_moves = {
            'e1': ['c1', 'd1', 'd2', 'e2', 'f1', 'f2', 'g1'],
            'e8': ['c8', 'd7', 'd8', 'e7', 'f7', 'f8', 'g8'],
        }
        for position, expected_moves in expected_legal_moves.items():
            with self.subTest(position=position,
                              expected_moves=expected_moves):
                legal_moves = board.get_legal_moves(position)
                legal_moves.sort()
                self.assertListEqual(
                    expected_moves, legal_moves,
                    'Castle move should be in legal move list')
コード例 #12
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_pawn_cant_capture(self):
        """
        Move a pawn to a square where there is a piece of the same color on one of the most immediate diagonal
        squares.
        Expected result is that the square that contains the piece of the same color is not in the list of possible
        moves for the pawn.
        :return:
        """
        board = ChessBoard()
        start_position = 'b1'
        board[start_position] = Pawn(Color.WHITE)
        board['c2'] = Bishop(Color.WHITE)
        expected_possible_moves = ['b2', 'b3']
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        message = 'Expected move list does not match actual move list'
        self.assertListEqual(expected_possible_moves, possible_moves, message)
コード例 #13
0
    def test_king_cant_put_self_in_check(self):
        """
        Place king in middle square. Place rook of opposing color on an immediate front right diagonal square.
        Expected result is the space directly to the right and in front of king is not in legal moves list.
        :return:
        """
        color_group = [(Color.WHITE, Color.BLACK), (Color.BLACK, Color.WHITE)]
        for group in color_group:
            with self.subTest(group=group):
                board = ChessBoard()
                king_color, rook_color = group
                board['d4'] = King(king_color)
                board['e5'] = Rook(rook_color)

                expected_moves = ['c3', 'c4', 'd3', 'e5']
                legal_moves = board.get_legal_moves('d4')
                legal_moves.sort()
                self.assertListEqual(
                    expected_moves, legal_moves,
                    'King should not be able to put self in check')
コード例 #14
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_queen_cant_capture(self):
        """
        Move queen to a square and place piece of same color in movement path.
        Expected result is that the square containing the piece of the same color is not in the list of legal
        moves.
        :return:
        """
        board = ChessBoard()
        board['b2'] = Queen(Color.WHITE)
        board['b3'] = Pawn(Color.WHITE)

        expected_legal_moves = [
            'a1', 'a2', 'a3', 'b1', 'c1', 'c2', 'c3', 'd2', 'd4', 'e2', 'e5',
            'f2', 'f6', 'g2', 'g7', 'h2', 'h8'
        ]
        legal_moves = board.get_legal_moves('b2')
        legal_moves.sort()

        self.assertListEqual(expected_legal_moves, legal_moves,
                             'Expected move list does not match actual')
コード例 #15
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_bishop_cant_capture(self):
        """
        Move bishop to square and place piece of same color in movement path.
        Expected result is that the square containing the piece of the same color is not in the list of legal
        moves.
        :return:
        """
        color_group = [Color.WHITE, Color.BLACK]
        for color in color_group:
            with self.subTest(color=color):
                board = ChessBoard()
                board['b2'] = Bishop(color)
                board['c3'] = Pawn(color)

                expected_moves = ['a1', 'a3', 'c1']
                legal_moves = board.get_legal_moves('b2')
                legal_moves.sort()
                self.assertListEqual(
                    expected_moves, legal_moves,
                    'Expected list does not match actual legal move list')
コード例 #16
0
    def test_pawn_en_passant_legal_move(self):
        """
        Place pawn on 4th or 5th rank and move pawn of opposite color immediately to left or right of first pawn.
        Expected result is en passant move is present in legal move list for first pawn.
        :return:
        """
        piece_movements = {
            Color.WHITE: [[('h2', 'h5'), ('g7', 'g5')],
                          [('a2', 'a5'), ('b7', 'b5')]],
            Color.BLACK: [[('a7', 'a4'), ('b2', 'b4')],
                          [('h7', 'h4'), ('g2', 'g4')]]
        }
        expected_moves = {
            Color.WHITE: {
                'h5': ['g6', 'h6'],
                'a5': ['a6', 'b6']
            },
            Color.BLACK: {
                'a4': ['a3', 'b3'],
                'h4': ['g3', 'h3']
            }
        }
        fen = Fen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -')
        for (c1, moves_for_color), (c2, expected_for_color) in zip(
                piece_movements.items(), expected_moves.items()):
            for piece_moves, (check_position, expected_list) in zip(
                    moves_for_color, expected_for_color.items()):
                with self.subTest(piece_moves=piece_moves,
                                  check_position=check_position,
                                  expected_list=expected_list):
                    board = ChessBoard(fen)
                    for movements in piece_moves:
                        start, end = movements
                        board.move_piece(start, end)

                    legal_moves = board.get_legal_moves(check_position)
                    legal_moves.sort()
                    self.assertListEqual(
                        expected_list, legal_moves,
                        'En passant move should be in legal moves list')
コード例 #17
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_rook_cant_capture(self):
        """
        Move rook to a square and another piece of the same color immediately to the right of the rook.
        Expected result is that the square containing the pieces of the same color is not in the list of legal
        moves for the rook.
        :return:
        """
        color_group = [Color.WHITE, Color.BLACK]
        for color in color_group:
            with self.subTest(color=color):
                board = ChessBoard()
                board['d4'] = Rook(color)
                board['e4'] = Pawn(color)

                expected_moves = [
                    'a4', 'b4', 'c4', 'd1', 'd2', 'd3', 'd5', 'd6', 'd7', 'd8'
                ]
                legal_moves = board.get_legal_moves('d4')
                legal_moves.sort()
                self.assertListEqual(
                    expected_moves, legal_moves,
                    'Expected moves does not match legal moves')
コード例 #18
0
ファイル: test_piece_capture.py プロジェクト: miyanda2/Chess
    def test_rook_capture(self):
        """
        Move a rook to square where there are pieces of the opposite color on capture file and rank.
        Expected result is that the squares that contain the pieces of the opposite color are in the list of possible
        moves for the rook. One opposing piece is also successfully captured by rook.
        :return:
        """
        board = ChessBoard()
        start_position = 'b1'
        capture_position = 'e1'
        board[start_position] = Rook(Color.WHITE)
        board['c2'] = Bishop(Color.BLACK)
        board['c8'] = Pawn(Color.BLACK)
        board['e1'] = Bishop(Color.BLACK)

        # Test possible moves with several pieces on possible capture squares
        expected_possible_moves = [
            'a1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'c1', 'd1', 'e1'
        ]
        possible_moves = board.get_legal_moves(start_position)
        possible_moves.sort()

        message = 'Expected move list does not match actual move list'
        self.assertListEqual(expected_possible_moves, possible_moves, message)

        # Confirm piece is captured
        move_result = board.move_piece(start_position, capture_position)
        message = 'Rook should have captured piece on ' + capture_position + ' square'
        self.assertIsInstance(board[capture_position], Rook, message)

        # Test move result
        expected_move_result = {
            start_position: None,
            capture_position: Rook(Color.WHITE)
        }
        self.assertDictEqual(expected_move_result, move_result,
                             'Expected move result does not match actual')
コード例 #19
0
    def test_knight_legal_moves(self):
        """
        Move a knight to each corner and one middle square.
        Expected result is that all the possible moves match the expected list.
        :return:
        """
        start_positions = {
            Color.WHITE: {
                'a1': ['b3', 'c2'],
                'a8': ['b6', 'c7'],
                'h1': ['f2', 'g3'],
                'h8': ['f7', 'g6'],
                'd4': ['b3', 'b5', 'c2', 'c6', 'e2', 'e6', 'f3', 'f5'],
                'g7': ['e6', 'e8', 'f5', 'h5']
            },
            Color.BLACK: {
                'a1': ['b3', 'c2'],
                'a8': ['b6', 'c7'],
                'h1': ['f2', 'g3'],
                'h8': ['f7', 'g6'],
                'd4': ['b3', 'b5', 'c2', 'c6', 'e2', 'e6', 'f3', 'f5'],
                'g7': ['e6', 'e8', 'f5', 'h5']
            }
        }
        for color, positions in start_positions.items():
            for start_position, expected_moves in positions.items():
                with self.subTest(color=color,
                                  start_position=start_position,
                                  expected_moves=expected_moves):
                    board = ChessBoard()
                    board[start_position] = Knight(color)
                    possible_moves = board.get_legal_moves(start_position)
                    possible_moves.sort()

                    message = 'Expected move list does not match actual move list'
                    self.assertListEqual(expected_moves, possible_moves,
                                         message)
コード例 #20
0
ファイル: test_chessboard.py プロジェクト: miyanda2/Chess
    def test_cannot_castle(self):
        """
        Test cases where a king cannot castle.
        Expected result is king cannot castle through check, from check, into check, after moving, if
        the rook has moved.
        :return:
        """
        # Check case where king would pass through check
        board = ChessBoard()
        board['a1'] = Rook(Color.WHITE)
        board['e1'] = King(Color.WHITE)
        board['d5'] = Rook(Color.BLACK)

        expected_moves = ['e2', 'f1', 'f2']
        legal_moves = board.get_legal_moves('e1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # King in check
        board.move_piece('d5', 'e5')
        expected_moves = ['d1', 'd2', 'f1', 'f2']
        legal_moves = board.get_legal_moves('e1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # King ends in check
        board.move_piece('e5', 'c5')
        expected_moves = ['d1', 'd2', 'e2', 'f1', 'f2']
        legal_moves = board.get_legal_moves('e1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # Check after king moves
        board = ChessBoard()
        board['a1'] = Rook(Color.WHITE)
        board['e1'] = King(Color.WHITE)
        board.move_piece('e1', 'd1')

        expected_moves = ['c1', 'c2', 'd2', 'e1', 'e2']
        legal_moves = board.get_legal_moves('d1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # Check after left rook moves
        board = ChessBoard()
        board['a1'] = Rook(Color.WHITE)
        board['e1'] = King(Color.WHITE)
        board.move_piece('a1', 'b1')

        expected_moves = ['d1', 'd2', 'e2', 'f1', 'f2']
        legal_moves = board.get_legal_moves('e1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # Check after right rook moves
        board = ChessBoard()
        board['e1'] = King(Color.WHITE)
        board['h1'] = Rook(Color.WHITE)
        board.move_piece('h1', 'h2')

        expected_moves = ['d1', 'd2', 'e2', 'f1', 'f2']
        legal_moves = board.get_legal_moves('e1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # Check with both rooks after right rook moves
        board = ChessBoard()
        board['a1'] = Rook(Color.WHITE)
        board['e1'] = King(Color.WHITE)
        board['h1'] = Rook(Color.WHITE)
        board.move_piece('h1', 'h2')

        expected_moves = ['c1', 'd1', 'd2', 'e2', 'f1', 'f2']
        legal_moves = board.get_legal_moves('e1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # Check with both rooks after right rook moves
        board = ChessBoard()
        board['a1'] = Rook(Color.WHITE)
        board['e1'] = King(Color.WHITE)
        board['h1'] = Rook(Color.WHITE)
        board.move_piece('a1', 'b1')

        expected_moves = ['d1', 'd2', 'e2', 'f1', 'f2', 'g1']
        legal_moves = board.get_legal_moves('e1')
        legal_moves.sort()
        self.assertListEqual(expected_moves, legal_moves,
                             'Expected moves does not match actual')

        # Confirm cannot castle even if king and rooks back in starting positions
        fen = Fen('r3k2r/8/8/8/8/8/8/8 b - -')
        board = ChessBoard(fen)

        can_castle_left = board.can_castle(Color.BLACK, MoveDirection.LEFT)
        can_castle_right = board.can_castle(Color.BLACK, MoveDirection.RIGHT)
        self.assertFalse(can_castle_left,
                         'King should not be able to castle left')
        self.assertFalse(can_castle_right,
                         'King should not be able to castle right')
コード例 #21
0
class ChessGame(db.Model):
    """
    Create new chess game
    """
    __tablename__ = 'game'

    id = db.Column(db.Integer, primary_key=True)
    fen = db.Column(db.String(100))
    white_player_id = db.Column(db.Integer, db.ForeignKey('players.id'))
    black_player_id = db.Column(db.Integer, db.ForeignKey('players.id'))
    is_over = db.Column(db.Boolean, default=False)

    white_player = db.relationship("Player", foreign_keys=white_player_id)
    black_player = db.relationship("Player", foreign_keys=black_player_id)
    score = db.relationship("GameScore", uselist=False, back_populates="game")

    def __init__(self, fen=None, **kwargs):
        """
        Generate a ChessGame object.

        :param fen: string
            Fen notation string to initialize game.
        :param kwargs:
        """
        super().__init__(**kwargs)

        self.fen = fen if fen else 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -'
        fen = Fen(self.fen, validate=False)
        self._board = ChessBoard(fen)

    @property
    def board(self):
        return self._board

    @board.setter
    def board(self, board):
        self._board = board

    def get_legal_moves(self, position):
        """
        Retrieve possible legal moves for a piece on a position.

        :param position: string
            Algebraic notation position.
        :return:
        """
        try:
            ChessHelper.validate_position(position)
        except InvalidPositionError as e:
            # Maybe log error here
            # Reraise exception either way
            raise
        else:
            return self._board.get_legal_moves(position)

    def move_piece(self, start_position, end_position):
        """
        Move a piece from start_position to end_position.

        :param start_position:
        :param end_position:
        :return:
        """
        try:
            ChessHelper.validate_position(start_position)
            ChessHelper.validate_position(end_position)
        except InvalidPositionError as e:
            # Maybe log error here
            # Reraise exception either way
            raise
        else:
            current_fen = Fen(self.fen)
            current_player = current_fen.current_player
            next_player = Color.WHITE if current_player == Color.BLACK else Color.BLACK
            move_result = MoveResult()

            # If moving a pawn to the end of the board, dont update anything on the board.
            # Instead, just return the pawn promote info.
            if self.can_promote_pawn(start_position, end_position):
                player = self._get_player_by_color(current_player)
                promote_info = {
                    'player': player,
                    'promote_types': self.get_pawn_promote_types()
                }
                move_result.pawn_promote_info = promote_info
                return move_result

            move_result.update_positions = self._board.move_piece(
                start_position, end_position)

            # Determine which directions castling is possible for.
            castle_info = {Color.BLACK: [], Color.WHITE: []}
            for color in [Color.WHITE, Color.BLACK]:
                for direction in [MoveDirection.LEFT, MoveDirection.RIGHT]:
                    if self._board.can_castle(color, direction):
                        castle_info[color].append(direction)

            # Generate and save fen string after move
            next_fen = Fen()
            next_fen_str = next_fen.generate_fen(
                self._board.get_board_pieces(), next_player,
                castle_info[Color.WHITE], castle_info[Color.BLACK],
                self._board.get_enpassant_position())
            self.fen = next_fen_str

            # If checkmate or draw, set game over flag. Also create game_score object and fill
            # the move results object.
            is_checkmate = self._board.is_checkmate(next_player)
            is_stalemate = self._board.is_stalemate(next_player)
            if is_checkmate or is_stalemate:
                self.is_over = True
                if is_checkmate:
                    if current_player == Color.WHITE:
                        self.score = GameScore(game=self, white_score=1)
                        player_in_checkmate = self.black_player
                        player_in_checkmate.color = Color.BLACK
                    else:
                        self.score = GameScore(game=self, black_score=1)
                        player_in_checkmate = self.white_player
                        player_in_checkmate.color = Color.WHITE
                    move_result.king_in_checkmate = player_in_checkmate
                else:
                    self.score = GameScore(game=self,
                                           white_score=0.5,
                                           black_score=0.5)
                    move_result.draw = True

            # If it is check, add info to move_result.
            is_check = self._board.is_check(next_player)
            if is_check:
                if current_player == Color.WHITE:
                    player_in_check = self._get_player_by_color(Color.BLACK)
                else:
                    player_in_check = self._get_player_by_color(Color.WHITE)
                move_result.king_in_check = player_in_check

            return move_result

    @property
    def current_player(self):
        """
        Retrieve the current player

        :return Player:
            Player object with color set.
        """
        fen = Fen(self.fen)
        current_player_color = fen.current_player
        current_player = self.white_player if current_player_color == Color.WHITE else self.black_player
        # Dynamically add color field so UI can know player info and color.
        if current_player:
            current_player.color = Color.WHITE if current_player_color == Color.WHITE else Color.BLACK

        return current_player

    def promote_pawn(self, start_position, end_position, piece_type):
        """
        Promote a pawn to another piece type.

        :param start_position: string
            Algebraic notation for pawn position.
        :param end_position: string
            Algebraic notation for destination position.
        :param piece_type: Type
            Value from Type enum
        :return:
        """
        try:
            ChessHelper.validate_position(start_position)
            ChessHelper.validate_position(end_position)
        except InvalidPositionError as e:
            # Maybe log error here
            # Reraise exception either way
            raise
        else:
            if piece_type not in self.get_pawn_promote_types():
                raise PieceTypeError(
                    piece_type, 'Cannot promote pawn to supplied piece type')
            if self._board[start_position] is None:
                raise EmptyPositionError(start_position)
            # TODO confirm pawn on second to last row

            piece = self._board[start_position]
            piece_class = {
                Type.ROOK: Rook,
                Type.KNIGHT: Knight,
                Type.BISHOP: Bishop,
                Type.QUEEN: Queen
            }
            self._board[start_position] = piece_class[piece_type](piece.color)

            return self.move_piece(start_position, end_position)

    def get_winner(self):
        """
        Return winner of game.

        :return:
        """
        # Check if score obj exist. If so, return winner
        pass

    @classmethod
    def get_pawn_promote_types(cls):
        """
        Retrieve the piece types a pawn can promote to.

        :return: Type[]
        """
        return [Type.ROOK, Type.KNIGHT, Type.BISHOP, Type.QUEEN]

    def can_promote_pawn(self, start_position, end_position):
        """
        Test if pawn promotion is possible for the provided position.

        :param start_position: string
            Algebraic notation position.
        :param end_position: string
            Algebraic notation position.
        :return:
        """
        try:
            ChessHelper.validate_position(start_position)
            ChessHelper.validate_position(end_position)
        except InvalidPositionError as e:
            # Maybe log error here
            # Reraise exception either way
            raise
        else:
            if self._board[start_position] is None:
                return False

            piece = self._board[start_position]
            if piece.type != Type.PAWN:
                return False

            _, start_row = self._board.position_to_row_and_column(
                start_position, piece.color)
            _, end_row = self._board.position_to_row_and_column(
                end_position, piece.color)
            if start_row == self._board.get_dimension(
            ) - 2 and end_row == self._board.get_dimension() - 1:
                return True

            return False

    def save_to_db(self):
        """
        Save game to db.

        :return:
        """
        db.session.add(self)
        db.session.commit()

    def delete_from_db(self):
        """
        Delete this game from the db.

        :return:
        """
        db.session.delete(self)
        db.session.commit()

    def to_dict(self):
        """
        Return dictionary for game.
        :return:
        """
        current_player = self.current_player
        white_player = self.white_player
        black_player = self.black_player

        return {
            'game_id': self.id,
            'current_player':
            current_player.to_dict() if current_player else None,
            'white_player': white_player.to_dict() if white_player else None,
            'black_player': black_player.to_dict() if black_player else None,
            'game_over': self.is_over,
            'board': {
                position: piece.to_dict()
                for position, piece in self.board.get_board_pieces().items()
                if piece
            }
        }

    @classmethod
    def load_by_id(cls, game_id):
        game = cls.query.get(game_id)
        if game:
            game.board = ChessBoard(Fen(game.fen))
        return game

    def _get_player_by_color(self, color):
        """
        Retrieve the player associated with the provided color.

        :param color: Color
        :return: Player
        """
        if color == Color.WHITE:
            player = self.white_player
            player.color = Color.WHITE
        else:
            player = self.black_player
            player.color = Color.BLACK

        return player

    def __str__(self):
        return str(self._board)
コード例 #22
0
    def test_rook_legal_moves(self):
        """
        Move a rook to each corner and one middle square.
        Expected result is that all the possible moves match the expected list.
        :return:
        """
        start_positions = {
            Color.WHITE: {
                'a1': [
                    'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'b1', 'c1', 'd1',
                    'e1', 'f1', 'g1', 'h1'
                ],
                'a8': [
                    'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'b8', 'c8', 'd8',
                    'e8', 'f8', 'g8', 'h8'
                ],
                'h1': [
                    'a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2', 'h3', 'h4',
                    'h5', 'h6', 'h7', 'h8'
                ],
                'h8': [
                    'a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h1', 'h2', 'h3',
                    'h4', 'h5', 'h6', 'h7'
                ],
                'd4': [
                    'a4', 'b4', 'c4', 'd1', 'd2', 'd3', 'd5', 'd6', 'd7', 'd8',
                    'e4', 'f4', 'g4', 'h4'
                ]
            },
            Color.BLACK: {
                'a1': [
                    'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'b1', 'c1', 'd1',
                    'e1', 'f1', 'g1', 'h1'
                ],
                'a8': [
                    'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'b8', 'c8', 'd8',
                    'e8', 'f8', 'g8', 'h8'
                ],
                'h1': [
                    'a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2', 'h3', 'h4',
                    'h5', 'h6', 'h7', 'h8'
                ],
                'h8': [
                    'a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h1', 'h2', 'h3',
                    'h4', 'h5', 'h6', 'h7'
                ],
                'd4': [
                    'a4', 'b4', 'c4', 'd1', 'd2', 'd3', 'd5', 'd6', 'd7', 'd8',
                    'e4', 'f4', 'g4', 'h4'
                ]
            }
        }
        for color, positions in start_positions.items():
            for start_position, expected_moves in positions.items():
                with self.subTest(color=color,
                                  start_position=start_position,
                                  expected_moves=expected_moves):
                    board = ChessBoard()
                    board[start_position] = Rook(color)
                    possible_moves = board.get_legal_moves(start_position)
                    possible_moves.sort()

                    message = 'Expected move list does not match actual move list'
                    self.assertListEqual(expected_moves, possible_moves,
                                         message)