From: Fabian Fichter Date: Fri, 15 Mar 2019 10:23:51 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=08f02cc34b7b36a1af7d20ffabcb7197babe3ad2;p=fairystockfish.git Merge official-stockfish/master bench: 3423031 --- 08f02cc34b7b36a1af7d20ffabcb7197babe3ad2 diff --cc src/movegen.cpp index ac003a7,5ed2489..6948538 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@@ -25,83 -25,25 +25,37 @@@ namespace { - template - ExtMove* generate_castling(const Position& pos, ExtMove* moveList) { - - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr CastlingRight Cr = Us | Cs; - constexpr bool KingSide = (Cs == KING_SIDE); - - if (pos.castling_impeded(Cr) || !pos.can_castle(Cr)) - return moveList; - - // After castling, the rook and king final positions are the same in Chess960 - // as they would be in standard chess. - Square kfrom = pos.count(Us) ? pos.square(Us) : make_square(FILE_E, relative_rank(Us, RANK_1, pos.max_rank())); - Square rfrom = pos.castling_rook_square(Cr); - Square kto = make_square(KingSide ? pos.castling_kingside_file() : pos.castling_queenside_file(), - relative_rank(Us, RANK_1, pos.max_rank())); - Bitboard enemies = pos.pieces(Them); - - assert(!pos.checkers()); - - const Direction step = Chess960 ? kto > kfrom ? WEST : EAST - : KingSide ? WEST : EAST; - - if (type_of(pos.piece_on(kfrom)) == KING) - { - for (Square s = kto; s != kfrom; s += step) - if (pos.attackers_to(s, ~Us) & enemies) - return moveList; - - // Because we generate only legal castling moves we need to verify that - // when moving the castling rook we do not discover some hidden checker. - // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. - if (Chess960 && pos.attackers_to(kto, pos.pieces() ^ rfrom, ~Us)) - return moveList; - } - - Move m = make(kfrom, rfrom); - - if (Checks && !pos.gives_check(m)) - return moveList; - - *moveList++ = m; - return moveList; - } - - - template - ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) { + template + ExtMove* make_promotions(const Position& pos, ExtMove* moveList, Square to) { if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) - *moveList++ = make(to - D, to, QUEEN); + for (PieceType pt : pos.promotion_piece_types()) + *moveList++ = make(to - D, to, pt); - if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS) + return moveList; + } + + template + ExtMove* generate_drops(const Position& pos, ExtMove* moveList, PieceType pt, Bitboard b) { + if (pos.count_in_hand(Us, pt)) { - *moveList++ = make(to - D, to, ROOK); - *moveList++ = make(to - D, to, BISHOP); - *moveList++ = make(to - D, to, KNIGHT); - } + // Restrict to valid target + b &= pos.drop_region(Us, pt); - // Knight promotion is the only promotion that can give a direct check - // that's not already included in the queen promotion. - if (Type == QUIET_CHECKS && (PseudoAttacks[KNIGHT][to] & ksq)) - *moveList++ = make(to - D, to, KNIGHT); - else - (void)ksq; // Silence a warning under MSVC + // Add to move list + if (pos.drop_promoted() && pos.promoted_piece_type(pt)) + { + Bitboard b2 = b; + if (Checks) + b2 &= pos.check_squares(pos.promoted_piece_type(pt)); + while (b2) + *moveList++ = make_drop(pop_lsb(&b2), pt, pos.promoted_piece_type(pt)); + } + if (Checks) + b &= pos.check_squares(pt); + while (b) + *moveList++ = make_drop(pop_lsb(&b), pt, pt); + } return moveList; } @@@ -337,38 -219,33 +291,46 @@@ template ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { - constexpr bool Checks = Type == QUIET_CHECKS; + constexpr CastlingRight OO = Us | KING_SIDE; + constexpr CastlingRight OOO = Us | QUEEN_SIDE; + constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations moveList = generate_pawn_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target); - moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target); - - if (Type != QUIET_CHECKS && Type != EVASIONS) + for (PieceType pt = PieceType(PAWN + 1); pt < KING; ++pt) + moveList = generate_moves(pos, moveList, Us, pt, target); + // generate drops + if (pos.piece_drops() && Type != CAPTURES && pos.count_in_hand(Us, ALL_PIECES)) + for (PieceType pt = PAWN; pt <= KING; ++pt) + moveList = generate_drops(pos, moveList, pt, target & ~pos.pieces(~Us)); + + if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count(Us)) { Square ksq = pos.square(Us); - Bitboard b = pos.attacks_from(ksq) & target; + Bitboard b = pos.attacks_from(Us, ksq) & target; while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); - } - if (pos.castling_enabled() && Type != CAPTURES && Type != EVASIONS && pos.castling_rights(Us)) - { - if (pos.is_chess960()) + if (Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO))) { - moveList = generate_castling(pos, moveList); - moveList = generate_castling(pos, moveList); - } - else - { - moveList = generate_castling(pos, moveList); - moveList = generate_castling(pos, moveList); + if (!pos.castling_impeded(OO) && pos.can_castle(OO)) + *moveList++ = make(ksq, pos.castling_rook_square(OO)); + + if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) + *moveList++ = make(ksq, pos.castling_rook_square(OOO)); } } ++ // Castling with non-king piece ++ if (!pos.count(Us) && Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO))) ++ { ++ Square from = make_square(FILE_E, relative_rank(Us, RANK_1, pos.max_rank())); ++ if (!pos.castling_impeded(OO) && pos.can_castle(OO)) ++ *moveList++ = make(from, pos.castling_rook_square(OO)); ++ ++ if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) ++ *moveList++ = make(from, pos.castling_rook_square(OOO)); ++ } ++ return moveList; } diff --cc src/position.cpp index f8af60b,21eff88..dd5f36a --- a/src/position.cpp +++ b/src/position.cpp @@@ -720,79 -541,16 +720,79 @@@ bool Position::legal(Move m) const Color us = sideToMove; Square from = from_sq(m); Square to = to_sq(m); - Square ksq = count(us) ? square(us) : SQ_NONE; 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)); + + // Illegal moves to squares outside of board + if (!(board_bb() & to)) + return false; + + // Illegal checks + if ((!checking_permitted() || (sittuyin_promotion() && type_of(m) == PROMOTION)) && gives_check(m)) + return false; + + // Illegal quiet moves + if (must_capture() && !capture(m)) + { + if (checkers()) + { + for (const auto& mevasion : MoveList(*this)) + if (capture(mevasion) && legal(mevasion)) + return false; + } + else + { + for (const auto& mcap : MoveList(*this)) + if (capture(mcap) && legal(mcap)) + return false; + } + } + + // Illegal non-drop moves + if (must_drop() && type_of(m) != DROP && count_in_hand(us, ALL_PIECES)) + { + 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) & ~pieces() & ~SquareBB[to] & board_bb(); + // 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; // 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) == ENPASSANT) { - Square ksq = square(us); ++ Square ksq = count(us) ? square(us) : SQ_NONE; Square capsq = to - pawn_push(us); Bitboard occupied = (pieces() ^ from ^ capsq) | to; @@@ -801,17 -559,39 +801,41 @@@ 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 !count(us) || !(attackers_to(ksq, 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! + if (type_of(m) == CASTLING) + { ++ // Non-royal pieces can not be impeded from castling ++ if (type_of(piece_on(from)) != KING) ++ return true; ++ + // After castling, the rook and king final positions are the same in + // Chess960 as they would be in standard chess. - to = relative_square(us, to > from ? SQ_G1 : SQ_C1); ++ to = make_square(to > from ? castling_kingside_file() : castling_queenside_file(), relative_rank(us, RANK_1, max_rank())); + Direction step = to > from ? WEST : EAST; + + for (Square s = to; s != from; s += step) - if (attackers_to(s) & pieces(~us)) ++ if (attackers_to(s, ~us)) + return false; + + // In case of Chess960, verify that when moving the castling rook we do + // not discover some hidden checker. + // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. + return !chess960 - || !(attacks_bb(to, pieces() ^ to_sq(m)) & pieces(~us, ROOK, QUEEN)); ++ || !(attackers_to(to, pieces() ^ to_sq(m), ~us)); + } + - // If the moving piece is a king, check whether the destination square is - // attacked by the opponent. - if (type_of(piece_on(from)) == KING) - return !(attackers_to(to) & pieces(~us)); + // If the moving piece is a king, check whether the destination + // square is attacked by the opponent. Castling moves are checked + // for legality during move generation. + if (type_of(moved_piece(m)) == KING) + return type_of(m) == CASTLING || !attackers_to(to, ~us); - // A non-king move is legal if and only if it is not pinned or it - // is moving along the ray towards or away from the king. - return !(blockers_for_king(us) & from) - || aligned(from, to, square(us)); + // A non-king move is legal if the king is not under attack after the move. - return !count(us) || !(attackers_to(ksq, (type_of(m) != DROP ? pieces() ^ from : pieces()) | to, ~us) & ~SquareBB[to]); ++ return !count(us) || !(attackers_to(square(us), (type_of(m) != DROP ? pieces() ^ from : pieces()) | to, ~us) & ~SquareBB[to]); }