Example #1
0
def king_safety(board: Board):
    wpieces = board.occupied_co[WHITE]
    bpieces = board.occupied_co[BLACK]
    wkingloc = lsb(board.kings & wpieces)
    bkingloc = lsb(board.kings & bpieces)
    safety: float = 0
    safety += sum(
        chess.square_distance(bkingloc, sq) * 2
        for sq in scan_forward(board.queens & wpieces))
    safety -= sum(
        chess.square_distance(wkingloc, sq) * 2
        for sq in scan_forward(board.queens & bpieces))
    safety += sum(
        chess.square_distance(bkingloc, sq) / 2
        for sq in scan_forward(board.bishops & wpieces))
    safety -= sum(
        chess.square_distance(wkingloc, sq) / 2
        for sq in scan_forward(board.bishops & bpieces))
    safety += sum(
        chess.square_distance(bkingloc, sq) / 2
        for sq in scan_forward(board.rooks & wpieces))
    safety -= sum(
        chess.square_distance(wkingloc, sq) / 2
        for sq in scan_forward(board.rooks & bpieces))
    safety += sum(
        chess.square_distance(bkingloc, sq)
        for sq in scan_forward(board.knights & wpieces))
    safety -= sum(
        chess.square_distance(wkingloc, sq)
        for sq in scan_forward(board.knights & bpieces))
    return safety
Example #2
0
def execute(position):
    board = chess.Board(fen=position)
    white_running_total = 0
    for i in chess.scan_forward(board.occupied_co[True]):
        white_running_total += sum(
            list(map(int,
                     bin(board.attackers_mask(True, i))[2:])))

    black_running_total = 0
    for i in chess.scan_forward(board.occupied_co[False]):
        black_running_total += sum(
            list(map(int,
                     bin(board.attackers_mask(False, i))[2:])))

    return (black_running_total, white_running_total)
Example #3
0
    def _locked_pawns(fen):
        """
        A pawn is locked iff. it cannot move forward because opponent's pawn occupy the square in front and cannot move
        diagonally, i.e. make a capture, because no such capture is available, regardless of whose turn is it.
        """

        board = chess.Board(fen)
        board_opposite_turn = board.copy()
        board_opposite_turn.turn = not board.turn

        locked_pawns = set()
        for square in chess.scan_forward(board.pawns):
            color = board.piece_at(square).color
            square_in_front = square + 8 if color == chess.WHITE else square - 8
            if not (0 <= square_in_front < 64):
                continue
            piece_in_front = board.piece_at(square_in_front)
            from_mask = chess.BB_SQUARES[square]
            if (piece_in_front is not None
                    and piece_in_front.piece_type == chess.PAWN
                    and piece_in_front.color != color
                    and not list(board.generate_legal_captures(from_mask))
                    and not list(
                        board_opposite_turn.generate_legal_captures(from_mask))
                ):
                locked_pawns.add(square)
        return locked_pawns
Example #4
0
    def _attacked_for_king(self, path, occupied):
        # Can castle onto attacked squares if they are connected to the
        # enemy king.
        enemy_kings = self.kings & self.occupied_co[not self.turn]
        for enemy_king in chess.scan_forward(enemy_kings):
            path &= ~chess.BB_KING_ATTACKS[enemy_king]

        return super()._attacked_for_king(path, occupied)
Example #5
0
def space(board: Board):
    w_area = BB_RANK_1 | BB_RANK_2 | BB_RANK_3 | BB_RANK_4
    b_area = BB_RANK_8 | BB_RANK_7 | BB_RANK_6 | BB_RANK_5
    space = 0
    space -= sum(
        popcount(BB_PAWN_ATTACKS[WHITE][sq] & b_area)
        for sq in scan_forward(board.pawns & board.occupied_co[WHITE]))
    space += sum(
        popcount(BB_PAWN_ATTACKS[BLACK][sq] & w_area)
        for sq in scan_forward(board.pawns & board.occupied_co[BLACK]))
    space -= sum(
        popcount(BB_KNIGHT_ATTACKS[sq] & b_area)
        for sq in scan_forward(board.knights & board.occupied_co[WHITE]))
    space += sum(
        popcount(BB_KNIGHT_ATTACKS[sq] & w_area)
        for sq in scan_forward(board.knights & board.occupied_co[BLACK]))
    return space
Example #6
0
    def _attacked_for_king(self, path, occupied):
        # Can castle onto attacked squares if they are connected to the
        # enemy king.
        enemy_kings = self.kings & self.occupied_co[not self.turn]
        for enemy_king in chess.scan_forward(enemy_kings):
            path &= ~chess.BB_KING_ATTACKS[enemy_king]

        return super(AtomicBoard, self)._attacked_for_king(path, occupied)
Example #7
0
 def generate_pseudo_legal_drops(
         self,
         to_mask: chess.Bitboard = chess.BB_ALL) -> Iterator[chess.Move]:
     for to_square in chess.scan_forward(to_mask & ~self.occupied):
         for pt, count in self.pockets[self.turn].pieces.items():
             if count and (pt != chess.PAWN or not chess.BB_BACKRANKS
                           & chess.BB_SQUARES[to_square]):
                 yield chess.Move(to_square, to_square, drop=pt)
Example #8
0
def piece_attack_counts(board: Board):
    white_pawn_attacks = sum(
        popcount(BB_PAWN_ATTACKS[WHITE][sq] & board.occupied_co[BLACK])
        for sq in scan_forward(board.pawns & board.occupied_co[WHITE]))
    black_pawn_attacks = sum(
        popcount(BB_PAWN_ATTACKS[BLACK][sq] & board.occupied_co[WHITE])
        for sq in scan_forward(board.pawns & board.occupied_co[BLACK]))
    white_knight_attacks = sum(
        popcount(BB_KNIGHT_ATTACKS[sq] & board.occupied_co[BLACK])
        for sq in scan_forward(board.knights & board.occupied_co[WHITE]))
    black_knight_attacks = sum(
        popcount(BB_KNIGHT_ATTACKS[sq] & board.occupied_co[WHITE])
        for sq in scan_forward(board.knights & board.occupied_co[BLACK]))
    white_bishop_attacks = sum(
        popcount(
            board.attacks_mask(sq) & board.occupied_co[BLACK]
            & (board.kings | board.queens | board.rooks))
        for sq in scan_forward(board.bishops & board.occupied_co[WHITE]))
    black_bishop_attacks = sum(
        popcount(
            board.attacks_mask(sq) & board.occupied_co[WHITE]
            & (board.kings | board.queens | board.rooks))
        for sq in scan_forward(board.bishops & board.occupied_co[BLACK]))
    white_rook_attacks = sum(
        popcount(
            board.attacks_mask(sq) & board.occupied_co[BLACK]
            & (board.kings | board.queens))
        for sq in scan_forward(board.bishops & board.occupied_co[WHITE]))
    black_rook_attacks = sum(
        popcount(
            board.attacks_mask(sq) & board.occupied_co[WHITE]
            & (board.kings | board.queens))
        for sq in scan_forward(board.bishops & board.occupied_co[BLACK]))
    white_queen_attacks = sum(
        popcount(
            board.attacks_mask(sq) & board.occupied_co[BLACK] & board.kings)
        for sq in scan_forward(board.bishops & board.occupied_co[WHITE]))
    black_queen_attacks = sum(
        popcount(
            board.attacks_mask(sq) & board.occupied_co[WHITE] & board.kings)
        for sq in scan_forward(board.bishops & board.occupied_co[BLACK]))
    black = black_pawn_attacks + black_knight_attacks + black_bishop_attacks + black_rook_attacks + black_queen_attacks
    white = white_pawn_attacks + white_knight_attacks + white_bishop_attacks + white_rook_attacks + white_queen_attacks
    return black - white
Example #9
0
    def apply(self, vec, board, move):
        """ Should be called prior to pushing move to board.
            Applies the move to the vector. """

        # Remove from square.
        piece_type = board.piece_type_at(move.from_square)
        color = board.turn
        vec -= self.piece_to_vec[piece_type, color, move.from_square]

        # Update castling rights.
        old_castling_rights = board.clean_castling_rights()
        new_castling_rights = old_castling_rights & ~chess.BB_SQUARES[
            move.to_square] & ~chess.BB_SQUARES[move.from_square]
        if piece_type == chess.KING:
            new_castling_rights &= ~chess.BB_RANK_1 if color else ~chess.BB_RANK_8
        # Castling rights can only have been removed
        for sq in chess.scan_forward(old_castling_rights
                                     ^ new_castling_rights):
            vec -= self.castling[sq]

        # Remove pawns captured en passant.
        if piece_type == chess.PAWN and move.to_square == board.ep_square:
            down = -8 if board.turn == chess.WHITE else 8
            capture_square = board.ep_square + down
            vec -= self.piece_to_vec[chess.PAWN, not board.turn,
                                     capture_square]

        # Move rook during castling.
        if piece_type == chess.KING:
            if move.from_square == chess.E1:
                if move.to_square == chess.G1:
                    vec -= self.piece_to_vec[chess.ROOK, color, chess.H1]
                    vec += self.piece_to_vec[chess.ROOK, color, chess.F1]
                if move.to_square == chess.C1:
                    vec -= self.piece_to_vec[chess.ROOK, color, chess.A1]
                    vec += self.piece_to_vec[chess.ROOK, color, chess.D1]
            if move.from_square == chess.E8:
                if move.to_square == chess.G8:
                    vec -= self.piece_to_vec[chess.ROOK, color, chess.H8]
                    vec += self.piece_to_vec[chess.ROOK, color, chess.F8]
                if move.to_square == chess.C8:
                    vec -= self.piece_to_vec[chess.ROOK, color, chess.A8]
                    vec += self.piece_to_vec[chess.ROOK, color, chess.D8]

        # Capture
        captured_piece_type = board.piece_type_at(move.to_square)
        if captured_piece_type:
            vec -= self.piece_to_vec[captured_piece_type, not color,
                                     move.to_square]

        # Put the piece on the target square.
        vec += self.piece_to_vec[move.promotion or piece_type, color,
                                 move.to_square]
        return vec
Example #10
0
def getMobilityOfPieces(board, piece_type, color):  # PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING 1-6
    pcs_mask = board.pieces_mask(piece_type, color)  # 返回棋子类型为piece_type的color方棋子的位棋盘
    pcs_position = chess.scan_forward(pcs_mask)
    attack_list = []
    for i in pcs_position:
        atks_mask = board.attacks_mask(i)
        atks_num = chess.popcount(atks_mask)
        overlap_mask = atks_mask & board.occupied_co[color]
        ol_num = chess.popcount(overlap_mask)
        attack_list.append(atks_num - ol_num)
    return attack_list
Example #11
0
    def _push_capture(self, move, capture_square, piece_type, was_promoted):
        # Explode the capturing piece.
        self._remove_piece_at(move.to_square)

        # Explode all non pawns around.
        explosion_radius = chess.BB_KING_ATTACKS[move.to_square] & ~self.pawns
        for explosion in chess.scan_forward(explosion_radius):
            self._remove_piece_at(explosion)

        # Destroy castling rights.
        self.castling_rights &= ~explosion_radius
Example #12
0
    def _push_capture(self, move, capture_square, piece_type, was_promoted):
        # Explode the capturing piece.
        self._remove_piece_at(move.to_square)

        # Explode all non pawns around.
        explosion_radius = chess.BB_KING_ATTACKS[move.to_square] & ~self.pawns
        for explosion in chess.scan_forward(explosion_radius):
            self._remove_piece_at(explosion)

        # Destroy castling rights.
        self.castling_rights &= ~explosion_radius
Example #13
0
def board_to_words(board, occ=False):
    for s, p in board.piece_map().items():
        yield f'{chess.SQUARE_NAMES[s]}{p.symbol()}'
    if board.castling_rights & chess.BB_H1:
        yield 'H1-C'
    if board.castling_rights & chess.BB_H8:
        yield 'H8-C'
    if board.castling_rights & chess.BB_A1:
        yield 'A1-C'
    if board.castling_rights & chess.BB_A8:
        yield 'A8-C'
    if occ:
        for square in chess.scan_forward(board.occupied):
            yield f'{chess.SQUARE_NAMES[square]}-Occ'
Example #14
0
    def is_variant_end(self) -> bool:
        if not self.kings & chess.BB_RANK_8:
            return False

        black_kings = self.kings & self.occupied_co[chess.BLACK]
        if self.turn == chess.WHITE or black_kings & chess.BB_RANK_8 or not black_kings:
            return True

        # White has reached the backrank. The game is over if black can not
        # also reach the backrank on the next move. Check if there are any
        # safe squares for the king.
        black_king = chess.msb(black_kings)
        targets = chess.BB_KING_ATTACKS[black_king] & chess.BB_RANK_8 & ~self.occupied_co[chess.BLACK]
        return all(self.attackers_mask(chess.WHITE, target) for target in chess.scan_forward(targets))
Example #15
0
 def _generate_pseudo_legal_drops_vp(
     self,
     to_mask: chess.Bitboard = chess.BB_ALL,
     virtual_pocket: Optional[CrazyhousePocket] = None
 ) -> Iterator[chess.Move]:
     pocket = self.pockets[
         self.turn] if virtual_pocket is None else virtual_pocket
     for to_square in chess.scan_forward(to_mask & ~self.occupied):
         for pt, count in pocket.pieces.items():
             if count and (pt != chess.PAWN or not chess.BB_BACKRANKS
                           & chess.BB_SQUARES[to_square]):
                 yield chess.Move(to_square,
                                  to_square,
                                  drop=pt,
                                  board_id=self.board_id)
Example #16
0
    def _push_capture(self, move: chess.Move, capture_square: chess.Square, piece_type: chess.PieceType, was_promoted: bool) -> None:
        explosion_radius = chess.BB_KING_ATTACKS[move.to_square] & ~self.pawns

        # Destroy castling rights.
        self.castling_rights &= ~explosion_radius
        if explosion_radius & self.kings & self.occupied_co[chess.WHITE] & ~self.promoted:
            self.castling_rights &= ~chess.BB_RANK_1
        if explosion_radius & self.kings & self.occupied_co[chess.BLACK] & ~self.promoted:
            self.castling_rights &= ~chess.BB_RANK_8

        # Explode the capturing piece.
        self._remove_piece_at(move.to_square)

        # Explode all non pawns around.
        for explosion in chess.scan_forward(explosion_radius):
            self._remove_piece_at(explosion)
Example #17
0
    def is_variant_end(self):
        if not self.kings & chess.BB_RANK_8:
            return False

        if self.turn == chess.WHITE or self.kings & self.occupied_co[chess.BLACK] & chess.BB_RANK_8:
            return True

        black_kings = self.kings & self.occupied_co[chess.BLACK]
        if not black_kings:
            return True

        black_king = chess.msb(black_kings)

        # White has reached the backrank. The game is over if black can not
        # also reach the backrank on the next move. Check if there are any
        # safe squares for the king.
        targets = chess.BB_KING_ATTACKS[black_king] & chess.BB_RANK_8
        return all(self.attackers_mask(chess.WHITE, target) for target in chess.scan_forward(targets))
Example #18
0
    def get_pieces_positions_by_type(self,
                                     piece_type: str,
                                     color: str = None) -> list:
        """Parse the bitboard representation to get pieces positions on the board

        Args:
            piece_type (str): the name of the piece in uppercase
            color (str, optional): WHITE or BLACK. Defaults to None.

        Raises:
            Exception: if the name of the piece is not recognized (practical to debug)

        Returns:
            list: The position (between 0 and 63) of the piece type selected
        """

        # Prepare binary representation of pieces
        piece_type = piece_type.upper()
        if piece_type == "BISHOP":
            pieces = self.bishops
        elif piece_type == "PAWN":
            pieces = self.pawns
        elif piece_type == "ROOK":
            pieces = self.rooks
        elif piece_type == "KNIGHT":
            pieces = self.knights
        elif piece_type == "QUEEN":
            pieces = self.queens
        elif piece_type == "KING":
            pieces = self.kings
        else:
            raise Exception(f"Piece type {piece_type} is not among {PIECES}")

        # Prepare binary color mask
        if color is None:
            mask = self.occupied
        else:
            if isinstance(color, str):
                color = 0 if color.upper() == "WHITE" else 1
            mask = self.occupied_co[1 - color]

        return list(scan_forward(pieces & mask))
Example #19
0
 def _kings_connected(self) -> bool:
     white_kings = self.kings & self.occupied_co[chess.WHITE]
     black_kings = self.kings & self.occupied_co[chess.BLACK]
     return any(chess.BB_KING_ATTACKS[sq] & black_kings
                for sq in chess.scan_forward(white_kings))
Example #20
0
 def generate_pseudo_legal_drops(self, to_mask=chess.BB_ALL):
     for to_square in chess.scan_forward(to_mask & ~self.occupied):
         for pt, count in self.pockets[self.turn].pieces.items():
             if count and (pt != chess.PAWN or not chess.BB_BACKRANKS & chess.BB_SQUARES[to_square]):
                 yield chess.Move(to_square, to_square, drop=pt)
Example #21
0
def pst_eval(board: Board) -> int:
    white = board.occupied_co[WHITE]
    black = board.occupied_co[BLACK]
    return sum(
        chain((mg_pst[p][i] for i in scan_forward(board.pawns & black)),
              (-mg_pst[P][i] for i in scan_forward(board.pawns & white)),
              (mg_pst[n][i] for i in scan_forward(board.knights & black)),
              (-mg_pst[N][i] for i in scan_forward(board.knights & white)),
              (mg_pst[b][i] for i in scan_forward(board.bishops & black)),
              (-mg_pst[B][i] for i in scan_forward(board.bishops & white)),
              (mg_pst[r][i] for i in scan_forward(board.rooks & black)),
              (-mg_pst[R][i] for i in scan_forward(board.rooks & white)),
              (mg_pst[q][i] for i in scan_forward(board.queens & black)),
              (-mg_pst[Q][i] for i in scan_forward(board.queens & white)),
              (mg_pst[k][i] for i in scan_forward(board.kings & black)),
              (-mg_pst[K][i] for i in scan_forward(board.kings & white))))
Example #22
0
 def _kings_connected(self):
     white_kings = self.kings & self.occupied_co[chess.WHITE]
     black_kings = self.kings & self.occupied_co[chess.BLACK]
     return any(chess.BB_KING_ATTACKS[sq] & black_kings for sq in chess.scan_forward(white_kings))