Square to = to_sq(m);
assert(color_of(moved_piece(m)) == us);
- assert(piece_on(square<KING>(us)) == make_piece(us, KING));
+ assert(!count<KING>(us) || piece_on(square<KING>(us)) == make_piece(us, KING));
+ assert(board_bb() & to);
+
+ // Illegal checks
+ if ((!checking_permitted() || (sittuyin_promotion() && type_of(m) == PROMOTION) || (!drop_checks() && type_of(m) == DROP)) && gives_check(m))
+ return false;
+
+ // Illegal quiet moves
+ if (must_capture() && !capture(m) && has_capture())
+ return false;
+
+ // Illegal non-drop moves
+ if (must_drop() && type_of(m) != DROP && count_in_hand(us, var->mustDropType) > 0)
+ {
+ if (checkers())
+ {
+ for (const auto& mevasion : MoveList<EVASIONS>(*this))
+ if (type_of(mevasion) == DROP && legal(mevasion))
+ return false;
+ }
+ else
+ {
+ for (const auto& mquiet : MoveList<QUIETS>(*this))
+ if (type_of(mquiet) == DROP && legal(mquiet))
+ return false;
+ }
+ }
+
+ // Illegal drop move
+ if (drop_opposite_colored_bishop() && type_of(m) == DROP)
+ {
+ if (type_of(moved_piece(m)) != BISHOP)
+ {
+ Bitboard remaining = drop_region(us, BISHOP) & ~pieces() & ~square_bb(to);
+ // Are enough squares available to drop bishops on opposite colors?
+ if ( (!( DarkSquares & pieces(us, BISHOP)) && ( DarkSquares & remaining))
+ + (!(~DarkSquares & pieces(us, BISHOP)) && (~DarkSquares & remaining)) < count_in_hand(us, BISHOP))
+ return false;
+ }
+ else
+ // Drop resulting in same-colored bishops
+ if ((DarkSquares & to ? DarkSquares : ~DarkSquares) & pieces(us, BISHOP))
+ return false;
+ }
+
+ // No legal moves from target square
+ if (immobility_illegal() && (type_of(m) == DROP || type_of(m) == NORMAL) && !(moves_bb(us, type_of(moved_piece(m)), to, 0) & board_bb()))
+ return false;
+
+ // Illegal king passing move
+ if (pass_on_stalemate() && is_pass(m) && !checkers())
+ {
+ for (const auto& move : MoveList<NON_EVASIONS>(*this))
+ if (!is_pass(move) && legal(move))
+ return false;
+ }
+
+ // Check for attacks to pseudo-royal pieces
+ if (var->extinctionPseudoRoyal)
+ {
+ Square kto = to;
+ Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) | kto;
+ if (type_of(m) == CASTLING)
+ {
+ // After castling, the rook and king final positions are the same in
+ // Chess960 as they would be in standard chess.
+ kto = make_square(to > from ? castling_kingside_file() : castling_queenside_file(), castling_rank(us));
+ Direction step = kto > from ? EAST : WEST;
+ Square rto = kto - step;
+ // Pseudo-royal king
+ if (st->pseudoRoyals & from)
+ for (Square s = from; s != kto; s += step)
+ if ( !(blast_on_capture() && (attacks_bb<KING>(s) & st->pseudoRoyals & pieces(~sideToMove)))
+ && attackers_to(s, pieces() ^ from, ~us))
+ return false;
+ occupied = (pieces() ^ from ^ to) | kto | rto;
+ }
+ if (type_of(m) == EN_PASSANT)
+ occupied &= ~square_bb(kto - pawn_push(us));
+ if (capture(m) && blast_on_capture())
+ occupied &= ~((attacks_bb<KING>(kto) & (pieces() ^ pieces(PAWN))) | kto);
+ Bitboard pseudoRoyals = st->pseudoRoyals & pieces(sideToMove);
+ Bitboard pseudoRoyalsTheirs = st->pseudoRoyals & pieces(~sideToMove);
+ if (is_ok(from) && (pseudoRoyals & from))
+ pseudoRoyals ^= square_bb(from) ^ kto;
+ if (type_of(m) == PROMOTION && extinction_piece_types().find(promotion_type(m)) != extinction_piece_types().end())
+ pseudoRoyals |= kto;
+ // Self-explosions are illegal
+ if (pseudoRoyals & ~occupied)
+ return false;
+ // Check for legality unless we capture a pseudo-royal piece
+ if (!(pseudoRoyalsTheirs & ~occupied))
+ while (pseudoRoyals)
+ {
+ Square sr = pop_lsb(pseudoRoyals);
+ // Touching pseudo-royal pieces are immune
+ if ( !(blast_on_capture() && (pseudoRoyalsTheirs & attacks_bb<KING>(sr)))
+ && (attackers_to(sr, occupied, ~us) & (occupied & ~square_bb(kto))))
+ return false;
+ }
+ }
- // st->previous->blockersForKing consider capsq as empty.
- // If pinned, it has to move along the king ray.
- if (type_of(m) == EN_PASSANT)
+ // En passant captures are a tricky special case. Because they are rather
+ // uncommon, we do it simply by testing whether the king is attacked after
+ // the move is made.
- if (type_of(m) == EN_PASSANT)
++ if (type_of(m) == EN_PASSANT && count<KING>(us))
{
- if (!count<KING>(us))
- return true;
-
+ Square ksq = square<KING>(us);
Square capsq = to - pawn_push(us);
Bitboard occupied = (pieces() ^ from ^ capsq) | to;
- return !(attackers_to(square<KING>(us), occupied, ~us) & occupied);
+ assert(to == ep_square());
+ assert(moved_piece(m) == make_piece(us, PAWN));
+ assert(piece_on(capsq) == make_piece(~us, PAWN));
+ assert(piece_on(to) == NO_PIECE);
+
- return !(attacks_bb< ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK))
- && !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP));
++ return !(attackers_to(ksq, occupied, ~us) & occupied);
}
// Castling moves generation does not check if the castling path is clear of
return false;
case PROMOTION:
- return attacks_bb(promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
+ return attacks_bb(sideToMove, promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
+
+ case PIECE_PROMOTION:
+ return attacks_bb(sideToMove, promoted_piece_type(type_of(moved_piece(m))), to, pieces() ^ from) & square<KING>(~sideToMove);
+
+ case PIECE_DEMOTION:
+ return attacks_bb(sideToMove, type_of(unpromoted_piece_on(from)), to, pieces() ^ from) & square<KING>(~sideToMove);
- // The double-pushed pawn blocked a check? En Passant will remove the blocker.
- // The only discovery check that wasn't handle is through capsq and fromsq
- // So the King must be in the same rank as fromsq to consider this possibility.
- // st->previous->blockersForKing consider capsq as empty.
+ // En passant capture with check? We have already handled the case
+ // of direct checks and ordinary discovered check, so the only case we
+ // need to handle is the unusual case of a discovered check through
+ // the captured pawn.
case EN_PASSANT:
{
Square capsq = make_square(file_of(to), rank_of(from));