- optimumTime = remaining(limits.time[us], limits.inc[us], moveOverhead, limits.movestogo, ply, OptimumTime);
- maximumTime = remaining(limits.time[us], limits.inc[us], moveOverhead, limits.movestogo, ply, MaxTime);
+
+ // Maximum move horizon of 50 moves
+ int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
+
+ // Make sure timeLeft is > 0 since we may use it as a divisor
+ TimePoint timeLeft = std::max(TimePoint(1),
+ limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg));
+
+ // A user may scale time usage by setting UCI option "Slow Mover"
+ // Default is 100 and changing this value will probably lose elo.
+ timeLeft = slowMover * timeLeft / 100;
+
+ // x basetime (+ z increment)
+ // If there is a healthy increment, timeLeft can exceed actual available
+ // game time for the current move, so also cap to 20% of available game time.
+ if (limits.movestogo == 0)
+ {
+ optScale = std::min(0.0084 + std::pow(ply + 3.0, 0.5) * 0.0042,
+ 0.2 * limits.time[us] / double(timeLeft));
+ maxScale = std::min(7.0, 4.0 + ply / 12.0);
+ }
+
+ // x moves in y seconds (+ z increment)
+ else
+ {
+ optScale = std::min((0.8 + ply / 128.0) / mtg,
+ 0.8 * limits.time[us] / double(timeLeft));
+ maxScale = std::min(6.3, 1.5 + 0.11 * mtg);
+ }
+
+ // Never use more than 80% of the available time for this move
+ optimumTime = TimePoint(optScale * timeLeft);
+ maximumTime = TimePoint(std::min(0.8 * limits.time[us] - moveOverhead, maxScale * optimumTime));