Esempio n. 1
0
    def is_legal_king_move(self, move):
        """
        Pseudo-Legal King Moves: one step in any direction
        :param move: the proposed Move instance
        :return: True iff Move is legal
        """
        bitboard = make_uint64()
        moving_to_square = set_bit(bitboard, move.to_sq)

        for i in [8, -8]:
            # North-South
            bitboard |= set_bit(bitboard, np.uint64(move.from_sq + i))
        for i in [1, 9, -7]:
            # East (mask the A file)
            bitboard |= set_bit(bitboard, np.uint64(move.from_sq + i) & ~np.uint64(File.hexA))
        for i in [-1, -9, 7]:
            # West (mask the H file)
            bitboard |= set_bit(bitboard, np.uint64(move.from_sq + i) & ~np.uint64(File.hexH))

        occupied_squares = {
            Color.BLACK: self.board.black_pieces_bb,
            Color.WHITE: self.board.white_pieces_bb,
        }

        # remove own piece targets
        own_piece_targets = occupied_squares[self.color_to_move] & moving_to_square

        if own_piece_targets:
            bitboard &= ~own_piece_targets

        return bitboard
Esempio n. 2
0
    def is_legal_rook_move(self, move: Move) -> bool:
        """
        Pseudo-Legal Rook Moves
        Implements the classical approach for determining legal sliding-piece moves
        for rank and file directions. Gets first blocker with forward or reverse bitscan
        based on the ray direction and XORs the open board ray with the ray continuation
        from the blocked square.
        :param move: the proposed Move instance
        :return: True iff Move is legal
        """
        bitboard = make_uint64()
        moving_to_square = set_bit(bitboard, move.to_sq)
        occupied = self.board.occupied_squares_bb

        # north route
        north_ray = get_north_ray(bitboard, move.from_sq)
        intersection = occupied & north_ray
        if intersection:
            first_blocker = bitscan_forward(intersection)
            block_ray = get_northwest_ray(bitboard, first_blocker)
            north_ray ^= block_ray

        # east route
        east_ray = get_east_ray(bitboard, move.from_sq)
        intersection = occupied & east_ray
        if intersection:
            first_blocker = bitscan_forward(intersection)
            block_ray = get_northeast_ray(bitboard, first_blocker)
            east_ray ^= block_ray

        # south route
        south_ray = get_south_ray(bitboard, move.from_sq)
        intersection = occupied & south_ray
        if intersection:
            first_blocker = bitscan_reverse(intersection)
            block_ray = get_southwest_ray(bitboard, first_blocker)
            south_ray ^= block_ray

        # west route
        west_ray = get_west_ray(bitboard, move.from_sq)
        intersection = occupied & west_ray
        if intersection:
            first_blocker = bitscan_reverse(intersection)
            block_ray = get_southeast_ray(bitboard, first_blocker)
            west_ray ^= block_ray

        legal_moves = moving_to_square & (north_ray | east_ray | south_ray | west_ray)

        occupied_squares = {
            Color.BLACK: self.board.black_pieces_bb,
            Color.WHITE: self.board.white_pieces_bb,
        }

        # remove own piece targets
        own_piece_targets = occupied_squares[self.color_to_move] & moving_to_square
        if own_piece_targets:
            legal_moves &= ~own_piece_targets

        return legal_moves
Esempio n. 3
0
 def intersects_with_opp_pieces(self, square):
     bitboard = make_uint64()
     move_square_bb = set_bit(bitboard, square)
     occupy_lookup = {
         Color.WHITE: self.board.black_pieces_bb,
         Color.BLACK: self.board.white_pieces_bb,
     }
     return occupy_lookup[self.color_to_move] & move_square_bb
Esempio n. 4
0
 def is_legal_knight_move(self, move: Move) -> np.uint64:
     bitboard = make_uint64()
     legal_knight_moves = self.board.get_knight_attack_from(move.from_sq)
     if not legal_knight_moves & set_bit(bitboard, move.to_sq):
         return False
     # if intersects_with_own_pieces return False
     if self.intersects_with_own_pieces(move.to_sq):
         return False
     # if intersects_with_opp_pieces return True, is_capture => True
     if self.intersects_with_opp_pieces(move.to_sq):
         move.is_capture = True
         return True
     return True
Esempio n. 5
0
    def is_legal_pawn_move(self, move: Move) -> bool:
        """
        Pseudo-Legal Pawn Moves:
        - Pawn non-attacks that don't intersect with occupied squares
        - Pawn attacks that intersect with opponent pieces
        :param move: the proposed Move instance
        :return: True iff Move is legal
        """
        bitboard = make_uint64()
        moving_to_square = set_bit(bitboard, move.to_sq)

        legal_non_attack_moves = {
            Color.WHITE: self.board.white_pawn_motion_bbs[move.from_sq],
            Color.BLACK: self.board.black_pawn_motion_bbs[move.from_sq]
        }

        legal_non_attack_moves[self.color_to_move] &= self.board.empty_squares_bb

        legal_attack_moves = {
            Color.WHITE: self.board.white_pawn_attack_bbs[move.from_sq],
            Color.BLACK: self.board.black_pawn_attack_bbs[move.from_sq]
        }

        opp_occupied = {
            Color.WHITE: self.board.black_pieces_bb,
            Color.BLACK: self.board.white_pieces_bb
        }

        legal_attack_moves[self.color_to_move] &= opp_occupied[self.color_to_move]

        legal_moves = legal_non_attack_moves[self.color_to_move] | legal_attack_moves[self.color_to_move]

        # Handle en-passant targets
        if self.en_passant_target:
            en_passant_bb = set_bit(bitboard, self.en_passant_target)
            en_passant_move = legal_attack_moves[self.color_to_move] & en_passant_bb
            legal_moves |= en_passant_move

        # Handle Captures
        if moving_to_square & legal_attack_moves[self.color_to_move]:
            move.is_capture = True

        # Handle removing own piece targets
        occupied_squares = {
            Color.BLACK: self.board.black_pieces_bb,
            Color.WHITE: self.board.white_pieces_bb,
        }

        own_piece_targets = occupied_squares[self.color_to_move] & moving_to_square

        if own_piece_targets:
            legal_moves &= ~own_piece_targets

        # Handle promotion
        promotion_rank = {
            Color.WHITE: Rank.hex8,
            Color.BLACK: Rank.hex1
        }

        if moving_to_square & promotion_rank[self.color_to_move]:
            move.is_promotion = True

        return legal_moves & moving_to_square
Esempio n. 6
0
    def __init__(self):

        # white piece groups
        self.white_R_bb = make_uint64()
        self.white_K_bb = make_uint64()
        self.white_B_bb = make_uint64()
        self.white_P_bb = make_uint64()
        self.white_N_bb = make_uint64()
        self.white_Q_bb = make_uint64()

        # black piece groups
        self.black_R_bb = make_uint64()
        self.black_K_bb = make_uint64()
        self.black_B_bb = make_uint64()
        self.black_P_bb = make_uint64()
        self.black_N_bb = make_uint64()
        self.black_Q_bb = make_uint64()

        self.init_pieces()

        # static bitboards
        self.knight_attack_bbs = make_knight_attack_bbs()
        self.bishop_attack_bbs = make_diag_attack_bbs()
        self.king_attack_bbs = make_king_attack_bbs()
        self.rook_attack_bbs = make_rook_attack_bbs()
        self.queen_attack_bbs = make_queen_attack_bbs()

        self.white_pawn_attack_bbs = make_white_pawn_attack_bbs()
        self.black_pawn_attack_bbs = make_black_pawn_attack_bbs()
        self.white_pawn_motion_bbs = make_white_pawn_motion_bbs()
        self.black_pawn_motion_bbs = make_black_pawn_motion_bbs()