- // Do we have time for the next iteration? Can we stop searching now?
- if (Limits.use_time_management() && !Signals.stop && !Signals.stopOnPonderhit)
- {
- // Take some extra time if the best move has changed
- if (depth > 4 * ONE_PLY && multiPV == 1)
- TimeMgr.pv_instability(BestMoveChanges);
-
- // Stop the search if only one legal move is available or all
- // of the available time has been used.
- if ( RootMoves.size() == 1
- || Time::now() - SearchTime > TimeMgr.available_time())
- {
- // If we are allowed to ponder do not stop the search now but
- // keep pondering until the GUI sends "ponderhit" or "stop".
- if (Limits.ponder)
- Signals.stopOnPonderhit = true;
- else
- Signals.stop = true;
- }
- }
- }
+ // When failing high/low give some update (without cluttering
+ // the UI) before a re-search.
+ if ( mainThread
+ && multiPV == 1
+ && (bestValue <= alpha || bestValue >= beta)
+ && Time.elapsed() > 3000)
+ sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
+
+ // In case of failing low/high increase aspiration window and
+ // re-search, otherwise exit the loop.
+ if (bestValue <= alpha)
+ {
+ beta = (alpha + beta) / 2;
+ alpha = std::max(bestValue - delta, -VALUE_INFINITE);
+
+ if (mainThread)
+ {
+ failedLow = true;
+ Threads.stopOnPonderhit = false;
+ }
+ }
+ else if (bestValue >= beta)
+ beta = std::min(bestValue + delta, VALUE_INFINITE);
+ else
+ break;
+
+ delta += delta / 4 + 5;
+
+ assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
+ }
+
+ // Sort the PV lines searched so far and update the GUI
+ std::stable_sort(rootMoves.begin() + pvFirst, rootMoves.begin() + pvIdx + 1);
+
+ if ( mainThread
+ && (Threads.stop || pvIdx + 1 == multiPV || Time.elapsed() > 3000))
+ sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
+ }
+
+ if (!Threads.stop)
+ completedDepth = rootDepth;
+
+ if (rootMoves[0].pv[0] != lastBestMove) {
+ lastBestMove = rootMoves[0].pv[0];
+ lastBestMoveDepth = rootDepth;
+ }
+
+ // Have we found a "mate in x"?
+ if ( Limits.mate
+ && bestValue >= VALUE_MATE_IN_MAX_PLY
+ && VALUE_MATE - bestValue <= 2 * Limits.mate)
+ Threads.stop = true;
+
+ if (!mainThread)
+ continue;
+
+ // If skill level is enabled and time is up, pick a sub-optimal best move
+ if (skill.enabled() && skill.time_to_pick(rootDepth))
+ skill.pick_best(multiPV);
+
+ // Do we have time for the next iteration? Can we stop searching now?
+ if ( Limits.use_time_management()
+ && !Threads.stop
+ && !Threads.stopOnPonderhit)
+ {
+ const int F[] = { failedLow,
+ bestValue - mainThread->previousScore };
+
+ int improvingFactor = std::max(246, std::min(832, 306 + 119 * F[0] - 6 * F[1]));
+
+ // If the bestMove is stable over several iterations, reduce time accordingly
+ timeReduction = 1.0;
+ for (int i : {3, 4, 5})
+ if (lastBestMoveDepth * i < completedDepth)
+ timeReduction *= 1.25;