along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-////
-//// Includes
-////
-
#include <cmath>
+#include <algorithm>
#include "misc.h"
+#include "search.h"
+#include "timeman.h"
#include "ucioption.h"
-////
-//// Local definitions
-////
-
namespace {
/// Constants
- const int MaxMoveHorizon = 50; // Plan time management at most this many moves ahead
- const float MaxRatio = 3.0; // When in trouble, we can step over reserved time with this ratio
- const float MaxStealRatio = 0.33; // However we must not steal time from remaining moves over this ratio
+ const int MoveHorizon = 50; // Plan time management at most this many moves ahead
+ const float MaxRatio = 3.0f; // When in trouble, we can step over reserved time with this ratio
+ const float StealRatio = 0.33f; // However we must not steal time from remaining moves over this ratio
// MoveImportance[] is based on naive statistical analysis of "how many games are still undecided
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1 };
- int move_importance(int ply) { return MoveImportance[Min(ply, 511)]; }
+ int move_importance(int ply) { return MoveImportance[std::min(ply, 511)]; }
/// Function Prototypes
- int min_time_for_MTG(int myTime, int movesToGo, int currentPly);
- int max_time_for_MTG(int myTime, int movesToGo, int currentPly);
+ enum TimeType { OptimumTime, MaxTime };
+
+ template<TimeType>
+ int remaining(int myTime, int movesToGo, int fullMoveNumber);
}
-////
-//// Functions
-////
+void TimeManager::pv_instability(int curChanges, int prevChanges) {
-void get_search_times(int myTime, int myInc, int movesToGo, int currentPly,
- int* maxSearchTime, int* absoluteMaxSearchTime)
+ unstablePVExtraTime = curChanges * (optimumSearchTime / 2)
+ + prevChanges * (optimumSearchTime / 3);
+}
+
+
+void TimeManager::init(const Search::LimitsType& limits, int currentPly)
{
/* We support four different kind of time controls:
- Inc == 0 && movesToGo == 0 means: x basetime [sudden death!]
- Inc == 0 && movesToGo != 0 means: (x moves) / (y minutes)
- Inc > 0 && movesToGo == 0 means: x basetime + z inc.
- Inc > 0 && movesToGo != 0 means: (x moves) / (y minutes) + z inc
+ increment == 0 && movesToGo == 0 means: x basetime [sudden death!]
+ increment == 0 && movesToGo != 0 means: x moves in y minutes
+ increment > 0 && movesToGo == 0 means: x basetime + z increment
+ increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment
Time management is adjusted by following UCI parameters:
- emergencyMoveHorizon :Be prepared to always play at least this many moves
- emergencyBaseTime :Always attempt to keep at least this much time (in ms) at clock
- emergencyMoveTime :Plus attempt to keep at least this much time for each remaining emergency move
- minThinkingTime :No matter what, use at least this much thinking before doing the move
+ emergencyMoveHorizon: Be prepared to always play at least this many moves
+ emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock
+ emergencyMoveTime : Plus attempt to keep at least this much time for each remaining emergency move
+ minThinkingTime : No matter what, use at least this much thinking before doing the move
*/
- int hypMTG, hypMyTime;
+ int hypMTG, hypMyTime, t1, t2;
// Read uci parameters
- int emergencyMoveHorizon = get_option_value_int("Emergency Move Horizon");
- int emergencyBaseTime = get_option_value_int("Emergency Base Time");
- int emergencyMoveTime = get_option_value_int("Emergency Move Time");
- int minThinkingTime = get_option_value_int("Minimum Thinking Time");
+ int emergencyMoveHorizon = Options["Emergency Move Horizon"].value<int>();
+ int emergencyBaseTime = Options["Emergency Base Time"].value<int>();
+ int emergencyMoveTime = Options["Emergency Move Time"].value<int>();
+ int minThinkingTime = Options["Minimum Thinking Time"].value<int>();
- // Initialize variables to maximum values
- *maxSearchTime = *absoluteMaxSearchTime = myTime;
+ // Initialize to maximum values but unstablePVExtraTime that is reset
+ unstablePVExtraTime = 0;
+ optimumSearchTime = maximumSearchTime = limits.time;
// We calculate optimum time usage for different hypothetic "moves to go"-values and choose the
// minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values.
- for (hypMTG = 1; hypMTG <= (movesToGo ? Min(movesToGo, MaxMoveHorizon) : MaxMoveHorizon); hypMTG++)
+ for (hypMTG = 1; hypMTG <= (limits.movesToGo ? std::min(limits.movesToGo, MoveHorizon) : MoveHorizon); hypMTG++)
{
// Calculate thinking time for hypothetic "moves to go"-value
- hypMyTime = Max(myTime + (hypMTG - 1) * myInc - emergencyBaseTime - Min(hypMTG, emergencyMoveHorizon) * emergencyMoveTime, 0);
+ hypMyTime = limits.time
+ + limits.increment * (hypMTG - 1)
+ - emergencyBaseTime
+ - emergencyMoveTime * std::min(hypMTG, emergencyMoveHorizon);
+
+ hypMyTime = std::max(hypMyTime, 0);
+
+ t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly);
+ t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly);
- *maxSearchTime = Min(*maxSearchTime, minThinkingTime + min_time_for_MTG(hypMyTime, hypMTG, currentPly));
- *absoluteMaxSearchTime = Min(*absoluteMaxSearchTime, minThinkingTime + max_time_for_MTG(hypMyTime, hypMTG, currentPly));
+ optimumSearchTime = std::min(optimumSearchTime, t1);
+ maximumSearchTime = std::min(maximumSearchTime, t2);
}
+ if (Options["Ponder"].value<bool>())
+ optimumSearchTime += optimumSearchTime / 4;
+
// Make sure that maxSearchTime is not over absoluteMaxSearchTime
- *maxSearchTime = Min(*maxSearchTime, *absoluteMaxSearchTime);
+ optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime);
}
-////
-//// Local functions
-////
namespace {
- int min_time_for_MTG(int myTime, int movesToGo, int currentPly)
+ template<TimeType T>
+ int remaining(int myTime, int movesToGo, int currentPly)
{
- float thisMoveImportance = move_importance(currentPly);
- float otherMovesImportance = 0;
+ const float TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
+ const float TStealRatio = (T == OptimumTime ? 0 : StealRatio);
- for (int i = 1; i < movesToGo; i++)
- otherMovesImportance += move_importance(currentPly + 2 * i);
-
- float ratio = thisMoveImportance / (thisMoveImportance + otherMovesImportance);
-
- return int(floor(myTime * ratio));
- }
-
- int max_time_for_MTG(int myTime, int movesToGo, int currentPly)
- {
- float thisMoveImportance = move_importance(currentPly);
- float otherMovesImportance = 0;
+ int thisMoveImportance = move_importance(currentPly);
+ int otherMovesImportance = 0;
for (int i = 1; i < movesToGo; i++)
otherMovesImportance += move_importance(currentPly + 2 * i);
- float ratio1 = (MaxRatio * thisMoveImportance) / (MaxRatio * thisMoveImportance + otherMovesImportance);
- float ratio2 = (thisMoveImportance + MaxStealRatio * otherMovesImportance) / (thisMoveImportance + otherMovesImportance);
+ float ratio1 = (TMaxRatio * thisMoveImportance) / float(TMaxRatio * thisMoveImportance + otherMovesImportance);
+ float ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / float(thisMoveImportance + otherMovesImportance);
- return int(floor(myTime * Min(ratio1, ratio2)));
+ return int(floor(myTime * std::min(ratio1, ratio2)));
}
}
-