template<bool FindPinned>
Bitboard Position::hidden_checkers(Color c) const {
- Bitboard pinners, result = EmptyBoardBB;
+ Bitboard result = EmptyBoardBB;
+ Bitboard pinners = pieces_of_color(FindPinned ? opposite_color(c) : c);
// Pinned pieces protect our king, dicovery checks attack
// the enemy king.
Square ksq = king_square(FindPinned ? c : opposite_color(c));
- // Pinners are sliders, not checkers, that give check when
- // candidate pinned is removed.
- pinners = (pieces(ROOK, QUEEN, FindPinned ? opposite_color(c) : c) & RookPseudoAttacks[ksq])
- | (pieces(BISHOP, QUEEN, FindPinned ? opposite_color(c) : c) & BishopPseudoAttacks[ksq]);
+ // Pinners are sliders, not checkers, that give check when candidate pinned is removed
+ pinners &= (pieces(ROOK, QUEEN) & RookPseudoAttacks[ksq]) | (pieces(BISHOP, QUEEN) & BishopPseudoAttacks[ksq]);
if (FindPinned && pinners)
pinners &= ~st->checkersBB;
bool Position::move_is_check(Move m, const CheckInfo& ci) const {
- Bitboard dcCandidates = ci.dcCandidates;
-
assert(is_ok());
assert(move_is_ok(m));
- assert(dcCandidates == discovered_check_candidates(side_to_move()));
+ assert(ci.dcCandidates == discovered_check_candidates(side_to_move()));
+ assert(color_of_piece_on(move_from(m)) == side_to_move());
+ assert(piece_on(ci.ksq) == piece_of_color_and_type(opposite_color(side_to_move()), KING));
- Color us = side_to_move();
- Color them = opposite_color(us);
Square from = move_from(m);
Square to = move_to(m);
- Square ksq = king_square(them);
+ PieceType pt = type_of_piece_on(from);
- assert(color_of_piece_on(from) == us);
- assert(piece_on(ksq) == piece_of_color_and_type(them, KING));
+ // Direct check ?
+ if (bit_is_set(ci.checkSq[pt], to))
+ return true;
- // Proceed according to the type of the moving piece
- switch (type_of_piece_on(from))
+ // Discovery check ?
+ if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from))
{
- case PAWN:
-
- if (bit_is_set(attacks_from<PAWN>(ksq, them), to)) // Normal check?
- return true;
-
- if ( dcCandidates // Discovered check?
- && bit_is_set(dcCandidates, from)
- && (direction_between_squares(from, ksq) != direction_between_squares(to, ksq)))
+ // For pawn and king moves we need to verify also direction
+ if ( (pt != PAWN && pt != KING)
+ ||(direction_between_squares(from, ci.ksq) != direction_between_squares(to, ci.ksq)))
return true;
+ }
- if (move_is_promotion(m)) // Promotion with check?
- {
- Bitboard b = occupied_squares();
- clear_bit(&b, from);
-
- switch (move_promotion_piece(m))
- {
- case KNIGHT:
- return bit_is_set(attacks_from<KNIGHT>(to), ksq);
- case BISHOP:
- return bit_is_set(bishop_attacks_bb(to, b), ksq);
- case ROOK:
- return bit_is_set(rook_attacks_bb(to, b), ksq);
- case QUEEN:
- return bit_is_set(queen_attacks_bb(to, b), ksq);
- default:
- assert(false);
- }
- }
- // En passant capture with check? We have already handled the case
- // of direct checks and ordinary discovered check, the only case we
- // need to handle is the unusual case of a discovered check through the
- // captured pawn.
- else if (move_is_ep(m))
- {
- Square capsq = make_square(square_file(to), square_rank(from));
- Bitboard b = occupied_squares();
- clear_bit(&b, from);
- clear_bit(&b, capsq);
- set_bit(&b, to);
- return (rook_attacks_bb(ksq, b) & pieces(ROOK, QUEEN, us))
- ||(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, us));
- }
+ // Can we skip the ugly special cases ?
+ if (!move_is_special(m))
return false;
- // Test discovered check and normal check according to piece type
- case KNIGHT:
- return (dcCandidates && bit_is_set(dcCandidates, from))
- || bit_is_set(attacks_from<KNIGHT>(ksq), to);
-
- case BISHOP:
- return (dcCandidates && bit_is_set(dcCandidates, from))
- || (direction_is_diagonal(ksq, to) && bit_is_set(attacks_from<BISHOP>(ksq), to));
-
- case ROOK:
- return (dcCandidates && bit_is_set(dcCandidates, from))
- || (direction_is_straight(ksq, to) && bit_is_set(attacks_from<ROOK>(ksq), to));
-
- case QUEEN:
- // Discovered checks are impossible!
- assert(!bit_is_set(dcCandidates, from));
- return ( (direction_is_straight(ksq, to) && bit_is_set(attacks_from<ROOK>(ksq), to))
- || (direction_is_diagonal(ksq, to) && bit_is_set(attacks_from<BISHOP>(ksq), to)));
-
- case KING:
- // Discovered check?
- if ( bit_is_set(dcCandidates, from)
- && (direction_between_squares(from, ksq) != direction_between_squares(to, ksq)))
- return true;
+ Color us = side_to_move();
+ Bitboard b = occupied_squares();
- // Castling with check?
- if (move_is_castle(m))
- {
- Square kfrom, kto, rfrom, rto;
- Bitboard b = occupied_squares();
- kfrom = from;
- rfrom = to;
+ // Promotion with check ?
+ if (move_is_promotion(m))
+ {
+ clear_bit(&b, from);
- if (rfrom > kfrom)
- {
- kto = relative_square(us, SQ_G1);
- rto = relative_square(us, SQ_F1);
- } else {
- kto = relative_square(us, SQ_C1);
- rto = relative_square(us, SQ_D1);
- }
- clear_bit(&b, kfrom);
- clear_bit(&b, rfrom);
- set_bit(&b, rto);
- set_bit(&b, kto);
- return bit_is_set(rook_attacks_bb(rto, b), ksq);
+ switch (move_promotion_piece(m))
+ {
+ case KNIGHT:
+ return bit_is_set(attacks_from<KNIGHT>(to), ci.ksq);
+ case BISHOP:
+ return bit_is_set(bishop_attacks_bb(to, b), ci.ksq);
+ case ROOK:
+ return bit_is_set(rook_attacks_bb(to, b), ci.ksq);
+ case QUEEN:
+ return bit_is_set(queen_attacks_bb(to, b), ci.ksq);
+ default:
+ assert(false);
}
- return false;
-
- default: // NO_PIECE_TYPE
- break;
}
- assert(false);
- return false;
-}
-
-
-/// Position::update_checkers() udpates chekers info given the move. It is called
-/// in do_move() and is faster then find_checkers().
-
-template<PieceType Piece>
-inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square from,
- Square to, Bitboard dcCandidates) {
-
- const bool Bishop = (Piece == QUEEN || Piece == BISHOP);
- const bool Rook = (Piece == QUEEN || Piece == ROOK);
- const bool Slider = Bishop || Rook;
-
- // Direct checks
- if ( ( (Bishop && bit_is_set(BishopPseudoAttacks[ksq], to))
- || (Rook && bit_is_set(RookPseudoAttacks[ksq], to)))
- && bit_is_set(attacks_from<Piece>(ksq), to)) // slow, try to early skip
- set_bit(pCheckersBB, to);
- else if ( Piece != KING
- && !Slider
- && bit_is_set(Piece == PAWN ? attacks_from<PAWN>(ksq, opposite_color(sideToMove))
- : attacks_from<Piece>(ksq), to))
- set_bit(pCheckersBB, to);
+ // En passant capture with check? We have already handled the case
+ // of direct checks and ordinary discovered check, the only case we
+ // need to handle is the unusual case of a discovered check through the
+ // captured pawn.
+ if (move_is_ep(m))
+ {
+ Square capsq = make_square(square_file(to), square_rank(from));
+ clear_bit(&b, from);
+ clear_bit(&b, capsq);
+ set_bit(&b, to);
+ return (rook_attacks_bb(ci.ksq, b) & pieces(ROOK, QUEEN, us))
+ ||(bishop_attacks_bb(ci.ksq, b) & pieces(BISHOP, QUEEN, us));
+ }
- // Discovery checks
- if (Piece != QUEEN && bit_is_set(dcCandidates, from))
+ // Castling with check ?
+ if (move_is_castle(m))
{
- if (Piece != ROOK)
- (*pCheckersBB) |= (attacks_from<ROOK>(ksq) & pieces(ROOK, QUEEN, side_to_move()));
+ Square kfrom, kto, rfrom, rto;
+ kfrom = from;
+ rfrom = to;
- if (Piece != BISHOP)
- (*pCheckersBB) |= (attacks_from<BISHOP>(ksq) & pieces(BISHOP, QUEEN, side_to_move()));
+ if (rfrom > kfrom)
+ {
+ kto = relative_square(us, SQ_G1);
+ rto = relative_square(us, SQ_F1);
+ } else {
+ kto = relative_square(us, SQ_C1);
+ rto = relative_square(us, SQ_D1);
+ }
+ clear_bit(&b, kfrom);
+ clear_bit(&b, rfrom);
+ set_bit(&b, rto);
+ set_bit(&b, kto);
+ return bit_is_set(rook_attacks_bb(rto, b), ci.ksq);
}
+
+ return false;
}
void Position::do_move(Move m, StateInfo& newSt) {
- do_move(m, newSt, discovered_check_candidates(side_to_move()));
+ CheckInfo ci(*this);
+ do_move(m, newSt, ci, move_is_check(m, ci));
}
-void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
+void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) {
assert(is_ok());
assert(move_is_ok(m));
st->key = key;
// Update checkers bitboard, piece must be already moved
- if (ep | pm)
- st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us);
- else
+ st->checkersBB = EmptyBoardBB;
+
+ if (moveIsCheck)
{
- st->checkersBB = EmptyBoardBB;
- Square ksq = king_square(them);
- switch (pt)
+ if (ep | pm)
+ st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us);
+ else
{
- case PAWN: update_checkers<PAWN>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
- case KNIGHT: update_checkers<KNIGHT>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
- case BISHOP: update_checkers<BISHOP>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
- case ROOK: update_checkers<ROOK>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
- case QUEEN: update_checkers<QUEEN>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
- case KING: update_checkers<KING>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
- default: assert(false); break;
+ // Direct checks
+ if (bit_is_set(ci.checkSq[pt], to))
+ st->checkersBB = SetMaskBB[to];
+
+ // Discovery checks
+ if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from))
+ {
+ if (pt != ROOK)
+ st->checkersBB |= (attacks_from<ROOK>(ci.ksq) & pieces(ROOK, QUEEN, us));
+
+ if (pt != BISHOP)
+ st->checkersBB |= (attacks_from<BISHOP>(ci.ksq) & pieces(BISHOP, QUEEN, us));
+ }
}
}