mirror of
https://github.com/sockspls/badfish
synced 2025-07-11 19:49:14 +00:00
Introduce and use SearchLimits
Pack a bit of global variables related to search limits in a single struct. No functional change. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
bbfe452f85
commit
1d368bbbdc
6 changed files with 112 additions and 119 deletions
|
@ -73,7 +73,7 @@ void benchmark(int argc, char* argv[]) {
|
||||||
|
|
||||||
vector<string> positions;
|
vector<string> positions;
|
||||||
string ttSize, threads, valStr, posFile, valType;
|
string ttSize, threads, valStr, posFile, valType;
|
||||||
int val, secsPerPos, maxDepth, maxNodes;
|
int val, maxTime, maxDepth, maxNodes;
|
||||||
|
|
||||||
ttSize = argc > 2 ? argv[2] : "128";
|
ttSize = argc > 2 ? argv[2] : "128";
|
||||||
threads = argc > 3 ? argv[3] : "1";
|
threads = argc > 3 ? argv[3] : "1";
|
||||||
|
@ -87,13 +87,13 @@ void benchmark(int argc, char* argv[]) {
|
||||||
Options["Use Search Log"].set_value("true");
|
Options["Use Search Log"].set_value("true");
|
||||||
Options["Search Log Filename"].set_value("bench.txt");
|
Options["Search Log Filename"].set_value("bench.txt");
|
||||||
|
|
||||||
secsPerPos = maxDepth = maxNodes = 0;
|
maxTime = maxDepth = maxNodes = 0;
|
||||||
val = atoi(valStr.c_str());
|
val = atoi(valStr.c_str());
|
||||||
|
|
||||||
if (valType == "depth" || valType == "perft")
|
if (valType == "depth" || valType == "perft")
|
||||||
maxDepth = val;
|
maxDepth = val;
|
||||||
else if (valType == "time")
|
else if (valType == "time")
|
||||||
secsPerPos = val * 1000;
|
maxTime = val * 1000;
|
||||||
else
|
else
|
||||||
maxNodes = val;
|
maxNodes = val;
|
||||||
|
|
||||||
|
@ -124,8 +124,7 @@ void benchmark(int argc, char* argv[]) {
|
||||||
|
|
||||||
for (it = positions.begin(); it != positions.end(); ++it, ++cnt)
|
for (it = positions.begin(); it != positions.end(); ++it, ++cnt)
|
||||||
{
|
{
|
||||||
Move moves[1] = { MOVE_NONE };
|
Move moves[] = { MOVE_NONE };
|
||||||
int dummy[2] = { 0, 0 };
|
|
||||||
Position pos(*it, false, 0);
|
Position pos(*it, false, 0);
|
||||||
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
|
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
|
||||||
if (valType == "perft")
|
if (valType == "perft")
|
||||||
|
@ -134,7 +133,7 @@ void benchmark(int argc, char* argv[]) {
|
||||||
cerr << "\nPerft " << maxDepth << " result (nodes searched): " << perftCnt << endl << endl;
|
cerr << "\nPerft " << maxDepth << " result (nodes searched): " << perftCnt << endl << endl;
|
||||||
totalNodes += perftCnt;
|
totalNodes += perftCnt;
|
||||||
} else {
|
} else {
|
||||||
if (!think(pos, false, false, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
|
if (!think(pos, SearchLimits(0, 0, 0, maxTime, maxDepth, maxNodes, false, false), moves))
|
||||||
break;
|
break;
|
||||||
totalNodes += pos.nodes_searched();
|
totalNodes += pos.nodes_searched();
|
||||||
}
|
}
|
||||||
|
|
102
src/search.cpp
102
src/search.cpp
|
@ -116,8 +116,8 @@ namespace {
|
||||||
|
|
||||||
void extract_pv_from_tt(Position& pos);
|
void extract_pv_from_tt(Position& pos);
|
||||||
void insert_pv_in_tt(Position& pos);
|
void insert_pv_in_tt(Position& pos);
|
||||||
std::string pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha, Value beta, int pvIdx);
|
std::string pv_info_to_uci(Position& pos, int depth, int selDepth,
|
||||||
|
Value alpha, Value beta, int pvIdx);
|
||||||
int64_t nodes;
|
int64_t nodes;
|
||||||
Value pv_score;
|
Value pv_score;
|
||||||
Value non_pv_score;
|
Value non_pv_score;
|
||||||
|
@ -125,7 +125,7 @@ namespace {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// RootMoveList struct is just a std::vector<> of RootMove objects,
|
// RootMoveList struct is just a vector of RootMove objects,
|
||||||
// with an handful of methods above the standard ones.
|
// with an handful of methods above the standard ones.
|
||||||
|
|
||||||
struct RootMoveList : public std::vector<RootMove> {
|
struct RootMoveList : public std::vector<RootMove> {
|
||||||
|
@ -188,8 +188,8 @@ namespace {
|
||||||
|
|
||||||
// Step 11. Decide the new search depth
|
// Step 11. Decide the new search depth
|
||||||
|
|
||||||
// Extensions. Configurable UCI options
|
// Extensions. Configurable UCI options. Array index 0 is used at
|
||||||
// Array index 0 is used at non-PV nodes, index 1 at PV nodes.
|
// non-PV nodes, index 1 at PV nodes.
|
||||||
Depth CheckExtension[2], PawnPushTo7thExtension[2];
|
Depth CheckExtension[2], PawnPushTo7thExtension[2];
|
||||||
Depth PassedPawnExtension[2], PawnEndgameExtension[2];
|
Depth PassedPawnExtension[2], PawnEndgameExtension[2];
|
||||||
|
|
||||||
|
@ -203,14 +203,14 @@ namespace {
|
||||||
|
|
||||||
// Futility lookup tables (initialized at startup) and their access functions
|
// Futility lookup tables (initialized at startup) and their access functions
|
||||||
Value FutilityMarginsMatrix[16][64]; // [depth][moveNumber]
|
Value FutilityMarginsMatrix[16][64]; // [depth][moveNumber]
|
||||||
int FutilityMoveCountArray[32]; // [depth]
|
int FutilityMoveCountArray[32]; // [depth]
|
||||||
|
|
||||||
inline Value futility_margin(Depth d, int mn) { return d < 7 * ONE_PLY ? FutilityMarginsMatrix[Max(d, 1)][Min(mn, 63)] : 2 * VALUE_INFINITE; }
|
inline Value futility_margin(Depth d, int mn) { return d < 7 * ONE_PLY ? FutilityMarginsMatrix[Max(d, 1)][Min(mn, 63)] : 2 * VALUE_INFINITE; }
|
||||||
inline int futility_move_count(Depth d) { return d < 16 * ONE_PLY ? FutilityMoveCountArray[d] : 512; }
|
inline int futility_move_count(Depth d) { return d < 16 * ONE_PLY ? FutilityMoveCountArray[d] : 512; }
|
||||||
|
|
||||||
// Step 14. Reduced search
|
// Step 14. Reduced search
|
||||||
|
|
||||||
// Reduction lookup tables (initialized at startup) and their getter functions
|
// Reduction lookup tables (initialized at startup) and their access function
|
||||||
int8_t ReductionMatrix[2][64][64]; // [pv][depth][moveNumber]
|
int8_t ReductionMatrix[2][64][64]; // [pv][depth][moveNumber]
|
||||||
|
|
||||||
template <NodeType PV>
|
template <NodeType PV>
|
||||||
|
@ -233,10 +233,9 @@ namespace {
|
||||||
int MultiPV, UCIMultiPV;
|
int MultiPV, UCIMultiPV;
|
||||||
|
|
||||||
// Time management variables
|
// Time management variables
|
||||||
int MaxNodes, MaxDepth, ExactMaxTime;
|
bool StopOnPonderhit, FirstRootMove, StopRequest, QuitRequest, AspirationFailLow;
|
||||||
bool UseTimeManagement, InfiniteSearch, Pondering, StopOnPonderhit;
|
|
||||||
bool FirstRootMove, StopRequest, QuitRequest, AspirationFailLow;
|
|
||||||
TimeManager TimeMgr;
|
TimeManager TimeMgr;
|
||||||
|
SearchLimits Limits;
|
||||||
|
|
||||||
// Log file
|
// Log file
|
||||||
bool UseLogFile;
|
bool UseLogFile;
|
||||||
|
@ -304,7 +303,7 @@ namespace {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// MovePickerExt is an extended MovePicker used to choose at compile time
|
// MovePickerExt is an extended MovePicker class used to choose at compile time
|
||||||
// the proper move source according to the type of node.
|
// the proper move source according to the type of node.
|
||||||
template<bool SpNode, bool Root> struct MovePickerExt;
|
template<bool SpNode, bool Root> struct MovePickerExt;
|
||||||
|
|
||||||
|
@ -439,25 +438,30 @@ int64_t perft(Position& pos, Depth depth) {
|
||||||
|
|
||||||
/// think() is the external interface to Stockfish's search, and is called when
|
/// think() is the external interface to Stockfish's search, and is called when
|
||||||
/// the program receives the UCI 'go' command. It initializes various global
|
/// the program receives the UCI 'go' command. It initializes various global
|
||||||
/// variables, and calls id_loop(). It returns false when a quit command is
|
/// variables, and calls id_loop(). It returns false when a "quit" command is
|
||||||
/// received during the search.
|
/// received during the search.
|
||||||
|
|
||||||
bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[],
|
bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
|
||||||
int movesToGo, int maxDepth, int maxNodes, int maxTime, Move searchMoves[]) {
|
|
||||||
|
|
||||||
// Initialize global search-related variables
|
// Initialize global search-related variables
|
||||||
StopOnPonderhit = StopRequest = QuitRequest = AspirationFailLow = SendSearchedNodes = false;
|
StopOnPonderhit = StopRequest = QuitRequest = AspirationFailLow = SendSearchedNodes = false;
|
||||||
NodesSincePoll = 0;
|
NodesSincePoll = 0;
|
||||||
current_search_time(get_system_time());
|
current_search_time(get_system_time());
|
||||||
ExactMaxTime = maxTime;
|
Limits = limits;
|
||||||
MaxDepth = maxDepth;
|
TimeMgr.init(Limits, pos.startpos_ply_counter());
|
||||||
MaxNodes = maxNodes;
|
|
||||||
InfiniteSearch = infinite;
|
// Set best NodesBetweenPolls interval to avoid lagging under time pressure
|
||||||
Pondering = ponder;
|
if (Limits.maxNodes)
|
||||||
UseTimeManagement = !ExactMaxTime && !MaxDepth && !MaxNodes && !InfiniteSearch;
|
NodesBetweenPolls = Min(Limits.maxNodes, 30000);
|
||||||
|
else if (Limits.time && Limits.time < 1000)
|
||||||
|
NodesBetweenPolls = 1000;
|
||||||
|
else if (Limits.time && Limits.time < 5000)
|
||||||
|
NodesBetweenPolls = 5000;
|
||||||
|
else
|
||||||
|
NodesBetweenPolls = 30000;
|
||||||
|
|
||||||
// Look for a book move, only during games, not tests
|
// Look for a book move, only during games, not tests
|
||||||
if (UseTimeManagement && Options["OwnBook"].value<bool>())
|
if (Limits.useTimeManagement() && Options["OwnBook"].value<bool>())
|
||||||
{
|
{
|
||||||
if (Options["Book File"].value<std::string>() != OpeningBook.name())
|
if (Options["Book File"].value<std::string>() != OpeningBook.name())
|
||||||
OpeningBook.open(Options["Book File"].value<std::string>());
|
OpeningBook.open(Options["Book File"].value<std::string>());
|
||||||
|
@ -465,7 +469,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
|
||||||
Move bookMove = OpeningBook.get_move(pos, Options["Best Book Move"].value<bool>());
|
Move bookMove = OpeningBook.get_move(pos, Options["Best Book Move"].value<bool>());
|
||||||
if (bookMove != MOVE_NONE)
|
if (bookMove != MOVE_NONE)
|
||||||
{
|
{
|
||||||
if (Pondering)
|
if (Limits.ponder)
|
||||||
wait_for_stop_or_ponderhit();
|
wait_for_stop_or_ponderhit();
|
||||||
|
|
||||||
cout << "bestmove " << bookMove << endl;
|
cout << "bestmove " << bookMove << endl;
|
||||||
|
@ -511,34 +515,18 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
|
||||||
ThreadsMgr[i].maxPly = 0;
|
ThreadsMgr[i].maxPly = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set thinking time
|
// Write to log file and keep it open to be accessed during the search
|
||||||
int myTime = time[pos.side_to_move()];
|
|
||||||
int myIncrement = increment[pos.side_to_move()];
|
|
||||||
if (UseTimeManagement)
|
|
||||||
TimeMgr.init(myTime, myIncrement, movesToGo, pos.startpos_ply_counter());
|
|
||||||
|
|
||||||
// Set best NodesBetweenPolls interval to avoid lagging under time pressure
|
|
||||||
if (MaxNodes)
|
|
||||||
NodesBetweenPolls = Min(MaxNodes, 30000);
|
|
||||||
else if (myTime && myTime < 1000)
|
|
||||||
NodesBetweenPolls = 1000;
|
|
||||||
else if (myTime && myTime < 5000)
|
|
||||||
NodesBetweenPolls = 5000;
|
|
||||||
else
|
|
||||||
NodesBetweenPolls = 30000;
|
|
||||||
|
|
||||||
// Write search information to log file
|
|
||||||
if (UseLogFile)
|
if (UseLogFile)
|
||||||
{
|
{
|
||||||
std::string name = Options["Search Log Filename"].value<std::string>();
|
std::string name = Options["Search Log Filename"].value<std::string>();
|
||||||
LogFile.open(name.c_str(), std::ios::out | std::ios::app);
|
LogFile.open(name.c_str(), std::ios::out | std::ios::app);
|
||||||
|
|
||||||
LogFile << "\nSearching: " << pos.to_fen()
|
LogFile << "\nSearching: " << pos.to_fen()
|
||||||
<< "\ninfinite: " << infinite
|
<< "\ninfinite: " << Limits.infinite
|
||||||
<< " ponder: " << ponder
|
<< " ponder: " << Limits.ponder
|
||||||
<< " time: " << myTime
|
<< " time: " << Limits.time
|
||||||
<< " increment: " << myIncrement
|
<< " increment: " << Limits.increment
|
||||||
<< " moves to go: " << movesToGo
|
<< " moves to go: " << Limits.movesToGo
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,15 +534,15 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
|
||||||
Move ponderMove = MOVE_NONE;
|
Move ponderMove = MOVE_NONE;
|
||||||
Move bestMove = id_loop(pos, searchMoves, &ponderMove);
|
Move bestMove = id_loop(pos, searchMoves, &ponderMove);
|
||||||
|
|
||||||
// Print final search statistics
|
|
||||||
cout << "info" << speed_to_uci(pos.nodes_searched()) << endl;
|
cout << "info" << speed_to_uci(pos.nodes_searched()) << endl;
|
||||||
|
|
||||||
|
// Write final search statistics and close log file
|
||||||
if (UseLogFile)
|
if (UseLogFile)
|
||||||
{
|
{
|
||||||
int t = current_search_time();
|
int t = current_search_time();
|
||||||
|
|
||||||
LogFile << "Nodes: " << pos.nodes_searched()
|
LogFile << "Nodes: " << pos.nodes_searched()
|
||||||
<< "\nNodes/second: " << (t > 0 ? int(pos.nodes_searched() * 1000 / t) : 0)
|
<< "\nNodes/second: " << (t > 0 ? pos.nodes_searched() * 1000 / t : 0)
|
||||||
<< "\nBest move: " << move_to_san(pos, bestMove);
|
<< "\nBest move: " << move_to_san(pos, bestMove);
|
||||||
|
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
|
@ -569,7 +557,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
|
||||||
|
|
||||||
// If we are pondering or in infinite search, we shouldn't print the
|
// If we are pondering or in infinite search, we shouldn't print the
|
||||||
// best move before we are told to do so.
|
// best move before we are told to do so.
|
||||||
if (!StopRequest && (Pondering || InfiniteSearch))
|
if (!StopRequest && (Limits.ponder || Limits.infinite))
|
||||||
wait_for_stop_or_ponderhit();
|
wait_for_stop_or_ponderhit();
|
||||||
|
|
||||||
// Could be MOVE_NONE when searching on a stalemate position
|
// Could be MOVE_NONE when searching on a stalemate position
|
||||||
|
@ -624,7 +612,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterative deepening loop
|
// Iterative deepening loop
|
||||||
while (++depth <= PLY_MAX && (!MaxDepth || depth <= MaxDepth) && !StopRequest)
|
while (++depth <= PLY_MAX && (!Limits.maxDepth || depth <= Limits.maxDepth) && !StopRequest)
|
||||||
{
|
{
|
||||||
Rml.bestMoveChanges = 0;
|
Rml.bestMoveChanges = 0;
|
||||||
cout << set960(pos.is_chess960()) << "info depth " << depth << endl;
|
cout << set960(pos.is_chess960()) << "info depth " << depth << endl;
|
||||||
|
@ -708,7 +696,7 @@ namespace {
|
||||||
else if (bestMove != easyMove)
|
else if (bestMove != easyMove)
|
||||||
easyMove = MOVE_NONE;
|
easyMove = MOVE_NONE;
|
||||||
|
|
||||||
if (UseTimeManagement && !StopRequest)
|
if (Limits.useTimeManagement() && !StopRequest)
|
||||||
{
|
{
|
||||||
// Time to stop?
|
// Time to stop?
|
||||||
bool noMoreTime = false;
|
bool noMoreTime = false;
|
||||||
|
@ -743,7 +731,7 @@ namespace {
|
||||||
|
|
||||||
if (noMoreTime)
|
if (noMoreTime)
|
||||||
{
|
{
|
||||||
if (Pondering)
|
if (Limits.ponder)
|
||||||
StopOnPonderhit = true;
|
StopOnPonderhit = true;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
@ -1907,7 +1895,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
if (!std::getline(std::cin, command) || command == "quit")
|
if (!std::getline(std::cin, command) || command == "quit")
|
||||||
{
|
{
|
||||||
// Quit the program as soon as possible
|
// Quit the program as soon as possible
|
||||||
Pondering = false;
|
Limits.ponder = false;
|
||||||
QuitRequest = StopRequest = true;
|
QuitRequest = StopRequest = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1915,7 +1903,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
{
|
{
|
||||||
// Stop calculating as soon as possible, but still send the "bestmove"
|
// Stop calculating as soon as possible, but still send the "bestmove"
|
||||||
// and possibly the "ponder" token when finishing the search.
|
// and possibly the "ponder" token when finishing the search.
|
||||||
Pondering = false;
|
Limits.ponder = false;
|
||||||
StopRequest = true;
|
StopRequest = true;
|
||||||
}
|
}
|
||||||
else if (command == "ponderhit")
|
else if (command == "ponderhit")
|
||||||
|
@ -1923,7 +1911,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
// The opponent has played the expected move. GUI sends "ponderhit" if
|
// The opponent has played the expected move. GUI sends "ponderhit" if
|
||||||
// we were told to ponder on the same move the opponent has played. We
|
// we were told to ponder on the same move the opponent has played. We
|
||||||
// should continue searching but switching from pondering to normal search.
|
// should continue searching but switching from pondering to normal search.
|
||||||
Pondering = false;
|
Limits.ponder = false;
|
||||||
|
|
||||||
if (StopOnPonderhit)
|
if (StopOnPonderhit)
|
||||||
StopRequest = true;
|
StopRequest = true;
|
||||||
|
@ -1951,7 +1939,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should we stop the search?
|
// Should we stop the search?
|
||||||
if (Pondering)
|
if (Limits.ponder)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool stillAtFirstMove = FirstRootMove
|
bool stillAtFirstMove = FirstRootMove
|
||||||
|
@ -1961,9 +1949,9 @@ split_point_start: // At split points actual search starts from here
|
||||||
bool noMoreTime = t > TimeMgr.maximum_time()
|
bool noMoreTime = t > TimeMgr.maximum_time()
|
||||||
|| stillAtFirstMove;
|
|| stillAtFirstMove;
|
||||||
|
|
||||||
if ( (UseTimeManagement && noMoreTime)
|
if ( (Limits.useTimeManagement() && noMoreTime)
|
||||||
|| (ExactMaxTime && t >= ExactMaxTime)
|
|| (Limits.maxTime && t >= Limits.maxTime)
|
||||||
|| (MaxNodes && pos.nodes_searched() >= MaxNodes)) // FIXME
|
|| (Limits.maxNodes && pos.nodes_searched() >= Limits.maxNodes)) // FIXME
|
||||||
StopRequest = true;
|
StopRequest = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
25
src/search.h
25
src/search.h
|
@ -23,13 +23,13 @@
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
class Position;
|
||||||
|
struct SplitPoint;
|
||||||
|
|
||||||
/// The SearchStack struct keeps track of the information we need to remember
|
/// The SearchStack struct keeps track of the information we need to remember
|
||||||
/// from nodes shallower and deeper in the tree during the search. Each
|
/// from nodes shallower and deeper in the tree during the search. Each
|
||||||
/// search thread has its own array of SearchStack objects, indexed by the
|
/// search thread has its own array of SearchStack objects, indexed by the
|
||||||
/// current ply.
|
/// current ply.
|
||||||
struct EvalInfo;
|
|
||||||
struct SplitPoint;
|
|
||||||
|
|
||||||
struct SearchStack {
|
struct SearchStack {
|
||||||
int ply;
|
int ply;
|
||||||
|
@ -45,12 +45,27 @@ struct SearchStack {
|
||||||
SplitPoint* sp;
|
SplitPoint* sp;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Position;
|
|
||||||
|
/// The SearchLimits struct stores information sent by GUI about available time
|
||||||
|
/// to search the current move, maximum depth/time, if we are in analysis mode
|
||||||
|
/// or if we have to ponder while is our opponent's side to move.
|
||||||
|
|
||||||
|
struct SearchLimits {
|
||||||
|
|
||||||
|
SearchLimits() {}
|
||||||
|
SearchLimits(int t, int i, int mtg, int mt, int md, int mn, bool inf, bool pon)
|
||||||
|
: time(t), increment(i), movesToGo(mtg), maxTime(mt), maxDepth(md),
|
||||||
|
maxNodes(mn), infinite(inf), ponder(pon) {}
|
||||||
|
|
||||||
|
bool useTimeManagement() const { return !(maxTime | maxDepth | maxNodes | int(infinite)); }
|
||||||
|
|
||||||
|
int time, increment, movesToGo, maxTime, maxDepth, maxNodes;
|
||||||
|
bool infinite, ponder;
|
||||||
|
};
|
||||||
|
|
||||||
extern void init_threads();
|
extern void init_threads();
|
||||||
extern void exit_threads();
|
extern void exit_threads();
|
||||||
extern int64_t perft(Position& pos, Depth depth);
|
extern int64_t perft(Position& pos, Depth depth);
|
||||||
extern bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[],
|
extern bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]);
|
||||||
int movesToGo, int maxDepth, int maxNodes, int maxTime, Move searchMoves[]);
|
|
||||||
|
|
||||||
#endif // !defined(SEARCH_H_INCLUDED)
|
#endif // !defined(SEARCH_H_INCLUDED)
|
||||||
|
|
|
@ -17,21 +17,13 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
////
|
|
||||||
//// Includes
|
|
||||||
////
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
#include "search.h"
|
||||||
#include "timeman.h"
|
#include "timeman.h"
|
||||||
#include "ucioption.h"
|
#include "ucioption.h"
|
||||||
|
|
||||||
////
|
|
||||||
//// Local definitions
|
|
||||||
////
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// Constants
|
/// Constants
|
||||||
|
@ -84,31 +76,28 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////
|
|
||||||
//// Functions
|
|
||||||
////
|
|
||||||
|
|
||||||
void TimeManager::pv_instability(int curChanges, int prevChanges) {
|
void TimeManager::pv_instability(int curChanges, int prevChanges) {
|
||||||
|
|
||||||
unstablePVExtraTime = curChanges * (optimumSearchTime / 2)
|
unstablePVExtraTime = curChanges * (optimumSearchTime / 2)
|
||||||
+ prevChanges * (optimumSearchTime / 3);
|
+ prevChanges * (optimumSearchTime / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeManager::init(int myTime, int myInc, int movesToGo, int currentPly)
|
|
||||||
|
void TimeManager::init(const SearchLimits& limits, int currentPly)
|
||||||
{
|
{
|
||||||
/* We support four different kind of time controls:
|
/* We support four different kind of time controls:
|
||||||
|
|
||||||
Inc == 0 && movesToGo == 0 means: x basetime [sudden death!]
|
increment == 0 && movesToGo == 0 means: x basetime [sudden death!]
|
||||||
Inc == 0 && movesToGo != 0 means: (x moves) / (y minutes)
|
increment == 0 && movesToGo != 0 means: x moves in y minutes
|
||||||
Inc > 0 && movesToGo == 0 means: x basetime + z inc.
|
increment > 0 && movesToGo == 0 means: x basetime + z increment
|
||||||
Inc > 0 && movesToGo != 0 means: (x moves) / (y minutes) + z inc
|
increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment
|
||||||
|
|
||||||
Time management is adjusted by following UCI parameters:
|
Time management is adjusted by following UCI parameters:
|
||||||
|
|
||||||
emergencyMoveHorizon :Be prepared to always play at least this many moves
|
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
|
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
|
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
|
minThinkingTime : No matter what, use at least this much thinking before doing the move
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int hypMTG, hypMyTime, t1, t2;
|
int hypMTG, hypMyTime, t1, t2;
|
||||||
|
@ -121,14 +110,19 @@ void TimeManager::init(int myTime, int myInc, int movesToGo, int currentPly)
|
||||||
|
|
||||||
// Initialize to maximum values but unstablePVExtraTime that is reset
|
// Initialize to maximum values but unstablePVExtraTime that is reset
|
||||||
unstablePVExtraTime = 0;
|
unstablePVExtraTime = 0;
|
||||||
optimumSearchTime = maximumSearchTime = myTime;
|
optimumSearchTime = maximumSearchTime = limits.time;
|
||||||
|
|
||||||
// We calculate optimum time usage for different hypothetic "moves to go"-values and choose the
|
// 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.
|
// minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values.
|
||||||
for (hypMTG = 1; hypMTG <= (movesToGo ? Min(movesToGo, MoveHorizon) : MoveHorizon); hypMTG++)
|
for (hypMTG = 1; hypMTG <= (limits.movesToGo ? Min(limits.movesToGo, MoveHorizon) : MoveHorizon); hypMTG++)
|
||||||
{
|
{
|
||||||
// Calculate thinking time for hypothetic "moves to go"-value
|
// 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 * Min(hypMTG, emergencyMoveHorizon);
|
||||||
|
|
||||||
|
hypMyTime = Max(hypMyTime, 0);
|
||||||
|
|
||||||
t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly);
|
t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly);
|
||||||
t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly);
|
t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly);
|
||||||
|
@ -144,9 +138,6 @@ void TimeManager::init(int myTime, int myInc, int movesToGo, int currentPly)
|
||||||
optimumSearchTime = Min(optimumSearchTime, maximumSearchTime);
|
optimumSearchTime = Min(optimumSearchTime, maximumSearchTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
|
||||||
//// Local functions
|
|
||||||
////
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,12 @@
|
||||||
#if !defined(TIMEMAN_H_INCLUDED)
|
#if !defined(TIMEMAN_H_INCLUDED)
|
||||||
#define TIMEMAN_H_INCLUDED
|
#define TIMEMAN_H_INCLUDED
|
||||||
|
|
||||||
|
struct SearchLimits;
|
||||||
|
|
||||||
class TimeManager {
|
class TimeManager {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void init(int myTime, int myInc, int movesToGo, int currentPly);
|
void init(const SearchLimits& limits, int currentPly);
|
||||||
void pv_instability(int curChanges, int prevChanges);
|
void pv_instability(int curChanges, int prevChanges);
|
||||||
int available_time() const { return optimumSearchTime + unstablePVExtraTime; }
|
int available_time() const { return optimumSearchTime + unstablePVExtraTime; }
|
||||||
int maximum_time() const { return maximumSearchTime; }
|
int maximum_time() const { return maximumSearchTime; }
|
||||||
|
|
42
src/uci.cpp
42
src/uci.cpp
|
@ -203,50 +203,48 @@ namespace {
|
||||||
bool go(Position& pos, UCIParser& up) {
|
bool go(Position& pos, UCIParser& up) {
|
||||||
|
|
||||||
string token;
|
string token;
|
||||||
Move searchMoves[MOVES_MAX];
|
int time[] = { 0, 0 }, inc[] = { 0, 0 };
|
||||||
int movesToGo, depth, nodes, moveTime, numOfMoves;
|
SearchLimits limits(0, 0, 0, 0, 0, 0, false, false);
|
||||||
bool infinite, ponder;
|
Move searchMoves[MOVES_MAX] = { MOVE_NONE };
|
||||||
int time[2] = {0, 0}, inc[2] = {0, 0};
|
Move* cur = searchMoves;
|
||||||
|
|
||||||
searchMoves[0] = MOVE_NONE;
|
|
||||||
infinite = ponder = false;
|
|
||||||
movesToGo = depth = nodes = moveTime = numOfMoves = 0;
|
|
||||||
|
|
||||||
while (up >> token)
|
while (up >> token)
|
||||||
{
|
{
|
||||||
if (token == "infinite")
|
if (token == "infinite")
|
||||||
infinite = true;
|
limits.infinite = true;
|
||||||
else if (token == "ponder")
|
else if (token == "ponder")
|
||||||
ponder = true;
|
limits.ponder = true;
|
||||||
else if (token == "wtime")
|
else if (token == "wtime")
|
||||||
up >> time[0];
|
up >> time[WHITE];
|
||||||
else if (token == "btime")
|
else if (token == "btime")
|
||||||
up >> time[1];
|
up >> time[BLACK];
|
||||||
else if (token == "winc")
|
else if (token == "winc")
|
||||||
up >> inc[0];
|
up >> inc[WHITE];
|
||||||
else if (token == "binc")
|
else if (token == "binc")
|
||||||
up >> inc[1];
|
up >> inc[BLACK];
|
||||||
else if (token == "movestogo")
|
else if (token == "movestogo")
|
||||||
up >> movesToGo;
|
up >> limits.movesToGo;
|
||||||
else if (token == "depth")
|
else if (token == "depth")
|
||||||
up >> depth;
|
up >> limits.maxDepth;
|
||||||
else if (token == "nodes")
|
else if (token == "nodes")
|
||||||
up >> nodes;
|
up >> limits.maxNodes;
|
||||||
else if (token == "movetime")
|
else if (token == "movetime")
|
||||||
up >> moveTime;
|
up >> limits.maxTime;
|
||||||
else if (token == "searchmoves")
|
else if (token == "searchmoves")
|
||||||
{
|
{
|
||||||
while (up >> token)
|
while (up >> token)
|
||||||
searchMoves[numOfMoves++] = move_from_uci(pos, token);
|
*cur++ = move_from_uci(pos, token);
|
||||||
|
|
||||||
searchMoves[numOfMoves] = MOVE_NONE;
|
*cur = MOVE_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pos.is_ok());
|
assert(pos.is_ok());
|
||||||
|
|
||||||
return think(pos, infinite, ponder, time, inc, movesToGo,
|
limits.time = time[pos.side_to_move()];
|
||||||
depth, nodes, moveTime, searchMoves);
|
limits.increment = inc[pos.side_to_move()];
|
||||||
|
|
||||||
|
return think(pos, limits, searchMoves);
|
||||||
}
|
}
|
||||||
|
|
||||||
void perft(Position& pos, UCIParser& up) {
|
void perft(Position& pos, UCIParser& up) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue