]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Fix white space breakage
[stockfish] / src / search.cpp
index d0cedb82601d5b2526bdc608cd3f50106a00b793..6ee1ea02a17b1e45d9dc603a75ec23a6d8e0d50e 100644 (file)
@@ -301,7 +301,6 @@ namespace {
   bool connected_moves(const Position& pos, Move m1, Move m2);
   bool value_is_mate(Value value);
   bool move_is_killer(Move m, SearchStack* ss);
-  bool ok_to_do_nullmove(const Position& pos);
   bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply);
   bool connected_threat(const Position& pos, Move m, Move threat);
   Value refine_eval(const TTEntry* tte, Value defaultEval, int ply);
@@ -338,6 +337,51 @@ void exit_threads() { TM.exit_threads(); }
 int64_t nodes_searched() { return TM.nodes_searched(); }
 
 
+/// init_search() is called during startup. It initializes various lookup tables
+
+void init_search() {
+
+  int d;  // depth (OnePly == 2)
+  int hd; // half depth (OnePly == 1)
+  int mc; // moveCount
+
+  // Init reductions array
+  for (hd = 1; hd < 64; hd++) for (mc = 1; mc < 64; mc++)
+  {
+      double    pvRed = log(double(hd)) * log(double(mc)) / 3.0;
+      double nonPVRed = log(double(hd)) * log(double(mc)) / 1.5;
+      ReductionMatrix[PV][hd][mc]    = (int8_t) (   pvRed >= 1.0 ? floor(   pvRed * int(OnePly)) : 0);
+      ReductionMatrix[NonPV][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
+  }
+
+  // Init futility margins array
+  for (d = 0; d < 16; d++) for (mc = 0; mc < 64; mc++)
+      FutilityMarginsMatrix[d][mc] = 112 * int(log(double(d * d) / 2) / log(2.0) + 1) - 8 * mc + 45;
+
+  // Init futility move count array
+  for (d = 0; d < 32; d++)
+      FutilityMoveCountArray[d] = 3 + (1 << (3 * d / 8));
+}
+
+
+// SearchStack::init() initializes a search stack. Used at the beginning of a
+// new search from the root.
+void SearchStack::init(int ply) {
+
+  pv[ply] = pv[ply + 1] = MOVE_NONE;
+  currentMove = threatMove = MOVE_NONE;
+  reduction = Depth(0);
+  eval = VALUE_NONE;
+}
+
+void SearchStack::initKillers() {
+
+  mateKiller = MOVE_NONE;
+  for (int i = 0; i < KILLER_MAX; i++)
+      killers[i] = MOVE_NONE;
+}
+
+
 /// perft() is our utility to verify move generation is bug free. All the legal
 /// moves up to given depth are generated and counted and the sum returned.
 
@@ -550,51 +594,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
 }
 
 
-/// init_search() is called during startup. It initializes various lookup tables
-
-void init_search() {
-
-  // Init our reduction lookup tables
-  for (int i = 1; i < 64; i++) // i == depth (OnePly = 1)
-      for (int j = 1; j < 64; j++) // j == moveNumber
-      {
-          double    pvRed = log(double(i)) * log(double(j)) / 3.0;
-          double nonPVRed = log(double(i)) * log(double(j)) / 1.5;
-          ReductionMatrix[PV][i][j]    = (int8_t) (   pvRed >= 1.0 ? floor(   pvRed * int(OnePly)) : 0);
-          ReductionMatrix[NonPV][i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
-      }
-
-  // Init futility margins array
-  for (int i = 0; i < 16; i++) // i == depth (OnePly = 2)
-      for (int j = 0; j < 64; j++) // j == moveNumber
-      {
-          // FIXME: test using log instead of BSR
-          FutilityMarginsMatrix[i][j] = (i < 2 ? 0 : 112 * bitScanReverse32(i * i / 2)) - 8 * j + 45;
-      }
-
-  // Init futility move count array
-  for (int i = 0; i < 32; i++) // i == depth (OnePly = 2)
-      FutilityMoveCountArray[i] = 3 + (1 << (3 * i / 8));
-}
-
-
-// SearchStack::init() initializes a search stack. Used at the beginning of a
-// new search from the root.
-void SearchStack::init(int ply) {
-
-  pv[ply] = pv[ply + 1] = MOVE_NONE;
-  currentMove = threatMove = MOVE_NONE;
-  reduction = Depth(0);
-  eval = VALUE_NONE;
-}
-
-void SearchStack::initKillers() {
-
-  mateKiller = MOVE_NONE;
-  for (int i = 0; i < KILLER_MAX; i++)
-      killers[i] = MOVE_NONE;
-}
-
 namespace {
 
   // id_loop() is the main iterative deepening loop. It calls root_search
@@ -1125,11 +1124,11 @@ namespace {
 
     // Step 6. Razoring (is omitted in PV nodes)
     if (   !PvNode
+        &&  depth < RazorDepth
+        && !isCheck
         &&  refinedValue < beta - razor_margin(depth)
         &&  ttMove == MOVE_NONE
         &&  (ss-1)->currentMove != MOVE_NULL
-        &&  depth < RazorDepth
-        && !isCheck
         && !value_is_mate(beta)
         && !pos.has_pawn_on_7th(pos.side_to_move()))
     {
@@ -1147,10 +1146,10 @@ namespace {
     if (   !PvNode
         &&  allowNullmove
         &&  depth < RazorDepth
+        &&  refinedValue >= beta + futility_margin(depth, 0)
         && !isCheck
         && !value_is_mate(beta)
-        &&  ok_to_do_nullmove(pos)
-        &&  refinedValue >= beta + futility_margin(depth, 0))
+        &&  pos.non_pawn_material(pos.side_to_move()))
         return refinedValue - futility_margin(depth, 0);
 
     // Step 8. Null move search with verification search (is omitted in PV nodes)
@@ -1160,10 +1159,10 @@ namespace {
     if (   !PvNode
         &&  allowNullmove
         &&  depth > OnePly
+        &&  refinedValue >= beta - (depth >= 4 * OnePly ? NullMoveMargin : 0)
         && !isCheck
         && !value_is_mate(beta)
-        &&  ok_to_do_nullmove(pos)
-        &&  refinedValue >= beta - (depth >= 4 * OnePly ? NullMoveMargin : 0))
+        &&  pos.non_pawn_material(pos.side_to_move()))
     {
         ss->currentMove = MOVE_NULL;
 
@@ -1186,14 +1185,13 @@ namespace {
             if (nullValue >= value_mate_in(PLY_MAX))
                 nullValue = beta;
 
-            if (depth < 6 * OnePly)
+            // Do zugzwang verification search at high depths
+            if (   depth < 6 * OnePly
+                || search<NonPV>(pos, ss, alpha, beta, depth-5*OnePly, false, threadID) >= beta)
                 return nullValue;
-
-            // Do zugzwang verification search
-            Value v = search<NonPV>(pos, ss, alpha, beta, depth-5*OnePly, false, threadID);
-            if (v >= beta)
-                return nullValue;
-        } else {
+        }
+        else
+        {
             // The null move failed low, which means that we may be faced with
             // some kind of threat. If the previous move was reduced, check if
             // the move that refuted the null move was somehow connected to the
@@ -1279,11 +1277,11 @@ namespace {
 
       // Step 12. Futility pruning (is omitted in PV nodes)
       if (   !PvNode
+          && !captureOrPromotion
           && !isCheck
           && !dangerous
-          && !captureOrPromotion
-          && !move_is_castle(move)
-          &&  move != ttMove)
+          &&  move != ttMove
+          && !move_is_castle(move))
       {
           // Move count based pruning
           if (   moveCount >= futility_move_count(depth)
@@ -1321,8 +1319,8 @@ namespace {
           bool doFullDepthSearch = true;
 
           if (    depth >= 3 * OnePly
-              && !dangerous
               && !captureOrPromotion
+              && !dangerous
               && !move_is_castle(move)
               && !move_is_killer(move, ss))
           {
@@ -1387,13 +1385,13 @@ namespace {
       }
 
       // Step 18. Check for split
-      if (   TM.active_threads() > 1
+      if (   depth >= MinimumSplitDepth
+          && TM.active_threads() > 1
           && bestValue < beta
-          && depth >= MinimumSplitDepth
-          && Iteration <= 99
           && TM.available_thread_exists(threadID)
           && !AbortSearch
-          && !TM.thread_should_stop(threadID))
+          && !TM.thread_should_stop(threadID)
+          && Iteration <= 99)
           TM.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
                               mateThreat, &moveCount, &mp, threadID, PvNode);
     }
@@ -1675,9 +1673,9 @@ namespace {
 
       // Step 12. Futility pruning (is omitted in PV nodes)
       if (   !PvNode
+          && !captureOrPromotion
           && !isCheck
           && !dangerous
-          && !captureOrPromotion
           && !move_is_castle(move))
       {
           // Move count based pruning
@@ -1711,8 +1709,8 @@ namespace {
       // If the move fails high will be re-searched at full depth.
       bool doFullDepthSearch = true;
 
-      if (   !dangerous
-          && !captureOrPromotion
+      if (   !captureOrPromotion
+          && !dangerous
           && !move_is_castle(move)
           && !move_is_killer(move, ss))
       {
@@ -1720,7 +1718,9 @@ namespace {
           if (ss->reduction)
           {
               Value localAlpha = sp->alpha;
-              value = -search<NonPV>(pos, ss+1, -(localAlpha+1), -localAlpha, newDepth-ss->reduction, true, threadID);
+              Depth d = newDepth - ss->reduction;
+              value = d < OnePly ? -qsearch<NonPV>(pos, ss+1, -(localAlpha+1), -localAlpha, Depth(0), threadID)
+                                 : - search<NonPV>(pos, ss+1, -(localAlpha+1), -localAlpha, d, true, threadID);
               doFullDepthSearch = (value > localAlpha);
           }
 
@@ -1729,22 +1729,29 @@ namespace {
           // if the move fails high again then go with full depth search.
           if (doFullDepthSearch && ss->reduction > 2 * OnePly)
           {
+              assert(newDepth - OnePly >= OnePly);
+
               ss->reduction = OnePly;
               Value localAlpha = sp->alpha;
               value = -search<NonPV>(pos, ss+1, -(localAlpha+1), -localAlpha, newDepth-ss->reduction, true, threadID);
               doFullDepthSearch = (value > localAlpha);
           }
+          ss->reduction = Depth(0); // Restore original reduction
       }
 
       // Step 15. Full depth search
       if (doFullDepthSearch)
       {
-          ss->reduction = Depth(0);
           Value localAlpha = sp->alpha;
-          value = -search<NonPV>(pos, ss+1, -(localAlpha+1), -localAlpha, newDepth, true, threadID);
+          value = newDepth < OnePly ? -qsearch<NonPV>(pos, ss+1, -(localAlpha+1), -localAlpha, Depth(0), threadID)
+                                    : - search<NonPV>(pos, ss+1, -(localAlpha+1), -localAlpha, newDepth, true, threadID);
 
+          // Step extra. pv search (only in PV nodes)
+          // Search only for possible new PV nodes, if instead value >= beta then
+          // parent node fails low with value <= alpha and tries another move.
           if (PvNode && value > localAlpha && value < sp->beta)
-              value = -search<PV>(pos, ss+1, -sp->beta, -sp->alpha, newDepth, false, threadID);
+              value = newDepth < OnePly ? -qsearch<PV>(pos, ss+1, -sp->beta, -sp->alpha, Depth(0), threadID)
+                                        : - search<PV>(pos, ss+1, -sp->beta, -sp->alpha, newDepth, false, threadID);
       }
 
       // Step 16. Undo move
@@ -1965,20 +1972,6 @@ namespace {
   }
 
 
-  // ok_to_do_nullmove() looks at the current position and decides whether
-  // doing a 'null move' should be allowed. In order to avoid zugzwang
-  // problems, null moves are not allowed when the side to move has very
-  // little material left. Currently, the test is a bit too simple: Null
-  // moves are avoided only when the side to move has only pawns left.
-  // It's probably a good idea to avoid null moves in at least some more
-  // complicated endgames, e.g. KQ vs KR.  FIXME
-
-  bool ok_to_do_nullmove(const Position& pos) {
-
-    return pos.non_pawn_material(pos.side_to_move()) != Value(0);
-  }
-
-
   // connected_threat() tests whether it is safe to forward prune a move or if
   // is somehow coonected to the threat move returned by null search.