Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ namespace {

const Bitboard pawns = pos.pieces(Us, PAWN);
const Bitboard movable = pos.board_bb(Us, PAWN) & ~pos.pieces();
const Bitboard capturable = pos.board_bb(Us, PAWN) & pos.pieces(Them);
const Bitboard capturable = pos.board_bb(Us, PAWN)
& ((pos.self_capture() && (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS))
? (pos.pieces(Them) | (pos.pieces(Us) & ~pos.pieces(Us, KING)))
: pos.pieces(Them));

target = Type == EVASIONS ? target : AllSquares;

Expand Down Expand Up @@ -299,9 +302,13 @@ namespace {

Bitboard attacks = pos.attacks_from(Us, Pt, from);
Bitboard quiets = pos.moves_from(Us, Pt, from);
Bitboard b = ( (attacks & pos.pieces())
| (quiets & ~pos.pieces()));
Bitboard b1 = b & target;
Bitboard captureTarget = (pos.self_capture() && (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS))
? (target | (pos.pieces(Us) & ~pos.pieces(Us, KING)))
: target;
Bitboard captureSquares = (attacks & pos.pieces()) & captureTarget;
Bitboard quietSquares = (quiets & ~pos.pieces()) & target;
Bitboard b = captureSquares | quietSquares;
Bitboard b1 = b;
Bitboard promotion_zone = pos.promotion_zone(Us);
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);
Expand Down Expand Up @@ -455,8 +462,12 @@ namespace {
// King moves
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);
Bitboard baseTarget = Type == EVASIONS ? ~pos.pieces(Us) : target;
Bitboard kingCaptureMask = (pos.self_capture() && (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS))
? (baseTarget | (pos.pieces(Us) & ~pos.pieces(Us, KING)))
: baseTarget;
Bitboard b = ( (pos.attacks_from(Us, KING, ksq) & pos.pieces() & kingCaptureMask)
| (pos.moves_from(Us, KING, ksq) & ~pos.pieces() & baseTarget));
while (b)
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(b));

Expand Down
2 changes: 2 additions & 0 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("oppositeCastling", v->oppositeCastling);
parse_attribute("checking", v->checking);
parse_attribute("dropChecks", v->dropChecks);
parse_attribute("selfCapture", v->selfCapture);
parse_attribute("capturingLast", v->capturingLast);
parse_attribute("mustCapture", v->mustCapture);
parse_attribute("mustDrop", v->mustDrop);
parse_attribute("mustDropType", v->mustDropType, v->pieceToChar);
Expand Down
43 changes: 32 additions & 11 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1362,9 +1362,16 @@ bool Position::pseudo_legal(const Move m) const {
if (pc == NO_PIECE || color_of(pc) != us)
return false;

// The destination square cannot be occupied by a friendly piece
// The destination square cannot be occupied by a friendly piece (unless self-capture)
if (pieces(us) & to)
return false;
{
if (!(self_capture() && capture(m)))
return false;

// Friendly king is never capturable, even with self-capture enabled
if (type_of(piece_on(to)) == KING)
return false;
}

// Handle the special case of a pawn move
if (type_of(pc) == PAWN)
Expand All @@ -1374,7 +1381,8 @@ bool Position::pseudo_legal(const Move m) const {
if (mandatory_pawn_promotion() && (promotion_zone(us) & to) && !sittuyin_promotion())
return false;

if ( !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture
if ( !(pawn_attacks_bb(us, from)
& (self_capture() ? (pieces() & ~pieces(KING)) : pieces(~us)) & to) // Not a capture
&& !((from + pawn_push(us) == to) && !(pieces() & to)) // Not a single push
&& !( (from + 2 * pawn_push(us) == to) // Not a double push
&& (double_step_region(us) & from)
Expand Down Expand Up @@ -1640,9 +1648,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
board[capsq] = NO_PIECE;
if (captures_to_hand())
{
Piece pieceToHand = !capturedPromoted || drop_loop() ? ~captured
: unpromotedCaptured ? ~unpromotedCaptured
: make_piece(~color_of(captured), main_promotion_pawn_type(color_of(captured)));
Piece pieceToHand = !capturedPromoted || drop_loop()
? make_piece(us, type_of(captured))
: unpromotedCaptured ? make_piece(us, type_of(unpromotedCaptured))
: make_piece(us, main_promotion_pawn_type(color_of(captured)));
add_to_hand(pieceToHand);
k ^= Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)] - 1]
^ Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)]];
Expand Down Expand Up @@ -2023,7 +2032,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st->promotedBycatch |= bsq;
remove_piece(bsq);
board[bsq] = NO_PIECE;
if (captures_to_hand())
if (captures_to_hand() && !(bsq == to && (var->petrifyOnCaptureTypes & type_of(bpc))))
{
Piece pieceToHand = !capturedPromoted || drop_loop() ? ~bpc
: unpromotedCaptured ? ~unpromotedCaptured
Expand Down Expand Up @@ -2168,7 +2177,7 @@ void Position::undo_move(Move m) {
if (bpc)
{
put_piece(bpc, bsq, isPromoted, st->demotedBycatch & bsq ? unpromotedBpc : NO_PIECE);
if (captures_to_hand())
if (captures_to_hand() && !(bsq == to && (var->petrifyOnCaptureTypes & type_of(bpc))))
remove_from_hand(!drop_loop() && (st->promotedBycatch & bsq) ? make_piece(~color_of(unpromotedBpc), PAWN)
: ~unpromotedBpc);
}
Expand Down Expand Up @@ -2240,9 +2249,9 @@ void Position::undo_move(Move m) {

put_piece(st->capturedPiece, capsq, st->capturedpromoted, st->unpromotedCapturedPiece); // Restore the captured piece
if (captures_to_hand())
remove_from_hand(!drop_loop() && st->capturedpromoted ? (st->unpromotedCapturedPiece ? ~st->unpromotedCapturedPiece
: make_piece(~color_of(st->capturedPiece), main_promotion_pawn_type(us)))
: ~st->capturedPiece);
remove_from_hand(!drop_loop() && st->capturedpromoted ? (st->unpromotedCapturedPiece ? make_piece(us, type_of(st->unpromotedCapturedPiece))
: make_piece(us, main_promotion_pawn_type(color_of(st->capturedPiece))))
: make_piece(us, type_of(st->capturedPiece)));
}
}

Expand Down Expand Up @@ -2752,6 +2761,18 @@ bool Position::is_optional_game_end(Value& result, int ply, int countStarted) co

bool Position::is_immediate_game_end(Value& result, int ply) const {

// Capturing last opponent's piece wins
if (var->capturingLast)
{
if (st->capturedPiece != NO_PIECE
&& color_of(st->capturedPiece) == sideToMove
&& !pieces(sideToMove))
{
result = mated_in(ply);
return true;
}
}

// Extinction
// Extinction does not apply for pseudo-royal pieces, because they can not be captured
if (extinction_value() != VALUE_NONE && (!var->extinctionPseudoRoyal || blast_on_capture()))
Expand Down
12 changes: 12 additions & 0 deletions src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ class Position {
bool fast_attacks2() const;
bool checking_permitted() const;
bool drop_checks() const;
bool self_capture() const;
bool capturing_last() const;
bool must_capture() const;
bool has_capture() const;
bool must_drop() const;
Expand Down Expand Up @@ -639,6 +641,16 @@ inline bool Position::drop_checks() const {
return var->dropChecks;
}

inline bool Position::self_capture() const {
assert(var != nullptr);
return var->selfCapture;
}

inline bool Position::capturing_last() const {
assert(var != nullptr);
return var->capturingLast;
}

inline bool Position::must_capture() const {
assert(var != nullptr);
return var->mustCapture;
Expand Down
2 changes: 2 additions & 0 deletions src/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ struct Variant {
PieceType kingType = KING;
bool checking = true;
bool dropChecks = true;
bool selfCapture = false;
bool capturingLast = false;
bool mustCapture = false;
bool mustDrop = false;
PieceType mustDropType = ALL_PIECES;
Expand Down