- // 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 && 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)
+ {
+ mainThread->failedLow = true;
+ Signals.stopOnPonderhit = false;
+ }
+ }
+ else if (bestValue >= beta)
+ {
+ alpha = (alpha + beta) / 2;
+ 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(), rootMoves.begin() + PVIdx + 1);
+
+ if (!mainThread)
+ break;
+
+ if (Signals.stop)
+ sync_cout << "info nodes " << Threads.nodes_searched()
+ << " time " << Time.elapsed() << sync_endl;
+
+ else if (PVIdx + 1 == multiPV || Time.elapsed() > 3000)
+ sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
+ }
+
+ if (!Signals.stop)
+ completedDepth = rootDepth;
+
+ 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);
+
+ // Have we found a "mate in x"?
+ if ( Limits.mate
+ && bestValue >= VALUE_MATE_IN_MAX_PLY
+ && VALUE_MATE - bestValue <= 2 * Limits.mate)
+ Signals.stop = true;
+
+ // Do we have time for the next iteration? Can we stop searching now?
+ if (Limits.use_time_management())
+ {
+ if (!Signals.stop && !Signals.stopOnPonderhit)
+ {
+ // Take some extra time if the best move has changed
+ if (rootDepth > 4 * ONE_PLY && multiPV == 1)
+ Time.pv_instability(mainThread->bestMoveChanges);
+
+ // Stop the search if only one legal move is available, or if all
+ // of the available time has been used, or if we matched an easyMove
+ // from the previous search and just did a fast verification.
+ const bool F[] = { !mainThread->failedLow,
+ bestValue >= mainThread->previousScore };
+
+ int improvingFactor = 640 - 160*F[0] - 126*F[1] - 124*F[0]*F[1];
+
+ bool doEasyMove = rootMoves[0].pv[0] == easyMove
+ && mainThread->bestMoveChanges < 0.03
+ && Time.elapsed() > Time.available() * 25 / 206;
+
+ if ( rootMoves.size() == 1
+ || Time.elapsed() > Time.available() * improvingFactor / 640
+ || (mainThread->easyMovePlayed = doEasyMove))
+ {
+ // 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;
+ }
+ }
+
+ if (rootMoves[0].pv.size() >= 3)
+ EasyMove.update(rootPos, rootMoves[0].pv);
+ else
+ EasyMove.clear();
+ }