Subversion Repositories Games.Chess Giants

Rev

Rev 169 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
  3.   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
  4.   Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
  5.   Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
  6.  
  7.   Stockfish is free software: you can redistribute it and/or modify
  8.   it under the terms of the GNU General Public License as published by
  9.   the Free Software Foundation, either version 3 of the License, or
  10.   (at your option) any later version.
  11.  
  12.   Stockfish is distributed in the hope that it will be useful,
  13.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.   GNU General Public License for more details.
  16.  
  17.   You should have received a copy of the GNU General Public License
  18.   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19. */
  20.  
  21. #include <algorithm>
  22. #include <cfloat>
  23. #include <cmath>
  24.  
  25. #include "search.h"
  26. #include "timeman.h"
  27. #include "uci.h"
  28.  
  29. TimeManagement Time; // Our global time management object
  30.  
  31. namespace {
  32.  
  33.   enum TimeType { OptimumTime, MaxTime };
  34.  
  35.   constexpr int MoveHorizon   = 50;   // Plan time management at most this many moves ahead
  36.   constexpr double MaxRatio   = 7.3;  // When in trouble, we can step over reserved time with this ratio
  37.   constexpr double StealRatio = 0.34; // However we must not steal time from remaining moves over this ratio
  38.  
  39.  
  40.   // move_importance() is a skew-logistic function based on naive statistical
  41.   // analysis of "how many games are still undecided after n half-moves". Game
  42.   // is considered "undecided" as long as neither side has >275cp advantage.
  43.   // Data was extracted from the CCRL game database with some simple filtering criteria.
  44.  
  45.   double move_importance(int ply) {
  46.  
  47.     constexpr double XScale = 6.85;
  48.     constexpr double XShift = 64.5;
  49.     constexpr double Skew   = 0.171;
  50.  
  51.     return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
  52.   }
  53.  
  54.   template<TimeType T>
  55.   TimePoint remaining(TimePoint myTime, int movesToGo, int ply, TimePoint slowMover) {
  56.  
  57.     constexpr double TMaxRatio   = (T == OptimumTime ? 1.0 : MaxRatio);
  58.     constexpr double TStealRatio = (T == OptimumTime ? 0.0 : StealRatio);
  59.  
  60.     double moveImportance = (move_importance(ply) * slowMover) / 100.0;
  61.     double otherMovesImportance = 0.0;
  62.  
  63.     for (int i = 1; i < movesToGo; ++i)
  64.         otherMovesImportance += move_importance(ply + 2 * i);
  65.  
  66.     double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
  67.     double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
  68.  
  69.     return TimePoint(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
  70.   }
  71.  
  72. } // namespace
  73.  
  74.  
  75. /// init() is called at the beginning of the search and calculates the allowed
  76. /// thinking time out of the time control and current game ply. We support four
  77. /// different kinds of time controls, passed in 'limits':
  78. ///
  79. ///  inc == 0 && movestogo == 0 means: x basetime  [sudden death!]
  80. ///  inc == 0 && movestogo != 0 means: x moves in y minutes
  81. ///  inc >  0 && movestogo == 0 means: x basetime + z increment
  82. ///  inc >  0 && movestogo != 0 means: x moves in y minutes + z increment
  83.  
  84. void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
  85.  
  86.   TimePoint minThinkingTime = Options["Minimum Thinking Time"];
  87.   TimePoint moveOverhead    = Options["Move Overhead"];
  88.   TimePoint slowMover       = Options["Slow Mover"];
  89.   TimePoint npmsec          = Options["nodestime"];
  90.   TimePoint hypMyTime;
  91.  
  92.   // If we have to play in 'nodes as time' mode, then convert from time
  93.   // to nodes, and use resulting values in time management formulas.
  94.   // WARNING: to avoid time losses, the given npmsec (nodes per millisecond)
  95.   // must be much lower than the real engine speed.
  96.   if (npmsec)
  97.   {
  98.       if (!availableNodes) // Only once at game start
  99.           availableNodes = npmsec * limits.time[us]; // Time is in msec
  100.  
  101.       // Convert from milliseconds to nodes
  102.       limits.time[us] = TimePoint(availableNodes);
  103.       limits.inc[us] *= npmsec;
  104.       limits.npmsec = npmsec;
  105.   }
  106.  
  107.   startTime = limits.startTime;
  108.   optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
  109.  
  110.   const int maxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
  111.  
  112.   // We calculate optimum time usage for different hypothetical "moves to go" values
  113.   // and choose the minimum of calculated search time values. Usually the greatest
  114.   // hypMTG gives the minimum values.
  115.   for (int hypMTG = 1; hypMTG <= maxMTG; ++hypMTG)
  116.   {
  117.       // Calculate thinking time for hypothetical "moves to go"-value
  118.       hypMyTime =  limits.time[us]
  119.                  + limits.inc[us] * (hypMTG - 1)
  120.                  - moveOverhead * (2 + std::min(hypMTG, 40));
  121.  
  122.       hypMyTime = std::max(hypMyTime, TimePoint(0));
  123.  
  124.       TimePoint t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
  125.       TimePoint t2 = minThinkingTime + remaining<MaxTime    >(hypMyTime, hypMTG, ply, slowMover);
  126.  
  127.       optimumTime = std::min(t1, optimumTime);
  128.       maximumTime = std::min(t2, maximumTime);
  129.   }
  130.  
  131.   if (Options["Ponder"])
  132.       optimumTime += optimumTime / 4;
  133. }
  134.