From: Fabian Fichter Date: Sun, 18 Jul 2021 13:26:37 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=9b4841cac4d72cf1dafc72904f916ed2ae50cde0;p=fairystockfish.git Merge official-stockfish/master No functional change. --- 9b4841cac4d72cf1dafc72904f916ed2ae50cde0 diff --cc src/position.cpp index 24b4ec6,56cb34e..3649240 --- a/src/position.cpp +++ b/src/position.cpp @@@ -924,119 -502,24 +924,123 @@@ 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) > 0) + { + 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; + 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(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(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; + } + } - // 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(us)) { - if (!count(us)) - return true; - + Square ksq = square(us); Square capsq = to - pawn_push(us); Bitboard occupied = (pieces() ^ from ^ capsq) | to; - return !(attackers_to(square(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(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 @@@ -1272,18 -651,12 +1276,18 @@@ 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); - // 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));