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
}
string brd = twoRows + twoRows + twoRows + twoRows + dottedLine;
+ for (Bitboard b = pieces(); b; )
+ {
+ Square s = pop_lsb(&b);
+ brd[513 - 68 * rank_of(s) + 4 * file_of(s)] = PieceToChar[piece_on(s)];
+ }
+
std::ostringstream ss;
if (move)
ss << "\nMove: " << (sideToMove == BLACK ? ".." : "")
<< move_to_san(*const_cast<Position*>(this), move);
- for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
- if (piece_on(sq) != NO_PIECE)
- brd[513 - 68*rank_of(sq) + 4*file_of(sq)] = PieceToChar[piece_on(sq)];
-
ss << brd << "\nFen: " << fen() << "\nKey: " << std::hex << std::uppercase
<< std::setfill('0') << std::setw(16) << st->key << "\nCheckers: ";
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
return true;
// Discovery check ?
- if (ci.dcCandidates && (ci.dcCandidates & from))
+ if (unlikely(ci.dcCandidates) && (ci.dcCandidates & from))
{
// For pawn and king moves we need to verify also direction
if ( (pt != PAWN && pt != KING)
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);
// 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;
}