mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-20 09:06:45 +08:00
STC (http://tests.stockfishchess.org/tests/view/598188a40ebc5916ff64a21b): LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 25363 W: 4658 L: 4545 D: 16160 LTC (http://tests.stockfishchess.org/tests/view/5981d59a0ebc5916ff64a229): LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 75356 W: 9690 L: 9640 D: 56026 40/10 TC (http://tests.stockfishchess.org/tests/view/5980c5780ebc5916ff64a1ed): LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 19377 W: 3650 L: 3526 D: 12201 15+0 TC (http://tests.stockfishchess.org/tests/view/5982cb730ebc5916ff64a25d): LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 5913 W: 1217 L: 1069 D: 3627 This time management handles base time and movestogo cases separatelly. One can test one case without affecting the other. Also, increment usage can be tested separately without (necessarily) affecting sudden death or x moves in y seconds performance. On stable machines there are no time losses on 0.1+0.001 time control (tested on i7 + Windows 10 platform). Bench 5608839
110 lines
3.8 KiB
C++
110 lines
3.8 KiB
C++
/*
|
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
|
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
|
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
|
|
|
Stockfish is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <cfloat>
|
|
#include <cmath>
|
|
|
|
#include "search.h"
|
|
#include "timeman.h"
|
|
#include "uci.h"
|
|
|
|
TimeManagement Time; // Our global time management object
|
|
|
|
namespace {
|
|
|
|
enum TimeType { OptimumTime, MaxTime };
|
|
|
|
int remaining(int myTime, int myInc, int moveOverhead,
|
|
int movesToGo, int ply, TimeType type) {
|
|
|
|
if (myTime <= 0)
|
|
return 0;
|
|
|
|
int moveNumber = (ply + 1) / 2;
|
|
double ratio; // Which ratio of myTime we are going to use. It is <= 1
|
|
double sd = 8.5;
|
|
|
|
// Usage of increment follows quadratic distribution with the maximum at move 25
|
|
double inc = myInc * std::max(55.0, 120.0 - 0.12 * (moveNumber - 25) * (moveNumber - 25));
|
|
|
|
// In moves-to-go we distribute time according to a quadratic function with
|
|
// the maximum around move 20 for 40 moves in y time case.
|
|
if (movesToGo)
|
|
{
|
|
ratio = (type == OptimumTime ? 1.0 : 6.0) / std::min(50, movesToGo);
|
|
|
|
if (moveNumber <= 40)
|
|
ratio *= 1.1 - 0.001 * (moveNumber - 20) * (moveNumber - 20);
|
|
else
|
|
ratio *= 1.5;
|
|
}
|
|
// Otherwise we increase usage of remaining time as the game goes on
|
|
else
|
|
{
|
|
sd = 1 + 20 * moveNumber / (500.0 + moveNumber);
|
|
ratio = (type == OptimumTime ? 0.017 : 0.07) * sd;
|
|
}
|
|
|
|
ratio = std::min(1.0, ratio * (1 + inc / (myTime * sd)));
|
|
|
|
return int(ratio * std::max(0, myTime - moveOverhead));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
/// init() is called at the beginning of the search and calculates the allowed
|
|
/// thinking time out of the time control and current game ply. We support four
|
|
/// different kinds of time controls, passed in 'limits':
|
|
///
|
|
/// inc == 0 && movestogo == 0 means: x basetime [sudden death!]
|
|
/// inc == 0 && movestogo != 0 means: x moves in y minutes
|
|
/// inc > 0 && movestogo == 0 means: x basetime + z increment
|
|
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
|
|
|
|
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
|
|
{
|
|
int moveOverhead = Options["Move Overhead"];
|
|
int npmsec = Options["nodestime"];
|
|
|
|
// If we have to play in 'nodes as time' mode, then convert from time
|
|
// to nodes, and use resulting values in time management formulas.
|
|
// WARNING: Given npms (nodes per millisecond) must be much lower then
|
|
// the real engine speed to avoid time losses.
|
|
if (npmsec)
|
|
{
|
|
if (!availableNodes) // Only once at game start
|
|
availableNodes = npmsec * limits.time[us]; // Time is in msec
|
|
|
|
// Convert from millisecs to nodes
|
|
limits.time[us] = (int)availableNodes;
|
|
limits.inc[us] *= npmsec;
|
|
limits.npmsec = npmsec;
|
|
}
|
|
|
|
startTime = limits.startTime;
|
|
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);
|
|
|
|
if (Options["Ponder"])
|
|
optimumTime += optimumTime / 4;
|
|
}
|