@@ -64,7 +64,23 @@ namespace {
6464 return moveList;
6565 }
6666
67- *moveList++ = make<T>(from, to, pt);
67+ PieceType forcedGate = NO_PIECE_TYPE;
68+ Square forcedGateSquare = SQ_NONE;
69+ if (from != to)
70+ {
71+ Piece pcFrom = pos.piece_on (from);
72+ if (pcFrom != NO_PIECE)
73+ {
74+ forcedGate = pos.forced_gating_type (us, type_of (pcFrom));
75+ if (forcedGate != NO_PIECE_TYPE)
76+ forcedGateSquare = from;
77+ }
78+ }
79+
80+ if (forcedGate != NO_PIECE_TYPE)
81+ *moveList++ = make_gating<T>(from, to, forcedGate, forcedGateSquare);
82+ else
83+ *moveList++ = make<T>(from, to, pt);
6884
6985 // Gating moves
7086 if (pos.seirawan_gating () && (pos.gates (us) & from))
@@ -142,14 +158,20 @@ namespace {
142158 constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
143159 constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
144160
161+ const bool allowFriendlyCaptures = pos.self_capture ()
162+ && (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS);
163+
145164 const Bitboard promotionZone = pos.promotion_zone (Us);
146165 const Bitboard standardPromotionZone = pos.sittuyin_promotion () ? Bitboard (0 ) : promotionZone;
147166 const Bitboard doubleStepRegion = pos.double_step_region (Us);
148167 const Bitboard tripleStepRegion = pos.triple_step_region (Us);
149168
150169 const Bitboard pawns = pos.pieces (Us, PAWN);
151170 const Bitboard movable = pos.board_bb (Us, PAWN) & ~pos.pieces ();
152- const Bitboard capturable = pos.board_bb (Us, PAWN) & pos.pieces (Them);
171+ const Bitboard friendlyCapturable = pos.pieces (Us) & ~pos.pieces (Us, KING);
172+ const Bitboard capturable = pos.board_bb (Us, PAWN)
173+ & (allowFriendlyCaptures ? (pos.pieces (Them) | friendlyCapturable)
174+ : pos.pieces (Them));
153175
154176 target = Type == EVASIONS ? target : AllSquares;
155177
@@ -287,26 +309,35 @@ namespace {
287309
288310
289311 template <Color Us, GenType Type>
290- ExtMove* generate_moves (const Position& pos, ExtMove* moveList, PieceType Pt, Bitboard target) {
312+ ExtMove* generate_moves (const Position& pos, ExtMove* moveList, PieceType Pt, Bitboard target, Bitboard captureTarget ) {
291313
292314 assert (Pt != KING && Pt != PAWN);
293315
294316 Bitboard bb = pos.pieces (Us, Pt);
295317
318+ const bool allowFriendlyCaptures = pos.self_capture ()
319+ && (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS);
320+
296321 while (bb)
297322 {
298323 Square from = pop_lsb (bb);
299324
300325 Bitboard attacks = pos.attacks_from (Us, Pt, from);
301326 Bitboard quiets = pos.moves_from (Us, Pt, from);
302- Bitboard b = ( (attacks & pos.pieces ())
303- | (quiets & ~pos.pieces ()));
304- Bitboard b1 = b & target;
327+ Bitboard captureSquares = (attacks & pos.pieces ()) & captureTarget;
328+ Bitboard quietSquares = (quiets & ~pos.pieces ()) & target;
329+ Bitboard b = captureSquares | quietSquares;
330+ Bitboard b1 = b;
305331 Bitboard promotion_zone = pos.promotion_zone (Us);
306332 PieceType promPt = pos.promoted_piece_type (Pt);
307333 Bitboard b2 = promPt && (!pos.promotion_limit (promPt) || pos.promotion_limit (promPt) > pos.count (Us, promPt)) ? b1 : Bitboard (0 );
308334 Bitboard b3 = pos.piece_demotion () && pos.is_promoted (from) ? b1 : Bitboard (0 );
309- Bitboard pawnPromotions = (pos.promotion_pawn_types (Us) & Pt) ? (b & (Type == EVASIONS ? target : ~pos.pieces (Us)) & promotion_zone) : Bitboard (0 );
335+ Bitboard pawnPromotions = (pos.promotion_pawn_types (Us) & Pt)
336+ ? (b & (Type == EVASIONS ? target
337+ : (~pos.pieces (Us)
338+ | (allowFriendlyCaptures ? pos.pieces (Us) : Bitboard (0 ))))
339+ & promotion_zone)
340+ : Bitboard (0 );
310341 Bitboard epSquares = (pos.en_passant_types (Us) & Pt) ? (attacks & ~quiets & pos.ep_squares () & ~pos.pieces ()) : Bitboard (0 );
311342
312343 // target squares considering pawn promotions
@@ -380,6 +411,7 @@ namespace {
380411 constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations
381412 const Square ksq = pos.count <KING>(Us) ? pos.square <KING>(Us) : SQ_NONE;
382413 Bitboard target;
414+ Bitboard captureTarget = Type == EVASIONS ? ~pos.pieces (Us) : Bitboard (0 );
383415
384416 // Skip generating non-king moves when in double check
385417 if (Type != EVASIONS || !more_than_one (pos.checkers () & ~pos.non_sliding_riders ()))
@@ -402,9 +434,13 @@ namespace {
402434 // Remove inaccessible squares (outside board + wall squares)
403435 target &= pos.board_bb ();
404436
437+ captureTarget = target;
438+ if (pos.self_capture () && (Type == NON_EVASIONS || Type == CAPTURES))
439+ captureTarget |= pos.pieces (Us) & ~pos.pieces (Us, KING);
440+
405441 moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
406442 for (PieceSet ps = pos.piece_types () & ~(piece_set (PAWN) | KING); ps;)
407- moveList = generate_moves<Us, Type>(pos, moveList, pop_lsb (ps), target);
443+ moveList = generate_moves<Us, Type>(pos, moveList, pop_lsb (ps), target, captureTarget );
408444 // generate drops
409445 if (pos.piece_drops () && Type != CAPTURES && (pos.can_drop (Us, ALL_PIECES) || pos.two_boards ()))
410446 for (PieceSet ps = pos.piece_types (); ps;)
@@ -455,8 +491,13 @@ namespace {
455491 // King moves
456492 if (pos.count <KING>(Us) && (!Checks || pos.blockers_for_king (~Us) & ksq))
457493 {
458- Bitboard b = ( (pos.attacks_from (Us, KING, ksq) & pos.pieces ())
459- | (pos.moves_from (Us, KING, ksq) & ~pos.pieces ())) & (Type == EVASIONS ? ~pos.pieces (Us) : target);
494+ Bitboard kingAttacks = pos.attacks_from (Us, KING, ksq) & pos.pieces ();
495+ Bitboard kingMoves = pos.moves_from (Us, KING, ksq) & ~pos.pieces ();
496+ Bitboard kingCaptureMask = Type == EVASIONS ? ~pos.pieces (Us) : captureTarget;
497+ if (Type == EVASIONS && pos.self_capture ())
498+ kingCaptureMask |= pos.pieces (Us) & ~pos.pieces (Us, KING);
499+ Bitboard kingQuietMask = Type == EVASIONS ? ~pos.pieces (Us) : target;
500+ Bitboard b = (kingAttacks & kingCaptureMask) | (kingMoves & kingQuietMask);
460501 while (b)
461502 moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb (b));
462503
0 commit comments