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.checkers():
- Type == CAPTURES ? target : pos.pieces(Them));
+ Bitboard enemies = (Type == EVASIONS ? pos.checkers()
+ : Type == CAPTURES ? target : pos.pieces(Them));
// Single and double pawn pushes, no promotions
if (Type != CAPTURES)
}
- template<bool Checks>
- ExtMove* generate_moves(const Position& pos, ExtMove* moveList, PieceType Pt, Bitboard piecesToMove, Bitboard target) {
- template<Color Us, PieceType Pt, bool Checks>
- ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
++ template<Color Us, bool Checks>
++ ExtMove* generate_moves(const Position& pos, ExtMove* moveList, PieceType Pt, Bitboard target) {
- static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()");
+ assert(Pt != KING && Pt != PAWN);
- Color us = pos.side_to_move();
-
- Bitboard bb = piecesToMove & pos.pieces(Pt);
+ Bitboard bb = pos.pieces(Us, Pt);
while (bb)
{
Square from = pop_lsb(bb);
- Bitboard b1 = ( (pos.attacks_from(us, Pt, from) & pos.pieces())
- | (pos.moves_from(us, Pt, from) & ~pos.pieces())) & target;
- Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
- if (Checks && (Pt == QUEEN || !(pos.blockers_for_king(~Us) & from)))
- 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 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 &= 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());
++ 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));
++ 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;
static_assert(Type != LEGAL, "Unsupported type in generate_all()");
constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations
- Bitboard target, piecesToMove = pos.pieces(Us);
- const Square ksq = pos.square<KING>(Us);
++ const Square ksq = pos.count<KING>(Us) ? pos.square<KING>(Us) : SQ_NONE;
+ Bitboard target;
+
- if (Type == EVASIONS && more_than_one(pos.checkers()))
++ if (Type == EVASIONS && more_than_one(pos.checkers() & ~pos.non_sliding_riders()))
+ goto kingMoves; // Double check, only a king move can save the day
- if(Type == QUIET_CHECKS)
- piecesToMove &= ~pos.blockers_for_king(~Us);
+ target = Type == EVASIONS ? between_bb(ksq, lsb(pos.checkers()))
+ : Type == NON_EVASIONS ? ~pos.pieces( Us)
+ : Type == CAPTURES ? pos.pieces(~Us)
+ : ~pos.pieces( ); // QUIETS || QUIET_CHECKS
- switch (Type)
++ if (Type == EVASIONS)
+ {
- case CAPTURES:
- target = pos.pieces(~Us);
- break;
- case QUIETS:
- case QUIET_CHECKS:
- target = ~pos.pieces();
- break;
- case EVASIONS:
- {
- if (pos.checkers() & pos.non_sliding_riders())
- {
- target = ~pos.pieces(Us);
- break;
- }
- target = between_bb(pos.square<KING>(Us), lsb(pos.checkers()));
- // Leaper attacks can not be blocked
- Square checksq = lsb(pos.checkers());
- if (LeaperAttacks[~Us][type_of(pos.piece_on(checksq))][checksq] & pos.square<KING>(Us))
- target = pos.checkers();
- break;
- }
- case NON_EVASIONS:
++ if (pos.checkers() & pos.non_sliding_riders())
+ target = ~pos.pieces(Us);
- break;
++ // Leaper attacks can not be blocked
++ Square checksq = lsb(pos.checkers());
++ if (LeaperAttacks[~Us][type_of(pos.piece_on(checksq))][checksq] & pos.square<KING>(Us))
++ target = pos.checkers();
+ }
++
+ target &= pos.board_bb();
+
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
- moveList = generate_moves<Us, KNIGHT, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, BISHOP, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, ROOK, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, QUEEN, Checks>(pos, moveList, target);
+ for (PieceType pt : pos.piece_types())
+ if (pt != PAWN && pt != KING)
- moveList = generate_moves<Checks>(pos, moveList, pt, piecesToMove, target);
++ moveList = generate_moves<Us, Checks>(pos, moveList, pt, target);
+ // generate drops
+ if (pos.piece_drops() && Type != CAPTURES && (pos.count_in_hand(Us, ALL_PIECES) > 0 || pos.two_boards()))
+ for (PieceType pt : pos.piece_types())
+ moveList = generate_drops<Us, Type>(pos, moveList, pt, target & ~pos.pieces(~Us));
+
- if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count<KING>(Us))
- {
- Square ksq = pos.square<KING>(Us);
- Bitboard b = ( (pos.attacks_from(Us, KING, ksq) & pos.pieces())
- | (pos.moves_from(Us, KING, ksq) & ~pos.pieces())) & target;
- while (b)
- moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(b));
-
- // Passing move by king
- if (pos.pass())
- *moveList++ = make<SPECIAL>(ksq, ksq);
-
- if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING))
- for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
- if (!pos.castling_impeded(cr) && pos.can_castle(cr))
- moveList = make_move_and_gating<CASTLING>(pos, moveList, Us,ksq, pos.castling_rook_square(cr));
- }
- // Workaround for passing: Execute a non-move with any piece
- else if (pos.pass() && !pos.count<KING>(Us) && pos.pieces(Us))
- *moveList++ = make<SPECIAL>(lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));
-
+ // Castling with non-king piece
+ if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(Us & ANY_CASTLING))
+ {
+ Square from = pos.castling_king_square(Us);
+ for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
+ if (!pos.castling_impeded(cr) && pos.can_castle(cr))
+ moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, from, pos.castling_rook_square(cr));
+ }
-kingMoves:
- if (!Checks || pos.blockers_for_king(~Us) & ksq)
+ // Special moves
+ if (pos.cambodian_moves() && pos.gates(Us))
{
- Bitboard b = attacks_bb<KING>(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
- if (Checks)
- b &= ~attacks_bb<QUEEN>(pos.square<KING>(~Us));
+ if (Type != CAPTURES && Type != EVASIONS && (pos.pieces(Us, KING) & pos.gates(Us)))
+ {
+ Square from = pos.square<KING>(Us);
+ Bitboard b = PseudoAttacks[WHITE][KNIGHT][from] & rank_bb(rank_of(from + (Us == WHITE ? NORTH : SOUTH)))
+ & target & ~pos.pieces();
+ while (b)
+ moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, from, pop_lsb(b));
+ }
+
+ Bitboard b = pos.pieces(Us, FERS) & pos.gates(Us);
+ while (b)
+ {
+ Square from = pop_lsb(b);
+ Square to = from + 2 * (Us == WHITE ? NORTH : SOUTH);
+ if (is_ok(to) && (target & to))
+ moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, from, to);
+ }
+ }
++ // Workaround for passing: Execute a non-move with any piece
++ if (pos.pass() && !pos.count<KING>(Us) && pos.pieces(Us))
++ *moveList++ = make<SPECIAL>(lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));
++
++kingMoves:
++ if (pos.count<KING>(Us) && (!Checks || pos.blockers_for_king(~Us) & ksq))
++ {
++ Bitboard b = ( (pos.attacks_from(Us, KING, ksq) & pos.pieces())
++ | (pos.moves_from(Us, KING, ksq) & ~pos.pieces())) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
+ while (b)
- *moveList++ = make_move(ksq, pop_lsb(b));
++ moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(b));
++
++ // Passing move by king
++ if (pos.pass())
++ *moveList++ = make<SPECIAL>(ksq, ksq);
+
+ if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
+ for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
+ if (!pos.castling_impeded(cr) && pos.can_castle(cr))
- *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(cr));
++ moveList = make_move_and_gating<CASTLING>(pos, moveList, Us,ksq, pos.castling_rook_square(cr));
+ }
+
return moveList;
}