]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Debugging: move debug function definitions in misc.cpp
[stockfish] / src / search.cpp
index bc66ebad15751eefb3b037ea9f446e455f11b4ef..f80d5ccb496d527fa93922a8e060c220239cc706 100644 (file)
@@ -106,6 +106,9 @@ namespace {
   const bool UseIIDAtPVNodes = true;
   const bool UseIIDAtNonPVNodes = false;
 
+  // Use null move driven internal iterative deepening?
+  bool UseNullDrivenIID = false;
+
   // Internal iterative deepening margin.  At Non-PV moves, when
   // UseIIDAtNonPVNodes is true, we do an internal iterative deepening search
   // when the static evaluation is at most IIDMargin below beta.
@@ -188,7 +191,7 @@ namespace {
   // Time managment variables
   int SearchStartTime;
   int MaxNodes, MaxDepth;
-  int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, TimeAdvantage;
+  int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime;
   Move BestRootMove, PonderMove, EasyMove;
   int RootMoveNumber;
   bool InfiniteSearch;
@@ -390,6 +393,7 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
   if (UseLogFile)
       LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
 
+  UseNullDrivenIID = get_option_value_bool("Null driven IID");
   UseQSearchFutilityPruning = get_option_value_bool("Futility Pruning (Quiescence Search)");
   UseFutilityPruning = get_option_value_bool("Futility Pruning (Main Search)");
 
@@ -427,8 +431,6 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
   int myIncrement = increment[side_to_move];
   int oppTime = time[1 - side_to_move];
 
-  TimeAdvantage = myTime - oppTime;
-
   if (!movesToGo) // Sudden death time control
   {
       if (myIncrement)
@@ -680,10 +682,6 @@ namespace {
                 ExtraSearchTime = BestMoveChangesByIteration[Iteration]   * (MaxSearchTime / 2)
                                 + BestMoveChangesByIteration[Iteration-1] * (MaxSearchTime / 3);
 
-            // If we need some more and we are in time advantage take it
-            if (ExtraSearchTime > 0 && TimeAdvantage > 2 * MaxSearchTime)
-                ExtraSearchTime += MaxSearchTime / 2;
-
             // Try to guess if the current iteration is the last one or the last two
             LastIterations = (current_search_time() > ((MaxSearchTime + ExtraSearchTime)*58) / 128);
 
@@ -731,6 +729,12 @@ namespace {
 
     if (UseLogFile)
     {
+        if (dbg_show_mean)
+            dbg_print_mean(LogFile);
+
+        if (dbg_show_hit_rate)
+            dbg_print_hit_rate(LogFile);
+
         UndoInfo u;
         LogFile << "Nodes: " << nodes_searched() << std::endl
                 << "Nodes/second: " << nps() << std::endl
@@ -1130,16 +1134,18 @@ namespace {
 
     if (tte && ok_to_use_TT(tte, depth, beta, ply))
     {
-        ss[ply].currentMove = ttMove; // can be MOVE_NONE ?
+        ss[ply].currentMove = ttMove; // can be MOVE_NONE
         return value_from_tt(tte->value(), ply);
     }
 
     Value approximateEval = quick_evaluate(pos);
     bool mateThreat = false;
+    bool nullDrivenIID = false;
     bool isCheck = pos.is_check();
 
     // Null move search
     if (    allowNullmove
+        &&  depth > OnePly
         && !isCheck
         &&  ok_to_do_nullmove(pos)
         &&  approximateEval >= beta - NullMoveMargin)
@@ -1149,7 +1155,21 @@ namespace {
         UndoInfo u;
         pos.do_null_move(u);
         int R = (depth > 7 ? 4 : 3);
+
         Value nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
+
+        // Check for a null capture artifact, if the value without the null capture
+        // is above beta then there is a good possibility that this is a cut-node.
+        // We will do an IID later to find a ttMove.
+        if (   UseNullDrivenIID
+            && nullValue < beta
+            && depth > 6 * OnePly
+            && ttMove == MOVE_NONE
+            && ss[ply + 1].currentMove != MOVE_NONE
+            && pos.move_is_capture(ss[ply + 1].currentMove)
+            && pos.see(ss[ply + 1].currentMove) + nullValue >= beta)
+            nullDrivenIID = true;
+
         pos.undo_null_move(u);
 
         if (nullValue >= beta)
@@ -1163,14 +1183,16 @@ namespace {
                 return beta;
         } 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
+            // some kind of threat. If the previous move was reduced, check if
             // the move that refuted the null move was somehow connected to the
-            // move which was reduced.  If a connection is found, return a fail
+            // move which was reduced. If a connection is found, return a fail
             // low score (which will cause the reduced move to fail high in the
             // parent node, which will trigger a re-search with full depth).
             if (nullValue == value_mated_in(ply + 2))
+            {
                 mateThreat = true;
-
+                nullDrivenIID = false;
+            }
             ss[ply].threatMove = ss[ply + 1].currentMove;
             if (   depth < ThreatDepth
                 && ss[ply - 1].reduction
@@ -1194,6 +1216,20 @@ namespace {
         search(pos, ss, beta, Min(depth/2, depth-2*OnePly), ply, false, threadID);
         ttMove = ss[ply].pv[ply];
     }
+    else if (nullDrivenIID)
+    {
+        // The null move failed low due to a suspicious capture. Perhaps we
+        // are facing a null capture artifact due to the side to move change
+        // and this is a cut-node. So it's a good time to search for a ttMove.
+        Move tm = ss[ply].threatMove;
+
+        assert(tm != MOVE_NONE);
+        assert(ttMove == MOVE_NONE);
+
+        search(pos, ss, beta, depth/2, ply, false, threadID);
+        ttMove = ss[ply].pv[ply];
+        ss[ply].threatMove = tm;
+    }
 
     // Initialize a MovePicker object for the current position, and prepare
     // to search all moves:
@@ -2128,31 +2164,34 @@ namespace {
     tto = move_to(threat);
 
     // Case 1: Castling moves are never pruned.
-    if(move_is_castle(m))
-      return false;
+    if (move_is_castle(m))
+        return false;
 
     // Case 2: Don't prune moves which move the threatened piece
-    if(!PruneEscapeMoves && threat != MOVE_NONE && mfrom == tto)
-      return false;
+    if (!PruneEscapeMoves && threat != MOVE_NONE && mfrom == tto)
+        return false;
 
     // Case 3: If the threatened piece has value less than or equal to the
     // value of the threatening piece, don't prune move which defend it.
-    if(!PruneDefendingMoves && threat != MOVE_NONE
-       && (piece_value_midgame(pos.piece_on(tfrom))
-           >= piece_value_midgame(pos.piece_on(tto)))
-       && pos.move_attacks_square(m, tto))
+    if (   !PruneDefendingMoves
+        && threat != MOVE_NONE
+        && pos.type_of_piece_on(tto) != NO_PIECE_TYPE
+        && (   pos.midgame_value_of_piece_on(tfrom) >= pos.midgame_value_of_piece_on(tto)
+            || pos.type_of_piece_on(tfrom) == KING)
+        && pos.move_attacks_square(m, tto))
       return false;
 
     // Case 4: Don't prune moves with good history.
-    if(!H.ok_to_prune(pos.piece_on(move_from(m)), m, d))
-      return false;
+    if (!H.ok_to_prune(pos.piece_on(move_from(m)), m, d))
+        return false;
 
     // Case 5: If the moving piece in the threatened move is a slider, don't
     // prune safe moves which block its ray.
-    if(!PruneBlockingMoves && threat != MOVE_NONE
-       && piece_is_slider(pos.piece_on(tfrom))
-       && bit_is_set(squares_between(tfrom, tto), mto) && pos.see(m) >= 0)
-      return false;
+    if (  !PruneBlockingMoves
+        && threat != MOVE_NONE
+        && piece_is_slider(pos.piece_on(tfrom))
+        && bit_is_set(squares_between(tfrom, tto), mto) && pos.see(m) >= 0)
+            return false;
 
     return true;
   }