Redefine reset of 50 move rule counter (#616)
authorFabian Fichter <ianfab@users.noreply.github.com>
Sat, 1 Apr 2023 16:25:21 +0000 (18:25 +0200)
committerGitHub <noreply@github.com>
Sat, 1 Apr 2023 16:25:21 +0000 (18:25 +0200)
src/position.cpp
src/variant.cpp
test.py
tests/js/test.js

index 19b5b57..ed12362 100644 (file)
@@ -1619,10 +1619,24 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
       k ^=  Zobrist::psq[pc][to]
           ^ Zobrist::inHand[pc_hand][pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)] - 1]
           ^ Zobrist::inHand[pc_hand][pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)]];
+
+      // Reset rule 50 counter for irreversible drops
+      st->rule50 = 0;
   }
   else
+  {
       k ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
 
+      // Reset rule 50 draw counter for irreversible moves
+      // - irreversible pawn/piece promotions
+      // - irreversible pawn moves
+      if (    type_of(m) == PROMOTION
+          || (type_of(m) == PIECE_PROMOTION && !piece_demotion())
+          || (    (var->nMoveRuleTypes[us] & type_of(pc))
+              && !(PseudoMoves[0][us][type_of(pc)][to] & from)))
+          st->rule50 = 0;
+  }
+
   // Reset en passant squares
   while (st->epSquares)
       k ^= Zobrist::enpassant[file_of(pop_lsb(st->epSquares))];
@@ -1856,10 +1870,6 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
           k ^= Zobrist::enpassant[file_of(pop_lsb(b))];
   }
 
-  // Reset rule 50 draw counter
-  if (var->nMoveRuleTypes[us] & type_of(pc))
-      st->rule50 = 0;
-
   // Set capture piece
   st->capturedPiece = captured;
 
index 265afe8..58c2aa2 100644 (file)
@@ -115,7 +115,7 @@ namespace {
         v->promotionPawnType[WHITE] = v->promotionPawnType[BLACK] = CUSTOM_PIECE_1;
         v->promotionPawnTypes[WHITE] = v->promotionPawnTypes[BLACK] = piece_set(CUSTOM_PIECE_1);
         v->enPassantTypes[WHITE] = v->enPassantTypes[BLACK] = piece_set(CUSTOM_PIECE_1);
-        v->nMoveRuleTypes[WHITE] = v->nMoveRuleTypes[BLACK] = piece_set(CUSTOM_PIECE_1);
+        v->nMoveRuleTypes[WHITE] = v->nMoveRuleTypes[BLACK] = NO_PIECE_SET; // backwards pawn moves are reversible
         return v;
     }
     // Legan Chess
diff --git a/test.py b/test.py
index 3ffd61a..8d79501 100644 (file)
--- a/test.py
+++ b/test.py
@@ -397,6 +397,13 @@ class TestPyffish(unittest.TestCase):
         result = sf.get_fen("passchess", fen, ["e1e1", "e8e8"])
         self.assertEqual(result, "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 2 2")
 
+        # only irreversible moves should reset 50 move rule counter
+        fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
+        result = sf.get_fen("pawnsideways", fen, ["e2e4", "g8f6", "e4d4"])
+        self.assertEqual(result, "rnbqkb1r/pppppppp/5n2/8/3P4/8/PPPP1PPP/RNBQKBNR b KQkq - 2 2")
+        result = sf.get_fen("pawnback", fen, ["e2e4", "e7e6"])
+        self.assertEqual(result, "rnbqkbnr/pppp1ppp/4p3/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 2 2")
+
         # SFEN
         result = sf.get_fen("shogi", SHOGI, [], False, True)
         self.assertEqual(result, SHOGI_SFEN)
index b504f6b..0f268c1 100644 (file)
@@ -788,7 +788,7 @@ describe('ffish.readGamePGN(pgn)', function () {
      let pgnFiles = ['deep_blue_kasparov_1997.pgn', 'lichess_pgn_2018.12.21_JannLee_vs_CrazyAra.j9eQS4TF.pgn', 'c60_ruy_lopez.pgn', 'pychess-variants_zJxHRVm1.pgn', 'Syrov - Dgebuadze.pgn', 'pychess-variants_YHEWvfWF.pgn']
 
      let expectedFens = ["1r6/5kp1/RqQb1p1p/1p1PpP2/1Pp1B3/2P4P/6P1/5K2 b - - 14 45",
-                         "3r2kr/2pb1Q2/4ppp1/3pN2p/1P1P4/3PbP2/P1P3PP/6NK[PPqrrbbnn] b - - 1 37",
+                         "3r2kr/2pb1Q2/4ppp1/3pN2p/1P1P4/3PbP2/P1P3PP/6NK[PPqrrbbnn] b - - 0 37",
                          "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3",
                          "r1bQkb1r/ppp1pppp/2P5/2n2q2/8/2N2N2/PPP2PPP/R1BEKB1R[Hh] b KQCFkqcf - 0 8",
                          "5rk1/4p3/2p3rR/2p1P3/2Pp1B2/1P1P2P1/2N1n3/6K1 w - - 1 44",