5

I'm currently working on a chess engine and have a pseudo-legal move generator working. I'm looking for a way to efficiently generate a bitboard of pinned pieces, so I could skip them when generating legal moves. How would one go about doing this, given 12 bitboards for each piece, and a bitboard called UNSAFE with all the squares the opponent is threatening?

3
  • 1
    All the answers below are probably correct but I can tell you that if you want a strong engine, you are looking in the wrong place. I am one of the authors of Koivisto (depending on the rating list, somewhere in between the top 4-10 engines in the world). We still use pseudo legal move generation and check if they are legal. move generation, compared to evaluation, move ordering etc. is almost insignificant. Commented Nov 27, 2021 at 21:56
  • Hi Finn! It's great hearing from you - I've been a fan ever since your neural networks tutorial on youtube :) Koivisto is really doing great recently - what was the change that brought you up from 3407 to 3445 (CCRL 40/15)? Thank you for the information - I ended up doing something similar to that, but I'm only testing certain moves for legality (when in check, en passant, moving a pinned piece, and when the king moves)
    – Ori Yonay
    Commented Nov 29, 2021 at 21:18
  • That makes me happy to hear. I assume you mean the difference between 6.0 and 7.0. most of it comes from slight search adjustments. We also retrained a new network with more data and a different architecture. You can also add me on Discord if you have more questions :) (Luecx#0540) Commented Nov 30, 2021 at 6:05

2 Answers 2

6

This task is nontrivial and cannot be obtained easily or setwise from the available bitboards.

The following solution is an example for how such a task might be done for a generic slider - only obvious substitutions are necessary to convert this code to be usable for bishops, rooks and queens.

First, identify the set of possible pinning pieces by calculating sliding attacks from the king square, using the opposite side as the set of occupied squares.

BitBoard bb_pinners = slider_moves(king_square, bb_other_side) & bb_other_side;

All bitboard engines should have some function similar to bishop_moves or rook_moves, which uses magic bitboards, PEXT or Koch-Stone to generate sliding moves from a square, given a bitboard of occupied squares as blockers to the slider.

To determine the set of pinned pieces from the set of pinners, it is necessary to iterate through the set of possible pinners (this is why pinned pieces cannot be calculated setwise).

For each pinner, we consider the set of bits between the pinner square and the king square (using the utility function between), determine if there is only one bit set, and if so, add that bit to the set of pinned pieces.

BitBoard bb_pinned = 0;
while(bb_pinners) {
    Square sq = pop_bit(bb_pinners);
    BitBoard bb_possible_pinned = between(sq, king_square) & bb_own_side;
    if(only_one_bit(bb_possible_pinned)) {
        bb_pinned |= bb_possible_pinned;
    }
}

Here, pop_bit finds the index of and removes the least significant bit of bb_pinners.

Stockfish implements a similar strategy in slider_blockers to determine possibly pinned pieces.

It is also worth mentioning that even with a set of these blockers, this does not mean that they may be excluded from legal move generation because if the pinned piece is a slider itself of the correct type, it may still have legal moves despite being pinned, under the above algorithm's definition.

2

Pinned pieces only exist when attackers are sliding pieces (bishop, rook, queen). Also pinned pieces can move along the attack ray to the king, you cannot exclude them from legal moves directly. For example, the rook can move d4 and d6 in the board image below and the pawn can do enpassant in the 2nd example. You can check all 8 directions N, W, E, S, NW, NE, SW, SE to get all pinned pieces.

A piece is pinned if it suits the rules below.

  • It is a friend piece
  • It is the closest piece to the friend king placed on the path from king to the end of the board on specific direction (NORTH, SOUTH-EAST etc.)
  • The second closest piece after the friend is the enemy and can attack along the direction to the king. Rook and queen for the N-S-W-E. Bishop and queen for NW-NE-SW-SE.
  • UnpinnedMoves = Pseudolegalmoves(pinned_piece) & PathFromKingToTheEnemy

For example I have shared my code to find the pinned piece on the NORTH. A8 is LSB and H1 is MSB in my bitboard. You can change BitScanReverse() into BitScanForward() according to your bitboard design and direction that is checking for pinned piece. (for south it must be BitScanForward() in my code)

enter image description here

enter image description here

public static ulong Pinned_NORTH(ulong king_loc, ulong friendPieces, ulong allPieces, ulong rookEnemies, ulong queenEnemies)
{
    //Gets all vertical sliding enemies
    ulong straightSlidingEnemies = rookEnemies | queenEnemies;

    //if no rook or queen enemies exist, there is no pinned piece
    if(straightSlidingEnemies == 0)
       return 0;

    //get all squares on the North side of the king
    ulong northSquares= CrossLookup.NORTH[king_loc];

    //get intersected pieces at the north side of the king, rook and queen in the example
    ulong intersectedPieces = northSquares& allPieces;

    //get closest piece to the king in intersectedPieces, rook in the example
    ulong closestPiece = intersectedPieces.BitScanReverse();

    //check if the closest piece is our friend
    ulong friend = closestPiece & friendPieces;

    //if it is ENEMY, there cannot be a pinned piece in the NORTH
    if (friend == 0)
        return 0;

    //Get second closest piece and check if it is an enemy that is a rook or a queen who can attack from the NORTH
    ulong slidingEnemy = (intersectedPieces & ~closestPiece ).BitScanReverse() & straightSlidingEnemies ;

    //if it is NOT A SLIDING ENEMY, there cannot be a pinned piece in the NORTH
    if (slidingEnemy == 0)
        return 0;
    
    //Otherwise closest piece is a pinned piece and can only move along the ray from king to the enemy
    return friend;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.