pgeorges wrote: I think some UCI engine does not handle correctly UCI protocol in some special circumstances, among them Stockfish (and of course some Glaurung versions, I did not check all).
Hi Pascal,
you are correct. It is a bug.
According to UCI specification
http://wbec-ridderkerk.nl/html/UCIProtocol.html after a 'go infinite' command engine should
"search until the "stop" command. Do not exit the search without being told so in this mode!"
Here is the patch against 1.6.2 that fixes the bug. You can use tool 'patch'
http://gnuwin32.sourceforge.net/packages/patch.htm to apply even under Windows.
Code: Select all
Date: Sun, 10 Jan 2010 12:38:59 +0100
Subject: [PATCH] Fix sending of best move during an infinite search
According to UCI standard once engine receives 'go infinite'
command it should search until the "stop" command and do not exit
the search without being told so, even if PLY_MAX has been reached.
Patch is quite invasive because it cleanups some hacks used
by fixed depth and fixed nodes modes, mainly during benchmarks.
Bug found by Pascal Georges.
---
src/benchmark.cpp | 2 +-
src/search.cpp | 105 ++++++++++++++++++++++++++---------------------------
2 files changed, 53 insertions(+), 54 deletions(-)
diff --git a/src/benchmark.cpp b/src/benchmark.cpp
index d797264..3abcda6 100644
--- a/src/benchmark.cpp
+++ b/src/benchmark.cpp
@@ -155,7 +155,7 @@ void benchmark(const string& commandLine) {
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (limitType == "perft")
totalNodes += perft(pos, maxDepth * OnePly);
- else if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
+ else if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
diff --git a/src/search.cpp b/src/search.cpp
index b56cf9a..faac667 100644
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -227,6 +227,7 @@ namespace {
int MaxNodes, MaxDepth;
int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
int RootMoveNumber;
+ bool UseTimeManagement;
bool InfiniteSearch;
bool PonderSearch;
bool StopOnPonderhit;
@@ -368,21 +369,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]) {
- // Look for a book move
- if (!infinite && !ponder && get_option_value_bool("OwnBook"))
- {
- Move bookMove;
- if (get_option_value_string("Book File") != OpeningBook.file_name())
- OpeningBook.open(get_option_value_string("Book File"));
-
- bookMove = OpeningBook.get_move(pos);
- if (bookMove != MOVE_NONE)
- {
- std::cout << "bestmove " << bookMove << std::endl;
- return true;
- }
- }
-
// Initialize global search variables
Idle = false;
SearchStartTime = get_system_time();
@@ -401,6 +387,24 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
FailLow = false;
Problem = false;
ExactMaxTime = maxTime;
+ MaxDepth = maxDepth;
+ MaxNodes = maxNodes;
+ UseTimeManagement = !ExactMaxTime && !MaxDepth && !MaxNodes && !InfiniteSearch;
+
+ // Look for a book move, only during games, not tests
+ if (UseTimeManagement && !ponder && get_option_value_bool("OwnBook"))
+ {
+ Move bookMove;
+ if (get_option_value_string("Book File") != OpeningBook.file_name())
+ OpeningBook.open(get_option_value_string("Book File"));
+
+ bookMove = OpeningBook.get_move(pos);
+ if (bookMove != MOVE_NONE)
+ {
+ std::cout << "bestmove " << bookMove << std::endl;
+ return true;
+ }
+ }
if (button_was_pressed("New Game"))
loseOnTime = false; // reset at the beginning of a new game
@@ -463,48 +467,42 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
// Set thinking time
int myTime = time[side_to_move];
int myIncrement = increment[side_to_move];
-
- if (!movesToGo) // Sudden death time control
+ if (UseTimeManagement)
{
- if (myIncrement)
+ if (!movesToGo) // Sudden death time control
{
- MaxSearchTime = myTime / 30 + myIncrement;
- AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
- } else { // Blitz game without increment
- MaxSearchTime = myTime / 30;
- AbsoluteMaxSearchTime = myTime / 8;
+ if (myIncrement)
+ {
+ MaxSearchTime = myTime / 30 + myIncrement;
+ AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
+ } else { // Blitz game without increment
+ MaxSearchTime = myTime / 30;
+ AbsoluteMaxSearchTime = myTime / 8;
+ }
}
- }
- else // (x moves) / (y minutes)
- {
- if (movesToGo == 1)
+ else // (x moves) / (y minutes)
{
- MaxSearchTime = myTime / 2;
- AbsoluteMaxSearchTime =
- (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
- } else {
- MaxSearchTime = myTime / Min(movesToGo, 20);
- AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
+ if (movesToGo == 1)
+ {
+ MaxSearchTime = myTime / 2;
+ AbsoluteMaxSearchTime =
+ (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
+ } else {
+ MaxSearchTime = myTime / Min(movesToGo, 20);
+ AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
+ }
}
- }
- if (PonderingEnabled)
- {
- MaxSearchTime += MaxSearchTime / 4;
- MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
+ if (PonderingEnabled)
+ {
+ MaxSearchTime += MaxSearchTime / 4;
+ MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
+ }
}
- // Fixed depth or fixed number of nodes?
- MaxDepth = maxDepth;
- if (MaxDepth)
- InfiniteSearch = true; // HACK
-
- MaxNodes = maxNodes;
+ // Set best NodesBetweenPolls interval
if (MaxNodes)
- {
NodesBetweenPolls = Min(MaxNodes, 30000);
- InfiniteSearch = true; // HACK
- }
else if (myTime && myTime < 1000)
NodesBetweenPolls = 1000;
else if (myTime && myTime < 5000)
@@ -782,7 +780,7 @@ namespace {
Problem = false;
- if (!InfiniteSearch)
+ if (UseTimeManagement)
{
// Time to stop?
bool stopSearch = false;
@@ -835,9 +833,9 @@ namespace {
rml.sort();
- // If we are pondering, we shouldn't print the best move before we
- // are told to do so
- if (PonderSearch)
+ // If we are pondering or in infinite search, we shouldn't print the
+ // best move before we are told to do so.
+ if (PonderSearch || InfiniteSearch)
wait_for_stop_or_ponderhit();
else
// Print final search statistics
@@ -2651,7 +2649,7 @@ namespace {
|| ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem
&& t > 6*(MaxSearchTime + ExtraSearchTime));
- if ( (Iteration >= 3 && (!InfiniteSearch && overTime))
+ if ( (Iteration >= 3 && (UseTimeManagement && overTime))
|| (ExactMaxTime && t >= ExactMaxTime)
|| (Iteration >= 3 && MaxNodes && nodes_searched() >= MaxNodes))
AbortSearch = true;
@@ -2666,8 +2664,9 @@ namespace {
int t = current_search_time();
PonderSearch = false;
+
if (Iteration >= 3 &&
- (!InfiniteSearch && (StopOnPonderhit ||
+ (UseTimeManagement && (StopOnPonderhit ||
t > AbsoluteMaxSearchTime ||
(RootMoveNumber == 1 &&
t > MaxSearchTime + ExtraSearchTime && !FailLow) ||
--
1.6.4.msysgit.0
I am quite satisfied we are fixing many very old bugs after the releasing of 1.6.2, it means many people is testing / using it.
Thanks again
Marco