namespace {
-// next_attacker() is an helper function used by see() to locate the least
+// min_attacker() is an helper function used by see() to locate the least
// valuable attacker for the side to move, remove the attacker we just found
-// from the 'occupied' bitboard and scan for new X-ray attacks behind it.
+// from the bitboards and scan for new X-ray attacks behind it.
template<int Pt> FORCE_INLINE
-PieceType next_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers,
- Bitboard& occupied, Bitboard& attackers) {
+PieceType min_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers,
+ Bitboard& occupied, Bitboard& attackers) {
- if (stmAttackers & bb[Pt])
- {
- Bitboard b = stmAttackers & bb[Pt];
- occupied ^= b & ~(b - 1);
+ Bitboard b = stmAttackers & bb[Pt];
+ if (!b)
+ return min_attacker<Pt+1>(bb, to, stmAttackers, occupied, attackers);
- if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN)
- attackers |= attacks_bb<BISHOP>(to, occupied) & (bb[BISHOP] | bb[QUEEN]);
+ occupied ^= b & ~(b - 1);
- if (Pt == ROOK || Pt == QUEEN)
- attackers |= attacks_bb<ROOK>(to, occupied) & (bb[ROOK] | bb[QUEEN]);
+ if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN)
+ attackers |= attacks_bb<BISHOP>(to, occupied) & (bb[BISHOP] | bb[QUEEN]);
- return (PieceType)Pt;
- }
- return next_attacker<Pt+1>(bb, to, stmAttackers, occupied, attackers);
+ if (Pt == ROOK || Pt == QUEEN)
+ attackers |= attacks_bb<ROOK>(to, occupied) & (bb[ROOK] | bb[QUEEN]);
+
+ attackers &= occupied; // After X-ray that may add already processed pieces
+ return (PieceType)Pt;
}
template<> FORCE_INLINE
-PieceType next_attacker<KING>(const Bitboard*, const Square&, const Bitboard&, Bitboard&, Bitboard&) {
+PieceType min_attacker<KING>(const Bitboard*, const Square&, const Bitboard&, Bitboard&, Bitboard&) {
return KING; // No need to update bitboards, it is the last cycle
}
Position& Position::operator=(const Position& pos) {
- memcpy(this, &pos, sizeof(Position));
+ std::memcpy(this, &pos, sizeof(Position));
startState = *st;
st = &startState;
nodes = 0;
}
-/// Position:hidden_checkers<>() returns a bitboard of all pinned (against the
-/// king) pieces for the given color. Or, when template parameter FindPinned is
-/// false, the function return the pieces of the given color candidate for a
-/// discovery check against the enemy king.
-template<bool FindPinned>
-Bitboard Position::hidden_checkers() const {
+/// Position:hidden_checkers() returns a bitboard of all pinned / discovery check
+/// pieces, according to the call parameters. Pinned pieces protect our king,
+/// discovery check pieces attack the enemy king.
+
+Bitboard Position::hidden_checkers(Square ksq, Color c) const {
- // Pinned pieces protect our king, dicovery checks attack the enemy king
- Bitboard b, result = 0;
- Bitboard pinners = pieces(FindPinned ? ~sideToMove : sideToMove);
- Square ksq = king_square(FindPinned ? sideToMove : ~sideToMove);
+ Bitboard b, pinners, result = 0;
- // Pinners are sliders, that give check when candidate pinned is removed
- pinners &= (pieces(ROOK, QUEEN) & PseudoAttacks[ROOK][ksq])
- | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq]);
+ // Pinners are sliders that give check when pinned piece is removed
+ pinners = ( (pieces( ROOK, QUEEN) & PseudoAttacks[ROOK ][ksq])
+ | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq])) & pieces(c);
while (pinners)
{
b = between_bb(ksq, pop_lsb(&pinners)) & pieces();
- if (b && !more_than_one(b) && (b & pieces(sideToMove)))
- result |= b;
+ if (!more_than_one(b))
+ result |= b & pieces(sideToMove);
}
return result;
}
-// Explicit template instantiations
-template Bitboard Position::hidden_checkers<true>() const;
-template Bitboard Position::hidden_checkers<false>() const;
-
/// Position::attackers_to() computes a bitboard of all pieces which attack a
/// given square. Slider attacks use occ bitboard as occupancy.
return false;
// The destination square cannot be occupied by a friendly piece
- if (piece_on(to) != NO_PIECE && color_of(piece_on(to)) == us)
+ if (pieces(us) & to)
return false;
// Handle the special case of a pawn move
Square rfrom = to; // 'King captures the rook' notation
Square kto = relative_square(us, rfrom > kfrom ? SQ_G1 : SQ_C1);
Square rto = relative_square(us, rfrom > kfrom ? SQ_F1 : SQ_D1);
- Bitboard b = (pieces() ^ kfrom ^ rfrom) | rto | kto;
- return attacks_bb<ROOK>(rto, b) & ksq;
+ return (PseudoAttacks[ROOK][rto] & ksq)
+ && (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & ksq);
}
default:
assert(false);
// Copy some fields of old state to our new StateInfo object except the ones
// which are going to be recalculated from scratch anyway, then switch our state
// pointer to point to the new, ready to be updated, state.
- memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t));
+ std::memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t));
newSt.previous = st;
st = &newSt;
assert(!checkers());
- memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy here
+ std::memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy here
newSt.previous = st;
st = &newSt;
// Early return if SEE cannot be negative because captured piece value
// is not less then capturing one. Note that king moves always return
// here because king midgame value is set to 0.
- if (PieceValue[MG][piece_on(to_sq(m))] >= PieceValue[MG][piece_moved(m)])
+ if (PieceValue[MG][piece_moved(m)] <= PieceValue[MG][piece_on(to_sq(m))])
return 1;
return see(m);
from = from_sq(m);
to = to_sq(m);
- captured = type_of(piece_on(to));
+ swapList[0] = PieceValue[MG][type_of(piece_on(to))];
+ stm = color_of(piece_on(from));
occupied = pieces() ^ from;
- // Handle en passant moves
+ // Castle moves are implemented as king capturing the rook so cannot be
+ // handled correctly. Simply return 0 that is always the correct value
+ // unless in the rare case the rook ends up under attack.
+ if (type_of(m) == CASTLE)
+ return 0;
+
if (type_of(m) == ENPASSANT)
{
- Square capQq = to - pawn_push(sideToMove);
-
- assert(!captured);
- assert(type_of(piece_on(capQq)) == PAWN);
-
- // Remove the captured pawn
- occupied ^= capQq;
- captured = PAWN;
+ occupied ^= to - pawn_push(stm); // Remove the captured pawn
+ swapList[0] = PieceValue[MG][PAWN];
}
- else if (type_of(m) == CASTLE)
- // Castle moves are implemented as king capturing the rook so cannot be
- // handled correctly. Simply return 0 that is always the correct value
- // unless the rook is ends up under attack.
- return 0;
// Find all attackers to the destination square, with the moving piece
// removed, but possibly an X-ray attacker added behind it.
- attackers = attackers_to(to, occupied);
+ attackers = attackers_to(to, occupied) & occupied;
// If the opponent has no attackers we are finished
- stm = ~color_of(piece_on(from));
+ stm = ~stm;
stmAttackers = attackers & pieces(stm);
if (!stmAttackers)
- return PieceValue[MG][captured];
+ 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
// 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.
- swapList[0] = PieceValue[MG][captured];
captured = type_of(piece_on(from));
do {
swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured];
slIndex++;
- // Locate and remove from 'occupied' the next least valuable attacker
- captured = next_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
-
- attackers &= occupied; // Remove the just found attacker
+ // Locate and remove the next least valuable attacker
+ captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
stm = ~stm;
stmAttackers = attackers & pieces(stm);
- if (captured == KING)
+ // Stop before processing a king capture
+ if (captured == KING && stmAttackers)
{
- // Stop before processing a king capture
- if (stmAttackers)
- swapList[slIndex++] = QueenValueMg * 16;
-
+ swapList[slIndex++] = QueenValueMg * 16;
break;
}
void Position::clear() {
- memset(this, 0, sizeof(Position));
+ std::memset(this, 0, sizeof(Position));
startState.epSquare = SQ_NONE;
st = &startState;