]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Sync qsearch with search
[stockfish] / src / search.cpp
index ee21915d149b43be8d459472d468d424155f27f5..4a8dd17f81c4b8079ddc745322340a13e8a5691a 100644 (file)
@@ -969,7 +969,7 @@ namespace {
                 && !captureOrPromotion
                 && !move_is_castle(move))
             {
-                double red = ln(RootMoveNumber - MultiPV + 1) * ln(depth / 2) / 3.0;
+                double red = 0.5 + ln(RootMoveNumber - MultiPV + 1) * ln(depth / 2) / 6.0;
                 if (red >= 1.0)
                 {
                     ss[0].reduction = Depth(int(floor(red * int(OnePly))));
@@ -1226,7 +1226,7 @@ namespace {
             && !move_is_castle(move)
             && !move_is_killer(move, ss[ply]))
         {
-          double red = ln(moveCount) * ln(depth / 2) / 3.0;
+          double red = 0.5 + ln(moveCount) * ln(depth / 2) / 6.0;
           if (red >= 1.0)
           {
               ss[ply].reduction = Depth(int(floor(red * int(OnePly))));
@@ -1341,7 +1341,7 @@ namespace {
     const TTEntry* tte;
     Move ttMove, move;
     Depth ext, newDepth;
-    Value approximateEval, nullValue, value, futilityValue, futilityValueScaled;
+    Value staticValue, nullValue, value, futilityValue, futilityValueScaled;
     bool isCheck, useFutilityPruning, singleEvasion, moveIsCheck, captureOrPromotion, dangerous;
     bool mateThreat = false;
     int moveCount = 0;
@@ -1385,8 +1385,24 @@ namespace {
         return value_from_tt(tte->value(), ply);
     }
 
-    approximateEval = refine_eval(tte, quick_evaluate(pos), ply);
     isCheck = pos.is_check();
+    ei.futilityMargin = Value(0); // Manually initialize futilityMargin
+
+    // Evaluate the position statically
+    if (isCheck)
+        staticValue = quick_evaluate(pos);
+    else if (tte && (tte->type() & VALUE_TYPE_EVAL))
+        staticValue = value_from_tt(tte->value(), ply);
+    else
+        staticValue = evaluate(pos, ei, threadID);
+
+    // Calculate depth dependant futility pruning parameters
+    const int FutilityMoveCountMargin = 3 + (1 << (3 * int(depth) / 8));
+    const int FutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2);
+
+    // Enhance score accuracy with TT value if possible
+    futilityValue = staticValue + FutilityValueMargin;
+    staticValue = refine_eval(tte, staticValue, ply);
 
     // Null move search
     if (    allowNullmove
@@ -1394,7 +1410,7 @@ namespace {
         && !isCheck
         && !value_is_mate(beta)
         &&  ok_to_do_nullmove(pos)
-        &&  approximateEval >= beta - NullMoveMargin)
+        &&  staticValue >= beta - NullMoveMargin)
     {
         ss[ply].currentMove = MOVE_NULL;
 
@@ -1404,7 +1420,7 @@ namespace {
         int R = 3 + (depth >= 5 * OnePly ? depth / 8 : 0);
 
         // Null move dynamic reduction based on value
-        if (approximateEval - beta > PawnValueMidgame)
+        if (staticValue - beta > PawnValueMidgame)
             R++;
 
         nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
@@ -1440,7 +1456,7 @@ namespace {
     // Null move search not allowed, try razoring
     else if (   !value_is_mate(beta)
              && depth < RazorDepth
-             && approximateEval < beta - RazorApprMargins[int(depth) - 2]
+             && staticValue < beta - RazorApprMargins[int(depth) - 2]
              && ss[ply - 1].currentMove != MOVE_NULL
              && ttMove == MOVE_NONE
              && !pos.has_pawn_on_7th(pos.side_to_move()))
@@ -1464,17 +1480,8 @@ namespace {
     // to search all moves.
     MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]);
     CheckInfo ci(pos);
-    futilityValue = VALUE_NONE;
     useFutilityPruning = depth < SelectiveDepth && !isCheck;
 
-    // Calculate depth dependant futility pruning parameters
-    const int FutilityMoveCountMargin = 3 + (1 << (3 * int(depth) / 8));
-    const int FutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2);
-
-    // Avoid calling evaluate() if we already have the score in TT
-    if (tte && (tte->type() & VALUE_TYPE_EVAL))
-        futilityValue = value_from_tt(tte->value(), ply) + FutilityValueMargin;
-
     // Loop through all legal moves until no moves remain or a beta cutoff occurs
     while (   bestValue < beta
            && (move = mp.get_next_move()) != MOVE_NONE
@@ -1485,8 +1492,8 @@ namespace {
       if (move == excludedMove)
           continue;
 
-      singleEvasion = (isCheck && mp.number_of_evasions() == 1);
       moveIsCheck = pos.move_is_check(move, ci);
+      singleEvasion = (isCheck && mp.number_of_evasions() == 1);
       captureOrPromotion = pos.move_is_capture_or_promotion(move);
 
       // Decide the new search depth
@@ -1532,9 +1539,6 @@ namespace {
               continue;
 
           // Value based pruning
-          if (futilityValue == VALUE_NONE)
-              futilityValue = evaluate(pos, ei, threadID) + FutilityValueMargin;
-
           futilityValueScaled = futilityValue - moveCount * IncrementalFutilityMargin;
 
           if (futilityValueScaled < beta)
@@ -1557,7 +1561,7 @@ namespace {
           && !move_is_killer(move, ss[ply])
           /* && move != ttMove*/)
       {
-          double red = ln(moveCount) * ln(depth / 2) / 1.5;
+          double red = 0.5 + ln(moveCount) * ln(depth / 2) / 3.0;
           if (red >= 1.0)
           {
               ss[ply].reduction = Depth(int(floor(red * int(OnePly))));
@@ -1602,9 +1606,9 @@ namespace {
           break;
     }
 
-    // All legal moves have been searched.  A special case: If there were
+    // All legal moves have been searched. A special case: If there were
     // no legal moves, it must be mate or stalemate.
-    if (moveCount == 0)
+    if (!moveCount)
         return excludedMove ? beta - 1 : (pos.is_check() ? value_mated_in(ply) : VALUE_DRAW);
 
     // If the search is not aborted, update the transposition table,
@@ -1618,12 +1622,13 @@ namespace {
     {
         BetaCounter.add(pos.side_to_move(), depth, threadID);
         move = ss[ply].pv[ply];
+        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, move);
         if (!pos.move_is_capture_or_promotion(move))
         {
             update_history(pos, move, depth, movesSearched, moveCount);
             update_killers(move, ss[ply]);
         }
-        TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, move);
+
     }
 
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
@@ -1648,7 +1653,7 @@ namespace {
     EvalInfo ei;
     StateInfo st;
     Move ttMove, move;
-    Value staticValue, bestValue, value, futilityValue;
+    Value staticValue, bestValue, value, futilityBase, futilityValue;
     bool isCheck, enoughMaterial, moveIsCheck;
     const TTEntry* tte = NULL;
     int moveCount = 0;
@@ -1665,18 +1670,21 @@ namespace {
     if (pos.is_draw())
         return VALUE_DRAW;
 
-    // Transposition table lookup, only when not in PV
-    if (!pvNode)
+    if (ply >= PLY_MAX - 1)
+        return pos.is_check() ? quick_evaluate(pos) : evaluate(pos, ei, threadID);
+
+    // Transposition table lookup. At PV nodes, we don't use the TT for
+    // pruning, but only for move ordering.
+    tte = TT.retrieve(pos.get_key());
+    ttMove = (tte ? tte->move() : MOVE_NONE);
+
+    if (!pvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
     {
-        tte = TT.retrieve(pos.get_key());
-        if (tte && ok_to_use_TT(tte, depth, beta, ply))
-        {
-            assert(tte->type() != VALUE_TYPE_EVAL);
+        assert(tte->type() != VALUE_TYPE_EVAL);
 
-            return value_from_tt(tte->value(), ply);
-        }
+        ss[ply].currentMove = ttMove; // Can be MOVE_NONE
+        return value_from_tt(tte->value(), ply);
     }
-    ttMove = (tte ? tte->move() : MOVE_NONE);
 
     isCheck = pos.is_check();
     ei.futilityMargin = Value(0); // Manually initialize futilityMargin
@@ -1684,20 +1692,11 @@ namespace {
     // Evaluate the position statically
     if (isCheck)
         staticValue = -VALUE_INFINITE;
-
     else if (tte && (tte->type() & VALUE_TYPE_EVAL))
-    {
-        // Use the cached evaluation score if possible
-        assert(ei.futilityMargin == Value(0));
-
         staticValue = value_from_tt(tte->value(), ply);
-    }
     else
         staticValue = evaluate(pos, ei, threadID);
 
-    if (ply >= PLY_MAX - 1)
-        return pos.is_check() ? quick_evaluate(pos) : evaluate(pos, ei, threadID);
-
     // Initialize "stand pat score", and return it immediately if it is
     // at least beta.
     bestValue = staticValue;
@@ -1720,6 +1719,7 @@ namespace {
     MovePicker mp = MovePicker(pos, ttMove, depth, H);
     CheckInfo ci(pos);
     enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame;
+    futilityBase = staticValue + FutilityMarginQS + ei.futilityMargin;
 
     // Loop through the moves until no moves remain or a beta cutoff
     // occurs.
@@ -1728,11 +1728,12 @@ namespace {
     {
       assert(move_is_ok(move));
 
+      moveIsCheck = pos.move_is_check(move, ci);
+
+      // Update current move
       moveCount++;
       ss[ply].currentMove = move;
 
-      moveIsCheck = pos.move_is_check(move, ci);
-
       // Futility pruning
       if (   enoughMaterial
           && !isCheck
@@ -1742,12 +1743,9 @@ namespace {
           && !move_is_promotion(move)
           && !pos.move_is_passed_pawn_push(move))
       {
-          futilityValue =  staticValue
-                         + Max(pos.midgame_value_of_piece_on(move_to(move)),
-                               pos.endgame_value_of_piece_on(move_to(move)))
-                         + (move_is_ep(move) ? PawnValueEndgame : Value(0))
-                         + FutilityMarginQS
-                         + ei.futilityMargin;
+          futilityValue =  futilityBase
+                         + pos.endgame_value_of_piece_on(move_to(move))
+                         + (move_is_ep(move) ? PawnValueEndgame : Value(0));
 
           if (futilityValue < alpha)
           {
@@ -1783,31 +1781,31 @@ namespace {
        }
     }
 
-    // All legal moves have been searched.  A special case: If we're in check
+    // All legal moves have been searched. A special case: If we're in check
     // and no legal moves were found, it is checkmate.
     if (!moveCount && pos.is_check()) // Mate!
         return value_mated_in(ply);
 
-    assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
-
     // Update transposition table
-    move = ss[ply].pv[ply];
-    if (!pvNode)
+    Depth d = (depth == Depth(0) ? Depth(0) : Depth(-1));
+    if (bestValue < beta)
     {
-        // If bestValue isn't changed it means it is still the static evaluation of
-        // the node, so keep this info to avoid a future costly evaluation() call.
+        // 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.futilityMargin ? VALUE_TYPE_EV_UP : VALUE_TYPE_UPPER);
-        Depth d = (depth == Depth(0) ? Depth(0) : Depth(-1));
+        TT.store(pos.get_key(), value_to_tt(bestValue, ply), type, d, MOVE_NONE);
+    }
+    else
+    {
+        move = ss[ply].pv[ply];
+        TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, d, move);
 
-        if (bestValue < beta)
-            TT.store(pos.get_key(), value_to_tt(bestValue, ply), type, d, MOVE_NONE);
-        else
-            TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, d, move);
+        // Update killers only for good checking moves
+        if (!pos.move_is_capture_or_promotion(move))
+            update_killers(move, ss[ply]);
     }
 
-    // Update killers only for good check moves
-    if (alpha >= beta && !pos.move_is_capture_or_promotion(move))
-        update_killers(move, ss[ply]);
+    assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
     return bestValue;
   }
@@ -1902,7 +1900,7 @@ namespace {
           && !move_is_castle(move)
           && !move_is_killer(move, ss[sp->ply]))
       {
-          double red = ln(moveCount) * ln(sp->depth / 2) / 1.5;
+          double red = 0.5 + ln(moveCount) * ln(sp->depth / 2) / 3.0;
           if (red >= 1.0)
           {
               ss[sp->ply].reduction = Depth(int(floor(red * int(OnePly))));
@@ -2013,7 +2011,7 @@ namespace {
           && !move_is_castle(move)
           && !move_is_killer(move, ss[sp->ply]))
       {
-          double red = ln(moveCount) * ln(sp->depth / 2) / 3.0;
+          double red = 0.5 + ln(moveCount) * ln(sp->depth / 2) / 6.0;
           if (red >= 1.0)
           {
               ss[sp->ply].reduction = Depth(int(floor(red * int(OnePly))));