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
parent
cf2bafb661
commit
e5ebd4f5d1
646
src/search.cpp
646
src/search.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue