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))
+ {
+ 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;
+ if (type_of(m) == CASTLING && (st->pseudoRoyals & from))
+ {
+ // 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 = to > from ? WEST : EAST;
+ for (Square s = kto; s != from + step; s += step)
+ if ( !(blast_on_capture() && (attacks_bb<KING>(s) & st->pseudoRoyals & pieces(~sideToMove)))
+ && attackers_to(s, (s == kto ? (pieces() ^ to) : pieces()) ^ from, ~us))
+ return false;
+ }
+ Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) | kto;
+ 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;
+ }
+ }
- // 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.
+ // st->previous->blockersForKing consider capsq as empty.
+ // If pinned, it has to move along the king ray.
if (type_of(m) == EN_PASSANT)
- return !(st->previous->blockersForKing[sideToMove] & from) ||
- aligned(from, to, square<KING>(us));
+ {
- Square ksq = count<KING>(us) ? square<KING>(us) : SQ_NONE;
++ if (!count<KING>(us))
++ return true;
++
+ Square capsq = to - pawn_push(us);
+ Bitboard occupied = (pieces() ^ from ^ capsq) | to;
+
- 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 !count<KING>(us) || !(attackers_to(ksq, occupied, ~us) & occupied);
++ return !(attackers_to(square<KING>(us), occupied, ~us) & occupied);
+ }
// Castling moves generation does not check if the castling path is clear of
// enemy attacks, it is delayed at a later time: now!
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);
- // 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.
+ // 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.
case EN_PASSANT:
- return st->previous->checkersBB || (rank_of(square<KING>(~sideToMove)) == rank_of(from)
- && st->previous->blockersForKing[~sideToMove] & from);
+ {
+ Square capsq = make_square(file_of(to), rank_of(from));
+ Bitboard b = (pieces() ^ from ^ capsq) | to;
+ return attackers_to(square<KING>(~sideToMove), b) & pieces(sideToMove) & b;
+ }
default: //CASTLING
{
// Castling is encoded as 'king captures the rook'