Cache evaluation score in qsearch
[stockfish] / src / search.cpp
index c4446fc5d95bd4a6271fca322eb5b75ec8610d91..3617853e5f23d2f3589b7af48da9decbf48e4593 100644 (file)
@@ -121,6 +121,9 @@ namespace {
   // Depth limit for selective search:
   Depth SelectiveDepth = 7*OnePly;
 
   // Depth limit for selective search:
   Depth SelectiveDepth = 7*OnePly;
 
+  // Use dynamic LMR?
+  const bool UseDynamicLMR = false;
+
   // Use internal iterative deepening?
   const bool UseIIDAtPVNodes = true;
   const bool UseIIDAtNonPVNodes = false;
   // Use internal iterative deepening?
   const bool UseIIDAtPVNodes = true;
   const bool UseIIDAtNonPVNodes = false;
@@ -1333,7 +1336,9 @@ namespace {
           && !move_is_killer(move, ss[ply]))
       {
           // LMR dynamic reduction
           && !move_is_killer(move, ss[ply]))
       {
           // LMR dynamic reduction
-          Depth R = (moveCount >= 2 * LMRNonPVMoves && depth > 7*OnePly ? 2*OnePly : OnePly);
+          Depth R =    UseDynamicLMR
+                    && moveCount >= 2 * LMRNonPVMoves
+                    && depth > 7*OnePly ? 2*OnePly : OnePly;
 
           ss[ply].reduction = R;
           value = -search(pos, ss, -(beta-1), newDepth-R, ply+1, true, threadID);
 
           ss[ply].reduction = R;
           value = -search(pos, ss, -(beta-1), newDepth-R, ply+1, true, threadID);
@@ -1429,18 +1434,38 @@ namespace {
         return VALUE_DRAW;
 
     // Transposition table lookup, only when not in PV
         return VALUE_DRAW;
 
     // Transposition table lookup, only when not in PV
+    TTEntry* tte = NULL;
     bool pvNode = (beta - alpha != 1);
     if (!pvNode)
     {
     bool pvNode = (beta - alpha != 1);
     if (!pvNode)
     {
-        const TTEntry* tte = TT.retrieve(pos);
+        tte = TT.retrieve(pos);
         if (tte && ok_to_use_TT(tte, depth, beta, ply))
         if (tte && ok_to_use_TT(tte, depth, beta, ply))
+        {
+            assert(tte->type() != VALUE_TYPE_EVAL);
+
             return value_from_tt(tte->value(), ply);
             return value_from_tt(tte->value(), ply);
+        }
     }
 
     // Evaluate the position statically
     EvalInfo ei;
     }
 
     // Evaluate the position statically
     EvalInfo ei;
+    Value staticValue;
     bool isCheck = pos.is_check();
     bool isCheck = pos.is_check();
-    Value staticValue = (isCheck ? -VALUE_INFINITE : evaluate(pos, ei, threadID));
+
+    if (isCheck)
+        staticValue = -VALUE_INFINITE;
+
+    else if (tte && tte->type() == VALUE_TYPE_EVAL)
+    {
+        // Use the cached evaluation score if possible
+        assert(tte->value() == evaluate(pos, ei, threadID));
+        assert(ei.futilityMargin == Value(0));
+
+        staticValue = tte->value();
+        ei.futilityMargin = Value(0); // manually initialize futilityMargin
+    }
+    else
+        staticValue = evaluate(pos, ei, threadID);
 
     if (ply == PLY_MAX - 1)
         return evaluate(pos, ei, threadID);
 
     if (ply == PLY_MAX - 1)
         return evaluate(pos, ei, threadID);
@@ -1455,6 +1480,11 @@ namespace {
         TT.store(pos, value_to_tt(bestValue, ply), depth, MOVE_NONE, VALUE_TYPE_EXACT);
         return bestValue;
     }
         TT.store(pos, value_to_tt(bestValue, ply), depth, MOVE_NONE, VALUE_TYPE_EXACT);
         return bestValue;
     }
+    else if (!isCheck && !tte && ei.futilityMargin == 0)
+    {
+        // Store the score to avoid a future costly evaluation() call
+        TT.store(pos, value_to_tt(bestValue, ply), Depth(-127*OnePly), MOVE_NONE, VALUE_TYPE_EVAL);
+    }
 
     if (bestValue > alpha)
         alpha = bestValue;
 
     if (bestValue > alpha)
         alpha = bestValue;
@@ -1462,7 +1492,7 @@ namespace {
     // Initialize a MovePicker object for the current position, and prepare
     // to search the moves.  Because the depth is <= 0 here, only captures,
     // queen promotions and checks (only if depth == 0) will be generated.
     // Initialize a MovePicker object for the current position, and prepare
     // to search the moves.  Because the depth is <= 0 here, only captures,
     // queen promotions and checks (only if depth == 0) will be generated.
-    MovePicker mp = MovePicker(pos, pvNode, MOVE_NONE, EmptySearchStack, depth, isCheck ? NULL : &ei);
+    MovePicker mp = MovePicker(pos, pvNode, MOVE_NONE, EmptySearchStack, depth);
     Move move;
     int moveCount = 0;
     Bitboard dcCandidates = mp.discovered_check_candidates();
     Move move;
     int moveCount = 0;
     Bitboard dcCandidates = mp.discovered_check_candidates();