mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 08:43:09 +00:00

What this patch does is: * increase safety margin from 40ms to 60ms. It's worth noting that the previous code not only used 60ms incompressible safety margin, but also an additional buffer of 30ms for each "move to go". * remove a whart, integrating the extra 10ms in Move Overhead value instead. Additionally, this ensures that optimumtime doesn't become bigger than maximum time after maximum time has been artificially discounted by 10ms. So it keeps the code more logical. Tested at 3 different time controls: Standard 10+0.1 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 58008 W: 10674 L: 10617 D: 36717 Sudden death 16+0 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 59664 W: 10945 L: 10891 D: 37828 Tournament 40/10 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 16371 W: 3092 L: 2963 D: 10316 bench: 5479946
112 lines
3.9 KiB
C++
112 lines
3.9 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 "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 moveNum, bool ponder, TimeType type) {
|
|
|
|
if (myTime <= 0)
|
|
return 0;
|
|
|
|
double ratio; // Which ratio of myTime we are going to use
|
|
|
|
// Usage of increment follows quadratic distribution with the maximum at move 25
|
|
double inc = myInc * std::max(55.0, 120 - 0.12 * (moveNum - 25) * (moveNum - 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 (moveNum <= 40)
|
|
ratio *= 1.1 - 0.001 * (moveNum - 20) * (moveNum - 20);
|
|
else
|
|
ratio *= 1.5;
|
|
|
|
ratio *= 1 + inc / (myTime * 8.5);
|
|
}
|
|
// Otherwise we increase usage of remaining time as the game goes on
|
|
else
|
|
{
|
|
double k = 1 + 20 * moveNum / (500.0 + moveNum);
|
|
ratio = (type == OptimumTime ? 0.017 : 0.07) * (k + inc / myTime);
|
|
}
|
|
|
|
int time = int(std::min(1.0, ratio) * std::max(0, myTime - moveOverhead));
|
|
|
|
if (type == OptimumTime && ponder)
|
|
time *= 1.25;
|
|
|
|
return time;
|
|
}
|
|
|
|
} // 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"];
|
|
bool ponder = Options["Ponder"];
|
|
|
|
// 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;
|
|
}
|
|
|
|
int moveNum = (ply + 1) / 2;
|
|
|
|
startTime = limits.startTime;
|
|
optimumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
|
|
limits.movestogo, moveNum, ponder, OptimumTime);
|
|
maximumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
|
|
limits.movestogo, moveNum, ponder, MaxTime);
|
|
}
|