#include <algorithm>
#include <cassert>
-#include <cstring> // For std::memset, std::memcmp
+#include <cstddef> // For offsetof()
+#include <cstring> // For std::memset, std::memcmp
#include <iomanip>
#include <sstream>
using std::string;
+namespace PSQT {
+ extern Score psq[PIECE_NB][SQUARE_NB];
+}
+
namespace Zobrist {
Key psq[PIECE_NB][SQUARE_NB];
/// 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.
+/// or the same of the color of the slider.
Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const {
- Bitboard b, p, result = 0;
+ Bitboard result = 0;
+ pinners = 0;
- // Pinners are sliders that attack 's' when a pinned piece is removed
- pinners = p = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
- | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
+ // Snipers are sliders that attack 's' when a piece is removed
+ Bitboard snipers = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
+ | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
- while (p)
+ while (snipers)
{
- b = between_bb(s, pop_lsb(&p)) & pieces();
-
- if (!more_than_one(b))
- result |= b;
+ Square sniperSq = pop_lsb(&snipers);
+ Bitboard b = between_bb(s, sniperSq) & pieces();
+
+ if (!more_than_one(b))
+ {
+ result |= b;
+ if (b & pieces(color_of(piece_on(s))))
+ pinners |= sniperSq;
+ }
}
return result;
}
Bitboard occupied, attackers, stmAttackers;
Value swapList[32];
int slIndex = 1;
- PieceType captured;
+ PieceType nextVictim;
Color stm;
assert(is_ok(m));
stmAttackers = attackers & pieces(stm);
occupied ^= to; // For the case when captured piece is a pinner
- // 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.
- if ( (stmAttackers & pinned_pieces(stm))
- && (st->pinnersForKing[stm] & occupied) == st->pinnersForKing[stm])
- stmAttackers &= ~pinned_pieces(stm);
+ // Don't allow pinned pieces to attack pieces except the king as long all
+ // pinners are on their original square.
+ if (!(st->pinnersForKing[stm] & ~occupied))
+ stmAttackers &= ~st->blockersForKing[stm];
if (!stmAttackers)
return swapList[0];
// destination square, where the sides alternately capture, and always
// capture with the least valuable piece. After each capture, we look for
// new X-ray attacks from behind the capturing piece.
- captured = type_of(piece_on(from));
+ nextVictim = type_of(piece_on(from));
do {
assert(slIndex < 32);
// Add the new entry to the swap list
- swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured];
+ swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][nextVictim];
// Locate and remove the next least valuable attacker
- captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
+ nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
stm = ~stm;
stmAttackers = attackers & pieces(stm);
- if ( (stmAttackers & pinned_pieces(stm))
- && (st->pinnersForKing[stm] & occupied) == st->pinnersForKing[stm])
- stmAttackers &= ~pinned_pieces(stm);
+
+ // Don't allow pinned pieces to attack pieces except the king
+ if ( nextVictim != KING
+ && !(st->pinnersForKing[stm] & ~occupied))
+ stmAttackers &= ~st->blockersForKing[stm];
++slIndex;
- } while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture
+ } while (stmAttackers && (nextVictim != KING || (--slIndex, false))); // Stop before a king capture
// Having built the swap list, we negamax through it to find the best
// achievable score from the point of view of the side to move.