From: Fabian Fichter Date: Tue, 9 Mar 2021 20:19:56 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=4eb3b7207d6e02d9b1e10e25f2485a711be84dfb;p=fairystockfish.git Merge official-stockfish/master No functional change. --- 4eb3b7207d6e02d9b1e10e25f2485a711be84dfb diff --cc src/position.cpp index d1a7e1d,35e307e..6ae1106 --- a/src/position.cpp +++ b/src/position.cpp @@@ -898,120 -513,13 +898,116 @@@ bool Position::legal(Move m) const Square to = to_sq(m); assert(color_of(moved_piece(m)) == us); - assert(piece_on(square(us)) == make_piece(us, KING)); + assert(!count(us) || piece_on(square(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(*this)) + if (type_of(mevasion) == DROP && legal(mevasion)) + return false; + } + else + { + for (const auto& mquiet : MoveList(*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(*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(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(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(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(us)); + { - Square ksq = count(us) ? square(us) : SQ_NONE; ++ if (!count(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(us) || !(attackers_to(ksq, occupied, ~us) & occupied); ++ return !(attackers_to(square(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! @@@ -1242,25 -650,16 +1238,25 @@@ bool Position::gives_check(Move m) cons return false; case PROMOTION: - return attacks_bb(promotion_type(m), to, pieces() ^ from) & square(~sideToMove); + return attacks_bb(sideToMove, promotion_type(m), to, pieces() ^ from) & square(~sideToMove); + + case PIECE_PROMOTION: + return attacks_bb(sideToMove, promoted_piece_type(type_of(moved_piece(m))), to, pieces() ^ from) & square(~sideToMove); + + case PIECE_DEMOTION: + return attacks_bb(sideToMove, type_of(unpromoted_piece_on(from)), to, pieces() ^ from) & square(~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(~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(~sideToMove), b) & pieces(sideToMove) & b; + } default: //CASTLING { // Castling is encoded as 'king captures the rook'