Cache legal capture state
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 29 Nov 2020 20:25:22 +0000 (21:25 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 29 Nov 2020 20:25:22 +0000 (21:25 +0100)
Speed-up for variants with mandatory captures.

giveaway STC
LLR: 2.94 (-2.94,2.94) [0.00,10.00]
Total: 1873 W: 743 L: 637 D: 493
http://www.variantfishtest.org:6543/tests/view/5fc2239d6e23db221d9e9423

losers STC
LLR: 2.95 (-2.94,2.94) [0.00,10.00]
Total: 1194 W: 577 L: 469 D: 148
http://www.variantfishtest.org:6543/tests/view/5fc223af6e23db221d9e9426

No functional change.

src/position.cpp
src/position.h
src/search.cpp
src/types.h

index 3cebafe..5c747c4 100644 (file)
@@ -504,6 +504,7 @@ void Position::set_check_info(StateInfo* si) const {
   si->checkSquares[KING]   = 0;
   si->shak = si->checkersBB & (byTypeBB[KNIGHT] | byTypeBB[ROOK] | byTypeBB[BERS]);
   si->bikjang = var->bikjangRule && ksq != SQ_NONE ? bool(attacks_bb(sideToMove, ROOK, ksq, pieces()) & pieces(sideToMove, KING)) : false;
+  si->legalCapture = NO_VALUE;
 }
 
 
@@ -842,20 +843,30 @@ bool Position::legal(Move m) const {
       return false;
 
   // Illegal quiet moves
-  if (must_capture() && !capture(m))
+  if (must_capture() && !capture(m) && st->legalCapture != VALUE_FALSE)
   {
+      // Check for cached value
+      if (st->legalCapture == VALUE_TRUE)
+          return false;
       if (checkers())
       {
           for (const auto& mevasion : MoveList<EVASIONS>(*this))
               if (capture(mevasion) && legal(mevasion))
+              {
+                  st->legalCapture = VALUE_TRUE;
                   return false;
+              }
       }
       else
       {
           for (const auto& mcap : MoveList<CAPTURES>(*this))
               if (capture(mcap) && legal(mcap))
+              {
+                  st->legalCapture = VALUE_TRUE;
                   return false;
+              }
       }
+      st->legalCapture = VALUE_FALSE;
   }
 
   // Illegal non-drop moves
index 6e4dc48..e57c31c 100644 (file)
@@ -29,6 +29,7 @@
 #include "evaluate.h"
 #include "types.h"
 #include "variant.h"
+#include "movegen.h"
 
 #include "nnue/nnue_accumulator.h"
 
@@ -62,6 +63,7 @@ struct StateInfo {
   Bitboard   pinners[COLOR_NB];
   Bitboard   checkSquares[PIECE_TYPE_NB];
   Bitboard   flippedPieces;
+  OptBool    legalCapture;
   bool       capturedpromoted;
   bool       shak;
   bool       bikjang;
@@ -134,6 +136,7 @@ public:
   bool checking_permitted() const;
   bool drop_checks() const;
   bool must_capture() const;
+  bool has_capture() const;
   bool must_drop() const;
   bool piece_drops() const;
   bool drop_loop() const;
@@ -492,6 +495,10 @@ inline bool Position::must_capture() const {
   return var->mustCapture;
 }
 
+inline bool Position::has_capture() const {
+  return st->legalCapture == VALUE_TRUE || (st->legalCapture == NO_VALUE && MoveList<CAPTURES>(*this).size());
+}
+
 inline bool Position::must_drop() const {
   assert(var != nullptr);
   return var->mustDrop;
index ee7eb04..094dbe1 100644 (file)
@@ -895,7 +895,7 @@ namespace {
                : ss->staticEval > (ss-2)->staticEval;
 
     // Skip early pruning in case of mandatory capture
-    if (pos.must_capture() && MoveList<CAPTURES>(pos).size())
+    if (pos.must_capture() && pos.has_capture())
         goto moves_loop;
 
     // Step 8. Futility pruning: child node (~50 Elo)
@@ -1250,7 +1250,7 @@ moves_loop: // When in check, search starts from here
               || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha
               || cutNode
               || thisThread->ttHitAverage < 427 * TtHitAverageResolution * TtHitAverageWindow / 1024)
-          && !(pos.must_capture() && (givesCheck || MoveList<CAPTURES>(pos).size())))
+          && !(pos.must_capture() && (givesCheck || pos.has_capture())))
       {
           Depth r = reduction(improving, depth, moveCount);
 
index bdb4a7c..e71536e 100644 (file)
@@ -294,6 +294,10 @@ enum EnclosingRule {
   NO_ENCLOSING, REVERSI, ATAXX
 };
 
+enum OptBool {
+  NO_VALUE, VALUE_FALSE, VALUE_TRUE
+};
+
 enum Phase {
   PHASE_ENDGAME,
   PHASE_MIDGAME = 128,