Bitboard emptySquares;
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
- Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
+ Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & (pos.mandatory_pawn_promotion() ? ~TRank7BB : AllSquares);
- Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
+ Bitboard enemies = (Type == EVASIONS ? pos.checkers():
Type == CAPTURES ? target : pos.pieces(Them));
// Single and double pawn pushes, no promotions
while (bb) {
Square from = pop_lsb(&bb);
- Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
- if constexpr (Checks)
- b &= pos.check_squares(Pt);
+ Bitboard b1 = ( (pos.attacks_from(us, Pt, from) & pos.pieces())
+ | (pos.moves_from(us, Pt, from) & ~pos.pieces())) & target;
+ PieceType promPt = pos.promoted_piece_type(Pt);
+ Bitboard b2 = promPt && (!pos.promotion_limit(promPt) || pos.promotion_limit(promPt) > pos.count(us, promPt)) ? b1 : Bitboard(0);
+ Bitboard b3 = pos.piece_demotion() && pos.is_promoted(from) ? b1 : Bitboard(0);
- while (b)
- *moveList++ = make_move(from, pop_lsb(&b));
+ if (Checks)
+ {
- b1 &= checkSquares;
++ b1 &= pos.check_squares(Pt);
+ if (b2)
+ b2 &= pos.check_squares(pos.promoted_piece_type(Pt));
+ if (b3)
+ b3 &= pos.check_squares(type_of(pos.unpromoted_piece_on(from)));
+ }
+
+ // Restrict target squares considering promotion zone
+ if (b2 | b3)
+ {
+ Bitboard promotion_zone = zone_bb(us, pos.promotion_rank(), pos.max_rank());
+ if (pos.mandatory_piece_promotion())
+ b1 &= (promotion_zone & from ? Bitboard(0) : ~promotion_zone) | (pos.piece_promotion_on_capture() ? ~pos.pieces() : Bitboard(0));
+ // Exclude quiet promotions/demotions
+ if (pos.piece_promotion_on_capture())
+ {
+ b2 &= pos.pieces();
+ b3 &= pos.pieces();
+ }
+ // Consider promotions/demotions into promotion zone
+ if (!(promotion_zone & from))
+ {
+ b2 &= promotion_zone;
+ b3 &= promotion_zone;
+ }
+ }
+
+ while (b1)
+ moveList = make_move_and_gating<NORMAL>(pos, moveList, us, from, pop_lsb(&b1));
+
+ // Shogi-style piece promotions
+ while (b2)
+ *moveList++ = make<PIECE_PROMOTION>(from, pop_lsb(&b2));
+
+ // Piece demotions
+ while (b3)
+ *moveList++ = make<PIECE_DEMOTION>(from, pop_lsb(&b3));
}
return moveList;
moveCount++;
- // Futility pruning
+ // Futility pruning and moveCount pruning
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !givesCheck
+ && !( pos.extinction_value() == -VALUE_MATE
+ && pos.piece_on(to_sq(move))
+ && pos.extinction_piece_types().find(type_of(pos.piece_on(to_sq(move)))) != pos.extinction_piece_types().end())
&& futilityBase > -VALUE_KNOWN_WIN
- && !pos.advanced_pawn_push(move))
+ && type_of(move) != PROMOTION)
{
- assert(type_of(move) != EN_PASSANT); // Due to !pos.advanced_pawn_push
- // moveCount pruning
if (moveCount > 2)
continue;