void Position::set_check_info(StateInfo* si) const {
- si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE));
- si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK));
+ si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), si->pinnersForKing[WHITE]);
+ si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si->pinnersForKing[BLACK]);
Square ksq = square<KING>(~sideToMove);
}
-/// Position::slider_blockers() returns a bitboard of all the pieces (both colors) that
-/// are blocking attacks on the square 's' from 'sliders'. A piece blocks a slider
-/// if removing that piece from the board would result in a position where square 's'
-/// is attacked. For example, a king-attack blocking piece can be either a pinned or
-/// a discovered check piece, according if its color is the opposite or the same of
-/// the color of the slider.
+/// Position::slider_blockers() returns a bitboard of all the pieces (both colors)
+/// that are blocking attacks on the square 's' from 'sliders'. A piece blocks a
+/// slider if removing that piece from the board would result in a position where
+/// square 's' is attacked. For example, a king-attack blocking piece can be either
+/// a pinned or a discovered check piece, according if its color is the opposite
+/// or the same of the color of the slider. The pinners bitboard get filled with
+/// real and potential pinners.
-Bitboard Position::slider_blockers(Bitboard sliders, Square s) const {
+Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const {
- Bitboard b, pinners, result = 0;
+ Bitboard b, p, result = 0;
// Pinners are sliders that attack 's' when a pinned piece is removed
- pinners = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
- | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
+ pinners = p = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
+ | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
- while (pinners)
+ while (p)
{
- b = between_bb(s, pop_lsb(&pinners)) & pieces();
+ b = between_bb(s, pop_lsb(&p)) & pieces();
if (!more_than_one(b))
result |= b;
if (!stmAttackers)
return swapList[0];
+ // Don't allow pinned pieces to attack as long all pinners (this includes also
+ // potential ones) are on their original square. When a pinner moves to the
+ // exchange-square or get captured on it, we fall back to standard SEE behaviour.
+ else if ( (stmAttackers & st->blockersForKing[stm])
+ && ((st->pinnersForKing[stm] & (occupied ^ (occupied & to))) == st->pinnersForKing[stm]))
+ {
+ // Pinned pieces can't attack so remove them from attackers
+ stmAttackers ^= (stmAttackers & st->blockersForKing[stm]);
+ if (!stmAttackers)
+ return swapList[0];
+ }
+
// The destination square is defended, which makes things rather more
// difficult to compute. We proceed by building up a "swap list" containing
// the material gain or loss at each stop in a sequence of captures to the
captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
stm = ~stm;
stmAttackers = attackers & pieces(stm);
+ if ( stmAttackers
+ && (stmAttackers & st->blockersForKing[stm])
+ && ((st->pinnersForKing[stm] & (occupied ^ (occupied & to))) == st->pinnersForKing[stm]))
+ stmAttackers ^= (stmAttackers & st->blockersForKing[stm]);
+
++slIndex;
} while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture