1
0
Fork 0

Partially space inflate search.cpp

Space inflate main remaining functions in search.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
sf_2.3.1_base
Marco Costalba 2008-10-30 11:35:44 +01:00
parent cf2bafb661
commit e5ebd4f5d1
1 changed files with 334 additions and 312 deletions

View File

@ -310,29 +310,33 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth, int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]) { int maxNodes, int maxTime, Move searchMoves[]) {
// Look for a book move: // Look for a book move
if(!infinite && !ponder && get_option_value_bool("OwnBook")) { if (!infinite && !ponder && get_option_value_bool("OwnBook"))
Move bookMove; {
if(get_option_value_string("Book File") != OpeningBook.file_name()) { Move bookMove;
OpeningBook.close(); if (get_option_value_string("Book File") != OpeningBook.file_name())
OpeningBook.open("book.bin"); {
} OpeningBook.close();
bookMove = OpeningBook.get_move(pos); OpeningBook.open("book.bin");
if(bookMove != MOVE_NONE) { }
std::cout << "bestmove " << bookMove << std::endl; bookMove = OpeningBook.get_move(pos);
return; if (bookMove != MOVE_NONE)
} {
std::cout << "bestmove " << bookMove << std::endl;
return;
}
} }
// Initialize global search variables: // Initialize global search variables
Idle = false; Idle = false;
SearchStartTime = get_system_time(); SearchStartTime = get_system_time();
BestRootMove = MOVE_NONE; BestRootMove = MOVE_NONE;
PonderMove = MOVE_NONE; PonderMove = MOVE_NONE;
EasyMove = MOVE_NONE; EasyMove = MOVE_NONE;
for(int i = 0; i < THREAD_MAX; i++) { for (int i = 0; i < THREAD_MAX; i++)
Threads[i].nodes = 0ULL; {
Threads[i].failHighPly1 = false; Threads[i].nodes = 0ULL;
Threads[i].failHighPly1 = false;
} }
NodesSincePoll = 0; NodesSincePoll = 0;
InfiniteSearch = infinite; InfiniteSearch = infinite;
@ -344,59 +348,49 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
Problem = false; Problem = false;
ExactMaxTime = maxTime; ExactMaxTime = maxTime;
// Read UCI option values: // Read UCI option values
TT.set_size(get_option_value_int("Hash")); TT.set_size(get_option_value_int("Hash"));
if(button_was_pressed("Clear Hash")) if (button_was_pressed("Clear Hash"))
TT.clear(); TT.clear();
PonderingEnabled = get_option_value_bool("Ponder"); PonderingEnabled = get_option_value_bool("Ponder");
MultiPV = get_option_value_int("MultiPV"); MultiPV = get_option_value_int("MultiPV");
CheckExtension[1] = Depth(get_option_value_int("Check Extension (PV nodes)")); CheckExtension[1] = Depth(get_option_value_int("Check Extension (PV nodes)"));
CheckExtension[0] = CheckExtension[0] = Depth(get_option_value_int("Check Extension (non-PV nodes)"));
Depth(get_option_value_int("Check Extension (non-PV nodes)"));
SingleReplyExtension[1] = Depth(get_option_value_int("Single Reply Extension (PV nodes)"));
SingleReplyExtension[0] =
Depth(get_option_value_int("Single Reply Extension (non-PV nodes)"));
PawnPushTo7thExtension[1] =
Depth(get_option_value_int("Pawn Push to 7th Extension (PV nodes)"));
PawnPushTo7thExtension[0] =
Depth(get_option_value_int("Pawn Push to 7th Extension (non-PV nodes)"));
PassedPawnExtension[1] =
Depth(get_option_value_int("Passed Pawn Extension (PV nodes)"));
PassedPawnExtension[0] =
Depth(get_option_value_int("Passed Pawn Extension (non-PV nodes)"));
PawnEndgameExtension[1] =
Depth(get_option_value_int("Pawn Endgame Extension (PV nodes)"));
PawnEndgameExtension[0] =
Depth(get_option_value_int("Pawn Endgame Extension (non-PV nodes)"));
MateThreatExtension[1] =
Depth(get_option_value_int("Mate Threat Extension (PV nodes)"));
MateThreatExtension[0] =
Depth(get_option_value_int("Mate Threat Extension (non-PV nodes)"));
LMRPVMoves = get_option_value_int("Full Depth Moves (PV nodes)") + 1; SingleReplyExtension[1] = Depth(get_option_value_int("Single Reply Extension (PV nodes)"));
LMRNonPVMoves = get_option_value_int("Full Depth Moves (non-PV nodes)") + 1; SingleReplyExtension[0] = Depth(get_option_value_int("Single Reply Extension (non-PV nodes)"));
ThreatDepth = get_option_value_int("Threat Depth") * OnePly;
PawnPushTo7thExtension[1] = Depth(get_option_value_int("Pawn Push to 7th Extension (PV nodes)"));
PawnPushTo7thExtension[0] = Depth(get_option_value_int("Pawn Push to 7th Extension (non-PV nodes)"));
PassedPawnExtension[1] = Depth(get_option_value_int("Passed Pawn Extension (PV nodes)"));
PassedPawnExtension[0] = Depth(get_option_value_int("Passed Pawn Extension (non-PV nodes)"));
PawnEndgameExtension[1] = Depth(get_option_value_int("Pawn Endgame Extension (PV nodes)"));
PawnEndgameExtension[0] = Depth(get_option_value_int("Pawn Endgame Extension (non-PV nodes)"));
MateThreatExtension[1] = Depth(get_option_value_int("Mate Threat Extension (PV nodes)"));
MateThreatExtension[0] = Depth(get_option_value_int("Mate Threat Extension (non-PV nodes)"));
LMRPVMoves = get_option_value_int("Full Depth Moves (PV nodes)") + 1;
LMRNonPVMoves = get_option_value_int("Full Depth Moves (non-PV nodes)") + 1;
ThreatDepth = get_option_value_int("Threat Depth") * OnePly;
SelectiveDepth = get_option_value_int("Selective Plies") * OnePly; SelectiveDepth = get_option_value_int("Selective Plies") * OnePly;
Chess960 = get_option_value_bool("UCI_Chess960"); Chess960 = get_option_value_bool("UCI_Chess960");
ShowCurrentLine = get_option_value_bool("UCI_ShowCurrLine"); ShowCurrentLine = get_option_value_bool("UCI_ShowCurrLine");
UseLogFile = get_option_value_bool("Use Search Log"); UseLogFile = get_option_value_bool("Use Search Log");
if(UseLogFile) if (UseLogFile)
LogFile.open(get_option_value_string("Search Log Filename").c_str(), LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
std::ios::out | std::ios::app);
UseQSearchFutilityPruning = UseQSearchFutilityPruning = get_option_value_bool("Futility Pruning (Quiescence Search)");
get_option_value_bool("Futility Pruning (Quiescence Search)"); UseFutilityPruning = get_option_value_bool("Futility Pruning (Main Search)");
UseFutilityPruning =
get_option_value_bool("Futility Pruning (Main Search)");
FutilityMargin0 = FutilityMargin0 = value_from_centipawns(get_option_value_int("Futility Margin 0"));
value_from_centipawns(get_option_value_int("Futility Margin 0")); FutilityMargin1 = value_from_centipawns(get_option_value_int("Futility Margin 1"));
FutilityMargin1 = FutilityMargin2 = value_from_centipawns(get_option_value_int("Futility Margin 2"));
value_from_centipawns(get_option_value_int("Futility Margin 1"));
FutilityMargin2 =
value_from_centipawns(get_option_value_int("Futility Margin 2"));
RazorDepth = (get_option_value_int("Maximum Razoring Depth") + 1) * OnePly; RazorDepth = (get_option_value_int("Maximum Razoring Depth") + 1) * OnePly;
RazorMargin = value_from_centipawns(get_option_value_int("Razoring Margin")); RazorMargin = value_from_centipawns(get_option_value_int("Razoring Margin"));
@ -406,22 +400,22 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
LSNValue = value_from_centipawns(get_option_value_int("LSN Value Margin")); LSNValue = value_from_centipawns(get_option_value_int("LSN Value Margin"));
MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly; MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly;
MaxThreadsPerSplitPoint = MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
get_option_value_int("Maximum Number of Threads per Split Point");
read_weights(pos.side_to_move()); read_weights(pos.side_to_move());
int newActiveThreads = get_option_value_int("Threads"); int newActiveThreads = get_option_value_int("Threads");
if(newActiveThreads != ActiveThreads) { if (newActiveThreads != ActiveThreads)
ActiveThreads = newActiveThreads; {
init_eval(ActiveThreads); ActiveThreads = newActiveThreads;
init_eval(ActiveThreads);
} }
// Wake up sleeping threads: // Wake up sleeping threads:
wake_sleeping_threads(); wake_sleeping_threads();
for(int i = 1; i < ActiveThreads; i++) for (int i = 1; i < ActiveThreads; i++)
assert(thread_is_available(i, 0)); assert(thread_is_available(i, 0));
// Set thinking time: // Set thinking time:
int myTime = time[side_to_move]; int myTime = time[side_to_move];
@ -430,52 +424,59 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
TimeAdvantage = myTime - oppTime; TimeAdvantage = myTime - oppTime;
if(!movesToGo) { // Sudden death time control if (!movesToGo) // Sudden death time control
if(increment) { {
MaxSearchTime = myTime / 30 + myIncrement; if (increment)
AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100); {
} MaxSearchTime = myTime / 30 + myIncrement;
else { // Blitz game without increment AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
MaxSearchTime = myTime / 40; } else { // Blitz game without increment
AbsoluteMaxSearchTime = myTime / 8; MaxSearchTime = myTime / 40;
} AbsoluteMaxSearchTime = myTime / 8;
}
} }
else { // (x moves) / (y minutes) else // (x moves) / (y minutes)
if(movesToGo == 1) { {
MaxSearchTime = myTime / 2; if (movesToGo == 1)
AbsoluteMaxSearchTime = Min(myTime / 2, myTime - 500); {
} MaxSearchTime = myTime / 2;
else { AbsoluteMaxSearchTime = Min(myTime / 2, myTime - 500);
MaxSearchTime = myTime / Min(movesToGo, 20); } else {
AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3); MaxSearchTime = myTime / Min(movesToGo, 20);
} AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
}
} }
if(PonderingEnabled) {
MaxSearchTime += MaxSearchTime / 4; if (PonderingEnabled)
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime); {
MaxSearchTime += MaxSearchTime / 4;
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
} }
// Fixed depth or fixed number of nodes? // Fixed depth or fixed number of nodes?
MaxDepth = maxDepth; MaxDepth = maxDepth;
if(MaxDepth) if (MaxDepth)
InfiniteSearch = true; // HACK InfiniteSearch = true; // HACK
MaxNodes = maxNodes; MaxNodes = maxNodes;
if(MaxNodes) { if (MaxNodes)
NodesBetweenPolls = Min(MaxNodes, 30000); {
InfiniteSearch = true; // HACK NodesBetweenPolls = Min(MaxNodes, 30000);
InfiniteSearch = true; // HACK
} }
else else
NodesBetweenPolls = 30000; NodesBetweenPolls = 30000;
// Write information to search log file: // Write information to search log file:
if(UseLogFile) { if (UseLogFile)
LogFile << "Searching: " << pos.to_fen() << '\n'; LogFile << "Searching: " << pos.to_fen() << std::endl
LogFile << "infinite: " << infinite << " ponder: " << ponder << "infinite: " << infinite
<< " time: " << myTime << " increment: " << myIncrement << " ponder: " << ponder
<< " moves to go: " << movesToGo << '\n'; << " time: " << myTime
} << " increment: " << myIncrement
<< " moves to go: " << movesToGo << std::endl;
// We're ready to start thinking. Call the iterative deepening loop // We're ready to start thinking. Call the iterative deepening loop
// function: // function:
@ -495,16 +496,16 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
id_loop(pos, searchMoves); // to fail gracefully id_loop(pos, searchMoves); // to fail gracefully
} }
if(UseLogFile) if (UseLogFile)
LogFile.close(); LogFile.close();
if(Quit) { if (Quit)
OpeningBook.close(); {
stop_threads(); OpeningBook.close();
quit_eval(); stop_threads();
exit(0); quit_eval();
exit(0);
} }
Idle = true; Idle = true;
} }
@ -514,13 +515,15 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
/// objects. /// objects.
void init_threads() { void init_threads() {
volatile int i; volatile int i;
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
pthread_t pthread[1]; pthread_t pthread[1];
#endif #endif
for(i = 0; i < THREAD_MAX; i++) for (i = 0; i < THREAD_MAX; i++)
Threads[i].activeSplitPoints = 0; Threads[i].activeSplitPoints = 0;
// Initialize global locks: // Initialize global locks:
lock_init(&MPLock, NULL); lock_init(&MPLock, NULL);
@ -532,31 +535,31 @@ void init_threads() {
pthread_mutex_init(&WaitLock, NULL); pthread_mutex_init(&WaitLock, NULL);
pthread_cond_init(&WaitCond, NULL); pthread_cond_init(&WaitCond, NULL);
#else #else
for(i = 0; i < THREAD_MAX; i++) for (i = 0; i < THREAD_MAX; i++)
SitIdleEvent[i] = CreateEvent(0, FALSE, FALSE, 0); SitIdleEvent[i] = CreateEvent(0, FALSE, FALSE, 0);
#endif #endif
// All threads except the main thread should be initialized to idle state: // All threads except the main thread should be initialized to idle state
for(i = 1; i < THREAD_MAX; i++) { for (i = 1; i < THREAD_MAX; i++)
Threads[i].stop = false; {
Threads[i].workIsWaiting = false; Threads[i].stop = false;
Threads[i].idle = true; Threads[i].workIsWaiting = false;
Threads[i].running = false; Threads[i].idle = true;
Threads[i].running = false;
} }
// Launch the helper threads: // Launch the helper threads
for(i = 1; i < THREAD_MAX; i++) { for(i = 1; i < THREAD_MAX; i++)
{
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
pthread_create(pthread, NULL, init_thread, (void*)(&i)); pthread_create(pthread, NULL, init_thread, (void*)(&i));
#else #else
{
DWORD iID[1]; DWORD iID[1];
CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID); CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID);
}
#endif #endif
// Wait until the thread has finished launching: // Wait until the thread has finished launching:
while(!Threads[i].running); while (!Threads[i].running);
} }
} }
@ -565,13 +568,15 @@ void init_threads() {
/// helper threads exit cleanly. /// helper threads exit cleanly.
void stop_threads() { void stop_threads() {
ActiveThreads = THREAD_MAX; // HACK ActiveThreads = THREAD_MAX; // HACK
Idle = false; // HACK Idle = false; // HACK
wake_sleeping_threads(); wake_sleeping_threads();
AllThreadsShouldExit = true; AllThreadsShouldExit = true;
for(int i = 1; i < THREAD_MAX; i++) { for (int i = 1; i < THREAD_MAX; i++)
Threads[i].stop = true; {
while(Threads[i].running); Threads[i].stop = true;
while(Threads[i].running);
} }
destroy_split_point_stack(); destroy_split_point_stack();
} }
@ -581,9 +586,10 @@ void stop_threads() {
/// the current search. /// the current search.
int64_t nodes_searched() { int64_t nodes_searched() {
int64_t result = 0ULL; int64_t result = 0ULL;
for(int i = 0; i < ActiveThreads; i++) for (int i = 0; i < ActiveThreads; i++)
result += Threads[i].nodes; result += Threads[i].nodes;
return result; return result;
} }
@ -596,6 +602,7 @@ namespace {
// reached. // reached.
Value id_loop(const Position &pos, Move searchMoves[]) { Value id_loop(const Position &pos, Move searchMoves[]) {
Position p(pos); Position p(pos);
SearchStack ss[PLY_MAX_PLUS_2]; SearchStack ss[PLY_MAX_PLUS_2];
@ -614,110 +621,112 @@ namespace {
EasyMove = rml.scan_for_easy_move(); EasyMove = rml.scan_for_easy_move();
// Iterative deepening loop // Iterative deepening loop
while(!AbortSearch && Iteration < PLY_MAX) { while (!AbortSearch && Iteration < PLY_MAX)
{
// Initialize iteration
rml.sort();
Iteration++;
BestMoveChangesByIteration[Iteration] = 0;
if (Iteration <= 5)
ExtraSearchTime = 0;
// Initialize iteration std::cout << "info depth " << Iteration << std::endl;
rml.sort();
Iteration++;
BestMoveChangesByIteration[Iteration] = 0;
if(Iteration <= 5)
ExtraSearchTime = 0;
std::cout << "info depth " << Iteration << std::endl; // Search to the current depth
ValueByIteration[Iteration] = root_search(p, ss, rml);
// Search to the current depth // Erase the easy move if it differs from the new best move
ValueByIteration[Iteration] = root_search(p, ss, rml); if (ss[0].pv[0] != EasyMove)
EasyMove = MOVE_NONE;
// Erase the easy move if it differs from the new best move Problem = false;
if(ss[0].pv[0] != EasyMove)
EasyMove = MOVE_NONE;
Problem = false; if (!InfiniteSearch)
{
// Time to stop?
bool stopSearch = false;
if(!InfiniteSearch) { // Stop search early if there is only a single legal move:
// Time to stop? if (Iteration >= 6 && rml.move_count() == 1)
bool stopSearch = false; stopSearch = true;
// Stop search early if there is only a single legal move: // Stop search early when the last two iterations returned a mate score
if(Iteration >= 6 && rml.move_count() == 1) if ( Iteration >= 6
stopSearch = true; && abs(ValueByIteration[Iteration]) >= abs(VALUE_MATE) - 100
&& abs(ValueByIteration[Iteration-1]) >= abs(VALUE_MATE) - 100)
stopSearch = true;
// Stop search early when the last two iterations returned a mate // Stop search early if one move seems to be much better than the rest
// score: int64_t nodes = nodes_searched();
if(Iteration >= 6 if ( Iteration >= 8
&& abs(ValueByIteration[Iteration]) >= abs(VALUE_MATE) - 100 && EasyMove == ss[0].pv[0]
&& abs(ValueByIteration[Iteration-1]) >= abs(VALUE_MATE) - 100) && ( ( rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100
stopSearch = true; && current_search_time() > MaxSearchTime / 16)
||( rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100
&& current_search_time() > MaxSearchTime / 32)))
stopSearch = true;
// Stop search early if one move seems to be much better than the // Add some extra time if the best move has changed during the last two iterations
// rest: if (Iteration > 5 && Iteration <= 50)
int64_t nodes = nodes_searched(); ExtraSearchTime = BestMoveChangesByIteration[Iteration] * (MaxSearchTime / 2)
if(Iteration >= 8 && EasyMove == ss[0].pv[0] && + BestMoveChangesByIteration[Iteration-1] * (MaxSearchTime / 3);
((rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100 &&
current_search_time() > MaxSearchTime / 16) ||
(rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100 &&
current_search_time() > MaxSearchTime / 32)))
stopSearch = true;
// Add some extra time if the best move has changed during the last // If we need some more and we are in time advantage take it
// two iterations: if (ExtraSearchTime > 0 && TimeAdvantage > 2 * MaxSearchTime)
if(Iteration > 5 && Iteration <= 50) ExtraSearchTime += MaxSearchTime / 2;
ExtraSearchTime =
BestMoveChangesByIteration[Iteration] * (MaxSearchTime / 2) +
BestMoveChangesByIteration[Iteration-1] * (MaxSearchTime / 3);
// If we need some more and we are in time advantage take it. // Stop search if most of MaxSearchTime is consumed at the end of the
if (ExtraSearchTime > 0 && TimeAdvantage > 2 * MaxSearchTime) // iteration. We probably don't have enough time to search the first
ExtraSearchTime += MaxSearchTime / 2; // move at the next iteration anyway.
if (current_search_time() > ((MaxSearchTime + ExtraSearchTime)*90) / 128)
stopSearch = true;
// Stop search if most of MaxSearchTime is consumed at the end of the if (stopSearch)
// iteration. We probably don't have enough time to search the first {
// move at the next iteration anyway. if (!PonderSearch)
if(current_search_time() > ((MaxSearchTime + ExtraSearchTime)*90) / 128) break;
stopSearch = true; else
StopOnPonderhit = true;
if(stopSearch) { }
if(!PonderSearch)
break;
else
StopOnPonderhit = true;
} }
} // Write PV to transposition table, in case the relevant entries have
// been overwritten during the search:
TT.insert_pv(p, ss[0].pv);
// Write PV to transposition table, in case the relevant entries have if (MaxDepth && Iteration >= MaxDepth)
// been overwritten during the search: break;
TT.insert_pv(p, ss[0].pv);
if(MaxDepth && Iteration >= MaxDepth)
break;
} }
rml.sort(); rml.sort();
// If we are pondering, we shouldn't print the best move before we // If we are pondering, we shouldn't print the best move before we
// are told to do so // are told to do so
if(PonderSearch) if (PonderSearch)
wait_for_stop_or_ponderhit(); wait_for_stop_or_ponderhit();
else else
// Print final search statistics // Print final search statistics
std::cout << "info nodes " << nodes_searched() << " nps " << nps() std::cout << "info nodes " << nodes_searched()
<< " time " << current_search_time() << " nps " << nps()
<< " hashfull " << TT.full() << std::endl; << " time " << current_search_time()
<< " hashfull " << TT.full() << std::endl;
// Print the best move and the ponder move to the standard output: // Print the best move and the ponder move to the standard output
std::cout << "bestmove " << ss[0].pv[0]; std::cout << "bestmove " << ss[0].pv[0];
if(ss[0].pv[1] != MOVE_NONE) if (ss[0].pv[1] != MOVE_NONE)
std::cout << " ponder " << ss[0].pv[1]; std::cout << " ponder " << ss[0].pv[1];
std::cout << std::endl; std::cout << std::endl;
if(UseLogFile) { if (UseLogFile)
UndoInfo u; {
LogFile << "Nodes: " << nodes_searched() << '\n'; UndoInfo u;
LogFile << "Nodes/second: " << nps() << '\n'; LogFile << "Nodes: " << nodes_searched() << std::endl
LogFile << "Best move: " << move_to_san(p, ss[0].pv[0]) << '\n'; << "Nodes/second: " << nps() << std::endl
p.do_move(ss[0].pv[0], u); << "Best move: " << move_to_san(p, ss[0].pv[0]) << std::endl;
LogFile << "Ponder move: " << move_to_san(p, ss[0].pv[1]) << '\n';
LogFile << std::endl; p.do_move(ss[0].pv[0], u);
LogFile << "Ponder move: " << move_to_san(p, ss[0].pv[1])
<< std::endl << std::endl;
} }
return rml.get_move_score(0); return rml.get_move_score(0);
} }
@ -729,134 +738,147 @@ namespace {
// and prints some information to the standard output. // and prints some information to the standard output.
Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml) { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml) {
Value alpha = -VALUE_INFINITE, beta = VALUE_INFINITE, value;
Value alpha = -VALUE_INFINITE;
Value beta = VALUE_INFINITE, value;
Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move());
// Loop through all the moves in the root move list: // Loop through all the moves in the root move list
for(int i = 0; i < rml.move_count() && !AbortSearch; i++) { for (int i = 0; i < rml.move_count() && !AbortSearch; i++)
int64_t nodes; {
Move move; int64_t nodes;
UndoInfo u; Move move;
Depth ext, newDepth; UndoInfo u;
Depth ext, newDepth;
RootMoveNumber = i + 1; RootMoveNumber = i + 1;
FailHigh = false; FailHigh = false;
// Remember the node count before the move is searched. The node counts // Remember the node count before the move is searched. The node counts
// are used to sort the root moves at the next iteration. // are used to sort the root moves at the next iteration.
nodes = nodes_searched(); nodes = nodes_searched();
// Pick the next root move, and print the move and the move number to // Pick the next root move, and print the move and the move number to
// the standard output: // the standard output.
move = ss[0].currentMove = rml.get_move(i); move = ss[0].currentMove = rml.get_move(i);
if(current_search_time() >= 1000) if (current_search_time() >= 1000)
std::cout << "info currmove " << move std::cout << "info currmove " << move
<< " currmovenumber " << i + 1 << std::endl; << " currmovenumber " << i + 1 << std::endl;
// Decide search depth for this move: // Decide search depth for this move
ext = extension(pos, move, true, pos.move_is_check(move), false, false); ext = extension(pos, move, true, pos.move_is_check(move), false, false);
newDepth = (Iteration-2)*OnePly + ext + InitialDepth; newDepth = (Iteration - 2) * OnePly + ext + InitialDepth;
// Make the move, and search it. // Make the move, and search it
pos.do_move(move, u, dcCandidates); pos.do_move(move, u, dcCandidates);
if(i < MultiPV) { if (i < MultiPV)
value = -search_pv(pos, ss, -beta, VALUE_INFINITE, newDepth, 1, 0); {
// If the value has dropped a lot compared to the last iteration, value = -search_pv(pos, ss, -beta, VALUE_INFINITE, newDepth, 1, 0);
// set the boolean variable Problem to true. This variable is used // If the value has dropped a lot compared to the last iteration,
// for time managment: When Problem is true, we try to complete the // set the boolean variable Problem to true. This variable is used
// current iteration before playing a move. // for time managment: When Problem is true, we try to complete the
Problem = (Iteration >= 2 && // current iteration before playing a move.
value <= ValueByIteration[Iteration-1] - ProblemMargin); Problem = (Iteration >= 2 && value <= ValueByIteration[Iteration-1] - ProblemMargin);
if(Problem && StopOnPonderhit)
StopOnPonderhit = false; if (Problem && StopOnPonderhit)
} StopOnPonderhit = false;
else { }
value = -search(pos, ss, -alpha, newDepth, 1, true, 0); else
if(value > alpha) { {
// Fail high! Set the boolean variable FailHigh to true, and value = -search(pos, ss, -alpha, newDepth, 1, true, 0);
// re-search the move with a big window. The variable FailHigh is if (value > alpha)
// used for time managment: We try to avoid aborting the search {
// prematurely during a fail high research. // Fail high! Set the boolean variable FailHigh to true, and
FailHigh = true; // re-search the move with a big window. The variable FailHigh is
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0); // used for time managment: We try to avoid aborting the search
// prematurely during a fail high research.
FailHigh = true;
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
}
} }
}
pos.undo_move(move, u); pos.undo_move(move, u);
// Finished searching the move. If AbortSearch is true, the search // Finished searching the move. If AbortSearch is true, the search
// was aborted because the user interrupted the search or because we // was aborted because the user interrupted the search or because we
// ran out of time. In this case, the return value of the search cannot // ran out of time. In this case, the return value of the search cannot
// be trusted, and we break out of the loop without updating the best // be trusted, and we break out of the loop without updating the best
// move and/or PV: // move and/or PV:
if(AbortSearch) if (AbortSearch)
break; break;
// Remember the node count for this move. The node counts are used to // Remember the node count for this move. The node counts are used to
// sort the root moves at the next iteration. // sort the root moves at the next iteration.
rml.set_move_nodes(i, nodes_searched() - nodes); rml.set_move_nodes(i, nodes_searched() - nodes);
assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE); assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE);
if(value <= alpha && i >= MultiPV) if (value <= alpha && i >= MultiPV)
rml.set_move_score(i, -VALUE_INFINITE); rml.set_move_score(i, -VALUE_INFINITE);
else { else
// New best move! {
// New best move!
// Update PV: // Update PV
rml.set_move_score(i, value); rml.set_move_score(i, value);
update_pv(ss, 0); update_pv(ss, 0);
rml.set_move_pv(i, ss[0].pv); rml.set_move_pv(i, ss[0].pv);
if(MultiPV == 1) { if (MultiPV == 1)
// We record how often the best move has been changed in each {
// iteration. This information is used for time managment: When // We record how often the best move has been changed in each
// the best move changes frequently, we allocate some more time. // iteration. This information is used for time managment: When
if(i > 0) // the best move changes frequently, we allocate some more time.
BestMoveChangesByIteration[Iteration]++; if (i > 0)
BestMoveChangesByIteration[Iteration]++;
// Print search information to the standard output: // Print search information to the standard output:
std::cout << "info depth " << Iteration std::cout << "info depth " << Iteration
<< " score " << value_to_string(value) << " score " << value_to_string(value)
<< " time " << current_search_time() << " time " << current_search_time()
<< " nodes " << nodes_searched() << " nodes " << nodes_searched()
<< " nps " << nps() << " nps " << nps()
<< " pv "; << " pv ";
for(int j = 0; ss[0].pv[j] != MOVE_NONE && j < PLY_MAX; j++)
std::cout << ss[0].pv[j] << " ";
std::cout << std::endl;
if(UseLogFile) for (int j = 0; ss[0].pv[j] != MOVE_NONE && j < PLY_MAX; j++)
LogFile << pretty_pv(pos, current_search_time(), Iteration, std::cout << ss[0].pv[j] << " ";
nodes_searched(), value, ss[0].pv)
<< std::endl;
alpha = value; std::cout << std::endl;
// Reset the global variable Problem to false if the value isn't too if (UseLogFile)
// far below the final value from the last iteration. LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value, ss[0].pv)
if(value > ValueByIteration[Iteration - 1] - NoProblemMargin) << std::endl;
Problem = false;
alpha = value;
// Reset the global variable Problem to false if the value isn't too
// far below the final value from the last iteration.
if (value > ValueByIteration[Iteration - 1] - NoProblemMargin)
Problem = false;
}
else // MultiPV > 1
{
rml.sort_multipv(i);
for (int j = 0; j < Min(MultiPV, rml.move_count()); j++)
{
int k;
std::cout << "info multipv " << j + 1
<< " score " << value_to_string(rml.get_move_score(j))
<< " depth " << ((j <= i)? Iteration : Iteration - 1)
<< " time " << current_search_time()
<< " nodes " << nodes_searched()
<< " nps " << nps()
<< " pv ";
for (k = 0; rml.get_move_pv(j, k) != MOVE_NONE && k < PLY_MAX; k++)
std::cout << rml.get_move_pv(j, k) << " ";
std::cout << std::endl;
}
alpha = rml.get_move_score(Min(i, MultiPV-1));
}
} }
else { // MultiPV > 1
rml.sort_multipv(i);
for(int j = 0; j < Min(MultiPV, rml.move_count()); j++) {
int k;
std::cout << "info multipv " << j + 1
<< " score " << value_to_string(rml.get_move_score(j))
<< " depth " << ((j <= i)? Iteration : Iteration - 1)
<< " time " << current_search_time()
<< " nodes " << nodes_searched()
<< " nps " << nps()
<< " pv ";
for(k = 0; rml.get_move_pv(j, k) != MOVE_NONE && k < PLY_MAX; k++)
std::cout << rml.get_move_pv(j, k) << " ";
std::cout << std::endl;
}
alpha = rml.get_move_score(Min(i, MultiPV-1));
}
}
} }
return alpha; return alpha;
} }