]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Always save static value and kingDanger to TT
[stockfish] / src / search.cpp
index 36ed82f2771a9c595c70c8835b2f7e9611fada31..4a108360a7cee9af7efcf5be646e097de072eae9 100644 (file)
@@ -89,8 +89,8 @@ namespace {
     void idle_loop(int threadID, SplitPoint* sp);
 
     template <bool Fake>
-    bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
-               Depth depth, bool mateThreat, int* moves, MovePicker* mp, int master, bool pvNode);
+    void split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
+               Depth depth, bool mateThreat, int* moveCount, MovePicker* mp, int master, bool pvNode);
 
   private:
     friend void poll();
@@ -122,7 +122,7 @@ namespace {
     // RootMove::operator<() is the comparison function used when
     // sorting the moves. A move m1 is considered to be better
     // than a move m2 if it has a higher score, or if the moves
-    // have equal score but m1 has the higher node count.
+    // have equal score but m1 has the higher beta cut-off count.
     bool operator<(const RootMove& m) const {
 
         return score != m.score ? score < m.score : theirBeta <= m.theirBeta;
@@ -1095,7 +1095,7 @@ namespace {
     if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
     {
         // Refresh tte entry to avoid aging
-        TT.store(posKey, tte->value(), tte->type(), tte->depth(), ttMove);
+        TT.store(posKey, tte->value(), tte->type(), tte->depth(), ttMove, tte->static_value(), tte->king_danger());
 
         ss[ply].currentMove = ttMove; // Can be MOVE_NONE
         return value_from_tt(tte->value(), ply);
@@ -1106,8 +1106,11 @@ namespace {
     isCheck = pos.is_check();
     if (!isCheck)
     {
-        if (tte && (tte->type() & VALUE_TYPE_EVAL))
-            ss[ply].eval = value_from_tt(tte->value(), ply);
+        if (tte && tte->static_value() != VALUE_NONE)
+        {
+            ss[ply].eval = tte->static_value();
+            ei.kingDanger[pos.side_to_move()] = tte->king_danger();
+        }
         else
             ss[ply].eval = evaluate(pos, ei, threadID);
 
@@ -1283,7 +1286,9 @@ namespace {
               continue;
 
           // Value based pruning
-          Depth predictedDepth = newDepth - reduction<NonPV>(depth, moveCount); // FIXME We illogically ignore reduction condition depth >= 3*OnePly
+          // We illogically ignore reduction condition depth >= 3*OnePly for predicted depth,
+          // but fixing this made program slightly weaker.
+          Depth predictedDepth = newDepth - reduction<NonPV>(depth, moveCount);
           futilityValueScaled =  ss[ply].eval + futility_margin(predictedDepth, moveCount)
                                + H.gain(pos.piece_on(move_from(move)), move_to(move));
 
@@ -1364,10 +1369,9 @@ namespace {
           && Iteration <= 99
           && TM.available_thread_exists(threadID)
           && !AbortSearch
-          && !TM.thread_should_stop(threadID)
-          && TM.split<FakeSplit>(pos, ss, ply, &alpha, beta, &bestValue, depth,
-                                 mateThreat, &moveCount, &mp, threadID, PvNode))
-          break;
+          && !TM.thread_should_stop(threadID))
+          TM.split<FakeSplit>(pos, ss, ply, &alpha, beta, &bestValue, depth,
+                              mateThreat, &moveCount, &mp, threadID, PvNode);
     }
 
     // Step 19. Check for mate and stalemate
@@ -1384,13 +1388,13 @@ namespace {
         return bestValue;
 
     if (bestValue <= oldAlpha)
-        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, depth, MOVE_NONE);
+        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, depth, MOVE_NONE, ss[ply].eval, ei.kingDanger[pos.side_to_move()]);
 
     else if (bestValue >= beta)
     {
         TM.incrementBetaCounter(pos.side_to_move(), depth, threadID);
         move = ss[ply].pv[ply];
-        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, move);
+        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, move, ss[ply].eval, ei.kingDanger[pos.side_to_move()]);
         if (!pos.move_is_capture_or_promotion(move))
         {
             update_history(pos, move, depth, movesSearched, moveCount);
@@ -1398,7 +1402,7 @@ namespace {
         }
     }
     else
-        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_EXACT, depth, ss[ply].pv[ply]);
+        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_EXACT, depth, ss[ply].pv[ply], ss[ply].eval, ei.kingDanger[pos.side_to_move()]);
 
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
@@ -1448,8 +1452,6 @@ namespace {
 
     if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
     {
-        assert(tte->type() != VALUE_TYPE_EVAL);
-
         ss[ply].currentMove = ttMove; // Can be MOVE_NONE
         return value_from_tt(tte->value(), ply);
     }
@@ -1459,8 +1461,11 @@ namespace {
     // Evaluate the position statically
     if (isCheck)
         staticValue = -VALUE_INFINITE;
-    else if (tte && (tte->type() & VALUE_TYPE_EVAL))
-        staticValue = value_from_tt(tte->value(), ply);
+    else if (tte && tte->static_value() != VALUE_NONE)
+    {
+        staticValue = tte->static_value();
+        ei.kingDanger[pos.side_to_move()] = tte->king_danger();
+    }
     else
         staticValue = evaluate(pos, ei, threadID);
 
@@ -1478,7 +1483,7 @@ namespace {
     {
         // Store the score to avoid a future costly evaluation() call
         if (!isCheck && !tte && ei.kingDanger[pos.side_to_move()] == 0)
-            TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_EV_LO, Depth(-127*OnePly), MOVE_NONE);
+            TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, Depth(-127*OnePly), MOVE_NONE, ss[ply].eval, ei.kingDanger[pos.side_to_move()]);
 
         return bestValue;
     }
@@ -1576,20 +1581,19 @@ namespace {
     {
         // If bestValue isn't changed it means it is still the static evaluation
         // of the node, so keep this info to avoid a future evaluation() call.
-        ValueType type = (bestValue == staticValue && !ei.kingDanger[pos.side_to_move()] ? VALUE_TYPE_EV_UP : VALUE_TYPE_UPPER);
-        TT.store(pos.get_key(), value_to_tt(bestValue, ply), type, d, MOVE_NONE);
+        TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, d, MOVE_NONE, ss[ply].eval, ei.kingDanger[pos.side_to_move()]);
     }
     else if (bestValue >= beta)
     {
         move = ss[ply].pv[ply];
-        TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, d, move);
+        TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, d, move, ss[ply].eval, ei.kingDanger[pos.side_to_move()]);
 
         // Update killers only for good checking moves
         if (!pos.move_is_capture_or_promotion(move))
             update_killers(move, ss[ply]);
     }
     else
-        TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_EXACT, d, ss[ply].pv[ply]);
+        TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_EXACT, d, ss[ply].pv[ply], ss[ply].eval, ei.kingDanger[pos.side_to_move()]);
 
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
@@ -1633,7 +1637,7 @@ namespace {
            && (move = sp->mp->get_next_move()) != MOVE_NONE
            && !TM.thread_should_stop(threadID))
     {
-      moveCount = ++sp->moves;
+      moveCount = ++sp->moveCount;
       lock_release(&(sp->lock));
 
       assert(move_is_ok(move));
@@ -2587,20 +2591,19 @@ namespace {
 
 
   // split() does the actual work of distributing the work at a node between
-  // several threads at PV nodes. If it does not succeed in splitting the
+  // several available threads. If it does not succeed in splitting the
   // node (because no idle threads are available, or because we have no unused
-  // split point objects), the function immediately returns false. If
-  // splitting is possible, a SplitPoint object is initialized with all the
-  // data that must be copied to the helper threads (the current position and
-  // search stack, alpha, beta, the search depth, etc.), and we tell our
-  // helper threads that they have been assigned work. This will cause them
-  // to instantly leave their idle loops and call sp_search(). When all
-  // threads have returned from sp_search() then split() returns true.
+  // split point objects), the function immediately returns. If splitting is
+  // possible, a SplitPoint object is initialized with all the data that must be
+  // copied to the helper threads and we tell our helper threads that they have
+  // been assigned work. This will cause them to instantly leave their idle loops
+  // and call sp_search(). When all threads have returned from sp_search() then
+  // split() returns.
 
   template <bool Fake>
-  bool ThreadsManager::split(const Position& p, SearchStack* sstck, int ply, Value* alpha,
+  void ThreadsManager::split(const Position& p, SearchStack* sstck, int ply, Value* alpha,
                              const Value beta, Value* bestValue, Depth depth, bool mateThreat,
-                             int* moves, MovePicker* mp, int master, bool pvNode) {
+                             int* moveCount, MovePicker* mp, int master, bool pvNode) {
     assert(p.is_ok());
     assert(sstck != NULL);
     assert(ply >= 0 && ply < PLY_MAX);
@@ -2612,8 +2615,6 @@ namespace {
     assert(master >= 0 && master < ActiveThreads);
     assert(ActiveThreads > 1);
 
-    SplitPoint* splitPoint;
-
     lock_grab(&MPLock);
 
     // If no other thread is available to help us, or if we have too many
@@ -2622,11 +2623,11 @@ namespace {
         || threads[master].activeSplitPoints >= ACTIVE_SPLIT_POINTS_MAX)
     {
         lock_release(&MPLock);
-        return false;
+        return;
     }
 
     // Pick the next available split point object from the split point stack
-    splitPoint = &SplitPointStack[master][threads[master].activeSplitPoints];
+    SplitPoint* splitPoint = &SplitPointStack[master][threads[master].activeSplitPoints];
 
     // Initialize the split point object
     splitPoint->parent = threads[master].splitPoint;
@@ -2638,9 +2639,8 @@ namespace {
     splitPoint->beta = beta;
     splitPoint->pvNode = pvNode;
     splitPoint->bestValue = *bestValue;
-    splitPoint->master = master;
     splitPoint->mp = mp;
-    splitPoint->moves = *moves;
+    splitPoint->moveCount = *moveCount;
     splitPoint->pos = &p;
     splitPoint->parentSstack = sstck;
     for (int i = 0; i < ActiveThreads; i++)
@@ -2698,7 +2698,6 @@ namespace {
     threads[master].splitPoint = splitPoint->parent;
 
     lock_release(&MPLock);
-    return true;
   }