mirror of
https://github.com/sockspls/badfish
synced 2025-05-01 01:03:09 +00:00
Additional search.cpp cleanup
Changed FutilityMarginsMatrix dimensions to be a power of two so that compiler can produce a faster accessing code. Introduced print_pv_info() to remove some redundant code in root_search() Remaining stuff is triviality and documentation tweaks. No functional change. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
0f50f10327
commit
a303bde26c
1 changed files with 126 additions and 138 deletions
250
src/search.cpp
250
src/search.cpp
|
@ -165,7 +165,7 @@ namespace {
|
||||||
const Depth RazorDepth = 4 * OnePly;
|
const Depth RazorDepth = 4 * OnePly;
|
||||||
|
|
||||||
// Dynamic razoring margin based on depth
|
// Dynamic razoring margin based on depth
|
||||||
inline Value razor_margin(Depth d) { return Value(0x200 + 0x10 * d); }
|
inline Value razor_margin(Depth d) { return Value(0x200 + 0x10 * int(d)); }
|
||||||
|
|
||||||
// Step 8. Null move search with verification search
|
// Step 8. Null move search with verification search
|
||||||
|
|
||||||
|
@ -182,14 +182,13 @@ namespace {
|
||||||
const Depth IIDDepthAtPVNodes = 5 * OnePly;
|
const Depth IIDDepthAtPVNodes = 5 * OnePly;
|
||||||
const Depth IIDDepthAtNonPVNodes = 8 * OnePly;
|
const Depth IIDDepthAtNonPVNodes = 8 * OnePly;
|
||||||
|
|
||||||
// Internal iterative deepening margin. At Non-PV nodes
|
// At Non-PV nodes we do an internal iterative deepening search
|
||||||
// we do an internal iterative deepening
|
// when the static evaluation is at most IIDMargin below beta.
|
||||||
// search when the static evaluation is at most IIDMargin below beta.
|
|
||||||
const Value IIDMargin = Value(0x100);
|
const Value IIDMargin = Value(0x100);
|
||||||
|
|
||||||
// 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 non-PV nodes, index 1 at PV nodes.
|
// Array index 0 is used at non-PV nodes, index 1 at PV nodes.
|
||||||
Depth CheckExtension[2], SingleEvasionExtension[2], PawnPushTo7thExtension[2];
|
Depth CheckExtension[2], SingleEvasionExtension[2], PawnPushTo7thExtension[2];
|
||||||
Depth PassedPawnExtension[2], PawnEndgameExtension[2], MateThreatExtension[2];
|
Depth PassedPawnExtension[2], PawnEndgameExtension[2], MateThreatExtension[2];
|
||||||
|
@ -208,11 +207,11 @@ namespace {
|
||||||
const Value FutilityMarginQS = Value(0x80);
|
const Value FutilityMarginQS = Value(0x80);
|
||||||
|
|
||||||
// Futility lookup tables (initialized at startup) and their getter functions
|
// Futility lookup tables (initialized at startup) and their getter functions
|
||||||
int32_t FutilityMarginsMatrix[14][64]; // [depth][moveNumber]
|
int32_t FutilityMarginsMatrix[16][64]; // [depth][moveNumber]
|
||||||
int FutilityMoveCountArray[32]; // [depth]
|
int FutilityMoveCountArray[32]; // [depth]
|
||||||
|
|
||||||
inline Value futility_margin(Depth d, int mn) { return Value(d < 7*OnePly ? FutilityMarginsMatrix[Max(d, 0)][Min(mn, 63)] : 2 * VALUE_INFINITE); }
|
inline Value futility_margin(Depth d, int mn) { return Value(d < 7 * OnePly ? FutilityMarginsMatrix[Max(d, 0)][Min(mn, 63)] : 2 * VALUE_INFINITE); }
|
||||||
inline int futility_move_count(Depth d) { return d < 16*OnePly ? FutilityMoveCountArray[d] : 512; }
|
inline int futility_move_count(Depth d) { return d < 16 * OnePly ? FutilityMoveCountArray[d] : 512; }
|
||||||
|
|
||||||
// Step 14. Reduced search
|
// Step 14. Reduced search
|
||||||
|
|
||||||
|
@ -223,7 +222,7 @@ namespace {
|
||||||
inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
|
inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
|
||||||
inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
|
inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
|
||||||
|
|
||||||
// Step. Common adjustments
|
// Common adjustments
|
||||||
|
|
||||||
// Search depth at iteration 1
|
// Search depth at iteration 1
|
||||||
const Depth InitialDepth = OnePly;
|
const Depth InitialDepth = OnePly;
|
||||||
|
@ -241,7 +240,7 @@ namespace {
|
||||||
|
|
||||||
/// Global variables
|
/// Global variables
|
||||||
|
|
||||||
// Iteration counters
|
// Iteration counter
|
||||||
int Iteration;
|
int Iteration;
|
||||||
|
|
||||||
// Scores and number of times the best move changed for each iteration
|
// Scores and number of times the best move changed for each iteration
|
||||||
|
@ -255,13 +254,10 @@ namespace {
|
||||||
int MultiPV;
|
int MultiPV;
|
||||||
|
|
||||||
// Time managment variables
|
// Time managment variables
|
||||||
int RootMoveNumber;
|
int RootMoveNumber, SearchStartTime, MaxNodes, MaxDepth;
|
||||||
int SearchStartTime;
|
|
||||||
int MaxNodes, MaxDepth;
|
|
||||||
int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
|
int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
|
||||||
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
|
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
|
||||||
bool AbortSearch, Quit;
|
bool AbortSearch, Quit, AspirationFailLow;
|
||||||
bool AspirationFailLow;
|
|
||||||
|
|
||||||
// Show current line?
|
// Show current line?
|
||||||
bool ShowCurrentLine;
|
bool ShowCurrentLine;
|
||||||
|
@ -270,20 +266,20 @@ namespace {
|
||||||
bool UseLogFile;
|
bool UseLogFile;
|
||||||
std::ofstream LogFile;
|
std::ofstream LogFile;
|
||||||
|
|
||||||
// MP related variables
|
// Multi-threads related variables
|
||||||
Depth MinimumSplitDepth;
|
Depth MinimumSplitDepth;
|
||||||
int MaxThreadsPerSplitPoint;
|
int MaxThreadsPerSplitPoint;
|
||||||
ThreadsManager TM;
|
ThreadsManager TM;
|
||||||
|
|
||||||
// Node counters, used only by thread[0] but try to keep in different
|
// Node counters, used only by thread[0] but try to keep in different cache
|
||||||
// cache lines (64 bytes each) from the heavy SMP read accessed variables.
|
// lines (64 bytes each) from the heavy multi-thread read accessed variables.
|
||||||
int NodesSincePoll;
|
int NodesSincePoll;
|
||||||
int NodesBetweenPolls = 30000;
|
int NodesBetweenPolls = 30000;
|
||||||
|
|
||||||
// History table
|
// History table
|
||||||
History H;
|
History H;
|
||||||
|
|
||||||
/// Functions
|
/// Local functions
|
||||||
|
|
||||||
Value id_loop(const Position& pos, Move searchMoves[]);
|
Value id_loop(const Position& pos, Move searchMoves[]);
|
||||||
Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta);
|
Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta);
|
||||||
|
@ -313,6 +309,7 @@ namespace {
|
||||||
void ponderhit();
|
void ponderhit();
|
||||||
void wait_for_stop_or_ponderhit();
|
void wait_for_stop_or_ponderhit();
|
||||||
void init_ss_array(SearchStack ss[]);
|
void init_ss_array(SearchStack ss[]);
|
||||||
|
void print_pv_info(const Position& pos, SearchStack ss[], Value alpha, Value beta, Value value);
|
||||||
|
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
void *init_thread(void *threadID);
|
void *init_thread(void *threadID);
|
||||||
|
@ -340,9 +337,10 @@ int64_t nodes_searched() { return TM.nodes_searched(); }
|
||||||
|
|
||||||
int perft(Position& pos, Depth depth)
|
int perft(Position& pos, Depth depth)
|
||||||
{
|
{
|
||||||
|
StateInfo st;
|
||||||
Move move;
|
Move move;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
MovePicker mp = MovePicker(pos, MOVE_NONE, depth, H);
|
MovePicker mp(pos, MOVE_NONE, depth, H);
|
||||||
|
|
||||||
// If we are at the last ply we don't need to do and undo
|
// If we are at the last ply we don't need to do and undo
|
||||||
// the moves, just to count them.
|
// the moves, just to count them.
|
||||||
|
@ -356,7 +354,6 @@ int perft(Position& pos, Depth depth)
|
||||||
CheckInfo ci(pos);
|
CheckInfo ci(pos);
|
||||||
while ((move = mp.get_next_move()) != MOVE_NONE)
|
while ((move = mp.get_next_move()) != MOVE_NONE)
|
||||||
{
|
{
|
||||||
StateInfo st;
|
|
||||||
pos.do_move(move, st, ci, pos.move_is_check(move, ci));
|
pos.do_move(move, st, ci, pos.move_is_check(move, ci));
|
||||||
sum += perft(pos, depth - OnePly);
|
sum += perft(pos, depth - OnePly);
|
||||||
pos.undo_move(move);
|
pos.undo_move(move);
|
||||||
|
@ -375,9 +372,9 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||||
int maxNodes, int maxTime, Move searchMoves[]) {
|
int maxNodes, int maxTime, Move searchMoves[]) {
|
||||||
|
|
||||||
// Initialize global search variables
|
// Initialize global search variables
|
||||||
StopOnPonderhit = AbortSearch = Quit = false;
|
StopOnPonderhit = AbortSearch = Quit = AspirationFailLow = false;
|
||||||
AspirationFailLow = false;
|
|
||||||
NodesSincePoll = 0;
|
NodesSincePoll = 0;
|
||||||
|
TM.resetNodeCounters();
|
||||||
SearchStartTime = get_system_time();
|
SearchStartTime = get_system_time();
|
||||||
ExactMaxTime = maxTime;
|
ExactMaxTime = maxTime;
|
||||||
MaxDepth = maxDepth;
|
MaxDepth = maxDepth;
|
||||||
|
@ -389,11 +386,10 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||||
// Look for a book move, only during games, not tests
|
// Look for a book move, only during games, not tests
|
||||||
if (UseTimeManagement && get_option_value_bool("OwnBook"))
|
if (UseTimeManagement && get_option_value_bool("OwnBook"))
|
||||||
{
|
{
|
||||||
Move bookMove;
|
|
||||||
if (get_option_value_string("Book File") != OpeningBook.file_name())
|
if (get_option_value_string("Book File") != OpeningBook.file_name())
|
||||||
OpeningBook.open(get_option_value_string("Book File"));
|
OpeningBook.open(get_option_value_string("Book File"));
|
||||||
|
|
||||||
bookMove = OpeningBook.get_move(pos);
|
Move bookMove = OpeningBook.get_move(pos);
|
||||||
if (bookMove != MOVE_NONE)
|
if (bookMove != MOVE_NONE)
|
||||||
{
|
{
|
||||||
if (PonderSearch)
|
if (PonderSearch)
|
||||||
|
@ -404,45 +400,37 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TM.resetNodeCounters();
|
// Reset loseOnTime flag at the beginning of a new game
|
||||||
|
|
||||||
if (button_was_pressed("New Game"))
|
if (button_was_pressed("New Game"))
|
||||||
loseOnTime = false; // Reset at the beginning of a new game
|
loseOnTime = false;
|
||||||
|
|
||||||
// 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();
|
||||||
|
|
||||||
bool PonderingEnabled = get_option_value_bool("Ponder");
|
|
||||||
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] = Depth(get_option_value_int("Check Extension (non-PV nodes)"));
|
CheckExtension[0] = Depth(get_option_value_int("Check Extension (non-PV nodes)"));
|
||||||
|
|
||||||
SingleEvasionExtension[1] = Depth(get_option_value_int("Single Evasion Extension (PV nodes)"));
|
SingleEvasionExtension[1] = Depth(get_option_value_int("Single Evasion Extension (PV nodes)"));
|
||||||
SingleEvasionExtension[0] = Depth(get_option_value_int("Single Evasion Extension (non-PV nodes)"));
|
SingleEvasionExtension[0] = Depth(get_option_value_int("Single Evasion Extension (non-PV nodes)"));
|
||||||
|
|
||||||
PawnPushTo7thExtension[1] = Depth(get_option_value_int("Pawn Push to 7th Extension (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)"));
|
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[1] = Depth(get_option_value_int("Passed Pawn Extension (PV nodes)"));
|
||||||
PassedPawnExtension[0] = Depth(get_option_value_int("Passed Pawn Extension (non-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[1] = Depth(get_option_value_int("Pawn Endgame Extension (PV nodes)"));
|
||||||
PawnEndgameExtension[0] = Depth(get_option_value_int("Pawn Endgame Extension (non-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[1] = Depth(get_option_value_int("Mate Threat Extension (PV nodes)"));
|
||||||
MateThreatExtension[0] = Depth(get_option_value_int("Mate Threat Extension (non-PV nodes)"));
|
MateThreatExtension[0] = Depth(get_option_value_int("Mate Threat Extension (non-PV nodes)"));
|
||||||
|
|
||||||
Chess960 = get_option_value_bool("UCI_Chess960");
|
|
||||||
ShowCurrentLine = get_option_value_bool("UCI_ShowCurrLine");
|
|
||||||
UseLogFile = get_option_value_bool("Use Search Log");
|
|
||||||
if (UseLogFile)
|
|
||||||
LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
|
|
||||||
|
|
||||||
MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly;
|
MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly;
|
||||||
MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
|
MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
|
||||||
|
ShowCurrentLine = get_option_value_bool("UCI_ShowCurrLine");
|
||||||
|
MultiPV = get_option_value_int("MultiPV");
|
||||||
|
Chess960 = get_option_value_bool("UCI_Chess960");
|
||||||
|
UseLogFile = get_option_value_bool("Use Search Log");
|
||||||
|
|
||||||
|
if (UseLogFile)
|
||||||
|
LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
|
||||||
|
|
||||||
read_weights(pos.side_to_move());
|
read_weights(pos.side_to_move());
|
||||||
|
|
||||||
|
@ -493,14 +481,15 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PonderingEnabled)
|
if (get_option_value_bool("Ponder"))
|
||||||
{
|
{
|
||||||
MaxSearchTime += MaxSearchTime / 4;
|
MaxSearchTime += MaxSearchTime / 4;
|
||||||
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
|
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set best NodesBetweenPolls interval
|
// Set best NodesBetweenPolls interval to avoid lagging under
|
||||||
|
// heavy time pressure.
|
||||||
if (MaxNodes)
|
if (MaxNodes)
|
||||||
NodesBetweenPolls = Min(MaxNodes, 30000);
|
NodesBetweenPolls = Min(MaxNodes, 30000);
|
||||||
else if (myTime && myTime < 1000)
|
else if (myTime && myTime < 1000)
|
||||||
|
@ -510,7 +499,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||||
else
|
else
|
||||||
NodesBetweenPolls = 30000;
|
NodesBetweenPolls = 30000;
|
||||||
|
|
||||||
// Write information to search log file
|
// Write search information to log file
|
||||||
if (UseLogFile)
|
if (UseLogFile)
|
||||||
LogFile << "Searching: " << pos.to_fen() << endl
|
LogFile << "Searching: " << pos.to_fen() << endl
|
||||||
<< "infinite: " << infinite
|
<< "infinite: " << infinite
|
||||||
|
@ -519,7 +508,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
|
||||||
<< " increment: " << myIncrement
|
<< " increment: " << myIncrement
|
||||||
<< " moves to go: " << movesToGo << endl;
|
<< " moves to go: " << movesToGo << endl;
|
||||||
|
|
||||||
// LSN filtering. Used only for developing purpose. Disabled by default.
|
// LSN filtering. Used only for developing purposes, disabled by default
|
||||||
if ( UseLSNFiltering
|
if ( UseLSNFiltering
|
||||||
&& loseOnTime)
|
&& loseOnTime)
|
||||||
{
|
{
|
||||||
|
@ -574,10 +563,11 @@ void init_search() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init futility margins array
|
// Init futility margins array
|
||||||
for (int i = 0; i < 14; i++) // i == depth (OnePly = 2)
|
for (int i = 0; i < 16; i++) // i == depth (OnePly = 2)
|
||||||
for (int j = 0; j < 64; j++) // j == moveNumber
|
for (int j = 0; j < 64; j++) // j == moveNumber
|
||||||
{
|
{
|
||||||
FutilityMarginsMatrix[i][j] = (i < 2 ? 0 : 112 * bitScanReverse32(i * i / 2)) - 8 * j; // FIXME: test using log instead of BSR
|
// FIXME: test using log instead of BSR
|
||||||
|
FutilityMarginsMatrix[i][j] = (i < 2 ? 0 : 112 * bitScanReverse32(i * i / 2)) - 8 * j;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init futility move count array
|
// Init futility move count array
|
||||||
|
@ -614,8 +604,10 @@ namespace {
|
||||||
|
|
||||||
Position p(pos);
|
Position p(pos);
|
||||||
SearchStack ss[PLY_MAX_PLUS_2];
|
SearchStack ss[PLY_MAX_PLUS_2];
|
||||||
|
Move EasyMove = MOVE_NONE;
|
||||||
|
Value value, alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
|
||||||
|
|
||||||
// searchMoves are verified, copied, scored and sorted
|
// Moves to search are verified, copied, scored and sorted
|
||||||
RootMoveList rml(p, searchMoves);
|
RootMoveList rml(p, searchMoves);
|
||||||
|
|
||||||
// Handle special case of searching on a mate/stale position
|
// Handle special case of searching on a mate/stale position
|
||||||
|
@ -624,12 +616,13 @@ namespace {
|
||||||
if (PonderSearch)
|
if (PonderSearch)
|
||||||
wait_for_stop_or_ponderhit();
|
wait_for_stop_or_ponderhit();
|
||||||
|
|
||||||
return pos.is_check()? -VALUE_MATE : VALUE_DRAW;
|
return pos.is_check() ? -VALUE_MATE : VALUE_DRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print RootMoveList c'tor startup scoring to the standard output,
|
// Print RootMoveList startup scoring to the standard output,
|
||||||
// so that we print information also for iteration 1.
|
// so to output information also for iteration 1.
|
||||||
cout << "info depth " << 1 << "\ninfo depth " << 1
|
cout << "info depth " << 1
|
||||||
|
<< "\ninfo depth " << 1
|
||||||
<< " score " << value_to_string(rml.get_move_score(0))
|
<< " score " << value_to_string(rml.get_move_score(0))
|
||||||
<< " time " << current_search_time()
|
<< " time " << current_search_time()
|
||||||
<< " nodes " << TM.nodes_searched()
|
<< " nodes " << TM.nodes_searched()
|
||||||
|
@ -644,7 +637,6 @@ namespace {
|
||||||
Iteration = 1;
|
Iteration = 1;
|
||||||
|
|
||||||
// Is one move significantly better than others after initial scoring ?
|
// Is one move significantly better than others after initial scoring ?
|
||||||
Move EasyMove = MOVE_NONE;
|
|
||||||
if ( rml.move_count() == 1
|
if ( rml.move_count() == 1
|
||||||
|| rml.get_move_score(0) > rml.get_move_score(1) + EasyMoveMargin)
|
|| rml.get_move_score(0) > rml.get_move_score(1) + EasyMoveMargin)
|
||||||
EasyMove = rml.get_move(0);
|
EasyMove = rml.get_move(0);
|
||||||
|
@ -661,9 +653,7 @@ namespace {
|
||||||
|
|
||||||
cout << "info depth " << Iteration << endl;
|
cout << "info depth " << Iteration << endl;
|
||||||
|
|
||||||
// Calculate dynamic search window based on previous iterations
|
// Calculate dynamic aspiration window based on previous iterations
|
||||||
Value alpha, beta;
|
|
||||||
|
|
||||||
if (MultiPV == 1 && Iteration >= 6 && abs(ValueByIteration[Iteration - 1]) < VALUE_KNOWN_WIN)
|
if (MultiPV == 1 && Iteration >= 6 && abs(ValueByIteration[Iteration - 1]) < VALUE_KNOWN_WIN)
|
||||||
{
|
{
|
||||||
int prevDelta1 = ValueByIteration[Iteration - 1] - ValueByIteration[Iteration - 2];
|
int prevDelta1 = ValueByIteration[Iteration - 1] - ValueByIteration[Iteration - 2];
|
||||||
|
@ -675,14 +665,9 @@ namespace {
|
||||||
alpha = Max(ValueByIteration[Iteration - 1] - AspirationDelta, -VALUE_INFINITE);
|
alpha = Max(ValueByIteration[Iteration - 1] - AspirationDelta, -VALUE_INFINITE);
|
||||||
beta = Min(ValueByIteration[Iteration - 1] + AspirationDelta, VALUE_INFINITE);
|
beta = Min(ValueByIteration[Iteration - 1] + AspirationDelta, VALUE_INFINITE);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
alpha = - VALUE_INFINITE;
|
|
||||||
beta = VALUE_INFINITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search to the current depth
|
// Search to the current depth
|
||||||
Value value = root_search(p, ss, rml, alpha, beta);
|
value = root_search(p, ss, rml, alpha, beta);
|
||||||
|
|
||||||
// Write PV to transposition table, in case the relevant entries have
|
// Write PV to transposition table, in case the relevant entries have
|
||||||
// been overwritten during the search.
|
// been overwritten during the search.
|
||||||
|
@ -694,7 +679,7 @@ namespace {
|
||||||
//Save info about search result
|
//Save info about search result
|
||||||
ValueByIteration[Iteration] = value;
|
ValueByIteration[Iteration] = value;
|
||||||
|
|
||||||
// Drop the easy move if it differs from the new best move
|
// Drop the easy move if differs from the new best move
|
||||||
if (ss[0].pv[0] != EasyMove)
|
if (ss[0].pv[0] != EasyMove)
|
||||||
EasyMove = MOVE_NONE;
|
EasyMove = MOVE_NONE;
|
||||||
|
|
||||||
|
@ -714,7 +699,7 @@ namespace {
|
||||||
&& abs(ValueByIteration[Iteration-1]) >= abs(VALUE_MATE) - 100)
|
&& abs(ValueByIteration[Iteration-1]) >= abs(VALUE_MATE) - 100)
|
||||||
stopSearch = true;
|
stopSearch = true;
|
||||||
|
|
||||||
// Stop search early if one move seems to be much better than the rest
|
// Stop search early if one move seems to be much better than the others
|
||||||
int64_t nodes = TM.nodes_searched();
|
int64_t nodes = TM.nodes_searched();
|
||||||
if ( Iteration >= 8
|
if ( Iteration >= 8
|
||||||
&& EasyMove == ss[0].pv[0]
|
&& EasyMove == ss[0].pv[0]
|
||||||
|
@ -737,10 +722,10 @@ namespace {
|
||||||
|
|
||||||
if (stopSearch)
|
if (stopSearch)
|
||||||
{
|
{
|
||||||
if (!PonderSearch)
|
if (PonderSearch)
|
||||||
break;
|
|
||||||
else
|
|
||||||
StopOnPonderhit = true;
|
StopOnPonderhit = true;
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,7 +752,11 @@ namespace {
|
||||||
ss[0].pv[0] = rml.get_move(0);
|
ss[0].pv[0] = rml.get_move(0);
|
||||||
ss[0].pv[1] = MOVE_NONE;
|
ss[0].pv[1] = MOVE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(ss[0].pv[0] != MOVE_NONE);
|
||||||
|
|
||||||
cout << "bestmove " << ss[0].pv[0];
|
cout << "bestmove " << ss[0].pv[0];
|
||||||
|
|
||||||
if (ss[0].pv[1] != MOVE_NONE)
|
if (ss[0].pv[1] != MOVE_NONE)
|
||||||
cout << " ponder " << ss[0].pv[1];
|
cout << " ponder " << ss[0].pv[1];
|
||||||
|
|
||||||
|
@ -787,7 +776,9 @@ namespace {
|
||||||
|
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
p.do_move(ss[0].pv[0], st);
|
p.do_move(ss[0].pv[0], st);
|
||||||
LogFile << "\nPonder move: " << move_to_san(p, ss[0].pv[1]) << endl;
|
LogFile << "\nPonder move: "
|
||||||
|
<< move_to_san(p, ss[0].pv[1]) // Works also with MOVE_NONE
|
||||||
|
<< endl;
|
||||||
}
|
}
|
||||||
return rml.get_move_score(0);
|
return rml.get_move_score(0);
|
||||||
}
|
}
|
||||||
|
@ -795,28 +786,28 @@ namespace {
|
||||||
|
|
||||||
// root_search() is the function which searches the root node. It is
|
// root_search() is the function which searches the root node. It is
|
||||||
// similar to search_pv except that it uses a different move ordering
|
// similar to search_pv except that it uses a different move ordering
|
||||||
// scheme and prints some information to the standard output.
|
// scheme, prints some information to the standard output and handles
|
||||||
|
// the fail low/high loops.
|
||||||
|
|
||||||
Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta) {
|
Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta) {
|
||||||
|
|
||||||
|
EvalInfo ei;
|
||||||
|
StateInfo st;
|
||||||
int64_t nodes;
|
int64_t nodes;
|
||||||
Move move;
|
Move move;
|
||||||
StateInfo st;
|
|
||||||
Depth depth, ext, newDepth;
|
Depth depth, ext, newDepth;
|
||||||
Value value;
|
Value value, alpha;
|
||||||
CheckInfo ci(pos);
|
bool isCheck, moveIsCheck, captureOrPromotion, dangerous;
|
||||||
int researchCount = 0;
|
int researchCount = 0;
|
||||||
bool moveIsCheck, captureOrPromotion, dangerous;
|
CheckInfo ci(pos);
|
||||||
Value alpha = oldAlpha;
|
alpha = oldAlpha;
|
||||||
bool isCheck = pos.is_check();
|
isCheck = pos.is_check();
|
||||||
|
|
||||||
// Evaluate the position statically
|
// Evaluate the position statically
|
||||||
EvalInfo ei;
|
|
||||||
ss[0].eval = !isCheck ? evaluate(pos, ei, 0) : VALUE_NONE;
|
ss[0].eval = !isCheck ? evaluate(pos, ei, 0) : VALUE_NONE;
|
||||||
|
|
||||||
while (1) // Fail low loop
|
while (1) // Fail low loop
|
||||||
{
|
{
|
||||||
|
|
||||||
// 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++)
|
||||||
{
|
{
|
||||||
|
@ -829,6 +820,7 @@ namespace {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is used by time management and starts from 1
|
||||||
RootMoveNumber = i + 1;
|
RootMoveNumber = i + 1;
|
||||||
|
|
||||||
// Save the current node count before the move is searched
|
// Save the current node count before the move is searched
|
||||||
|
@ -852,11 +844,11 @@ namespace {
|
||||||
ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, false, &dangerous);
|
ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, false, &dangerous);
|
||||||
newDepth = depth + ext;
|
newDepth = depth + ext;
|
||||||
|
|
||||||
|
// Reset value before the search
|
||||||
value = - VALUE_INFINITE;
|
value = - VALUE_INFINITE;
|
||||||
|
|
||||||
while (1) // Fail high loop
|
while (1) // Fail high loop
|
||||||
{
|
{
|
||||||
|
|
||||||
// Make the move, and search it
|
// Make the move, and search it
|
||||||
pos.do_move(move, st, ci, moveIsCheck);
|
pos.do_move(move, st, ci, moveIsCheck);
|
||||||
|
|
||||||
|
@ -866,6 +858,7 @@ namespace {
|
||||||
if (MultiPV > 1)
|
if (MultiPV > 1)
|
||||||
alpha = -VALUE_INFINITE;
|
alpha = -VALUE_INFINITE;
|
||||||
|
|
||||||
|
// Full depth PV search, done on first move or after a fail high
|
||||||
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
|
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -874,14 +867,15 @@ namespace {
|
||||||
// if the move fails high will be re-searched at full depth.
|
// if the move fails high will be re-searched at full depth.
|
||||||
bool doFullDepthSearch = true;
|
bool doFullDepthSearch = true;
|
||||||
|
|
||||||
if ( depth >= 3*OnePly // FIXME was newDepth
|
if ( depth >= 3 * OnePly // FIXME was newDepth
|
||||||
&& !dangerous
|
&& !dangerous
|
||||||
&& !captureOrPromotion
|
&& !captureOrPromotion
|
||||||
&& !move_is_castle(move))
|
&& !move_is_castle(move))
|
||||||
{
|
{
|
||||||
ss[0].reduction = pv_reduction(depth, RootMoveNumber - MultiPV + 1);
|
ss[0].reduction = pv_reduction(depth, i - MultiPV + 2);
|
||||||
if (ss[0].reduction)
|
if (ss[0].reduction)
|
||||||
{
|
{
|
||||||
|
// Reduced depth non-pv search using alpha as upperbound
|
||||||
value = -search(pos, ss, -alpha, newDepth-ss[0].reduction, 1, true, 0);
|
value = -search(pos, ss, -alpha, newDepth-ss[0].reduction, 1, true, 0);
|
||||||
doFullDepthSearch = (value > alpha);
|
doFullDepthSearch = (value > alpha);
|
||||||
}
|
}
|
||||||
|
@ -889,9 +883,12 @@ namespace {
|
||||||
|
|
||||||
if (doFullDepthSearch)
|
if (doFullDepthSearch)
|
||||||
{
|
{
|
||||||
|
// Full depth non-pv search using alpha as upperbound
|
||||||
ss[0].reduction = Depth(0);
|
ss[0].reduction = Depth(0);
|
||||||
value = -search(pos, ss, -alpha, newDepth, 1, true, 0);
|
value = -search(pos, ss, -alpha, newDepth, 1, true, 0);
|
||||||
|
|
||||||
|
// If we are above alpha then research at same depth but as PV
|
||||||
|
// to get a correct score or eventually a fail high above beta.
|
||||||
if (value > alpha)
|
if (value > alpha)
|
||||||
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
|
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
|
||||||
}
|
}
|
||||||
|
@ -903,36 +900,15 @@ namespace {
|
||||||
if (AbortSearch || value < beta)
|
if (AbortSearch || value < beta)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// We are failing high and going to do a research. It's important to update score
|
// We are failing high and going to do a research. It's important to update
|
||||||
// before research in case we run out of time while researching.
|
// the score before research in case we run out of time while researching.
|
||||||
rml.set_move_score(i, value);
|
rml.set_move_score(i, value);
|
||||||
update_pv(ss, 0);
|
update_pv(ss, 0);
|
||||||
TT.extract_pv(pos, ss[0].pv, PLY_MAX);
|
TT.extract_pv(pos, ss[0].pv, PLY_MAX);
|
||||||
rml.set_move_pv(i, ss[0].pv);
|
rml.set_move_pv(i, ss[0].pv);
|
||||||
|
|
||||||
// Print search information to the standard output
|
// Print information to the standard output
|
||||||
cout << "info depth " << Iteration
|
print_pv_info(pos, ss, alpha, beta, value);
|
||||||
<< " score " << value_to_string(value)
|
|
||||||
<< ((value >= beta) ? " lowerbound" :
|
|
||||||
((value <= alpha)? " upperbound" : ""))
|
|
||||||
<< " time " << current_search_time()
|
|
||||||
<< " nodes " << TM.nodes_searched()
|
|
||||||
<< " nps " << nps()
|
|
||||||
<< " pv ";
|
|
||||||
|
|
||||||
for (int j = 0; ss[0].pv[j] != MOVE_NONE && j < PLY_MAX; j++)
|
|
||||||
cout << ss[0].pv[j] << " ";
|
|
||||||
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
if (UseLogFile)
|
|
||||||
{
|
|
||||||
ValueType type = (value >= beta ? VALUE_TYPE_LOWER
|
|
||||||
: (value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT));
|
|
||||||
|
|
||||||
LogFile << pretty_pv(pos, current_search_time(), Iteration,
|
|
||||||
TM.nodes_searched(), value, type, ss[0].pv) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for a research after a fail high, each time with a wider window
|
// Prepare for a research after a fail high, each time with a wider window
|
||||||
researchCount++;
|
researchCount++;
|
||||||
|
@ -977,29 +953,11 @@ namespace {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
BestMoveChangesByIteration[Iteration]++;
|
BestMoveChangesByIteration[Iteration]++;
|
||||||
|
|
||||||
// Print search information to the standard output
|
// Print information to the standard output
|
||||||
cout << "info depth " << Iteration
|
print_pv_info(pos, ss, alpha, beta, value);
|
||||||
<< " score " << value_to_string(value)
|
|
||||||
<< ((value >= beta) ? " lowerbound" :
|
|
||||||
((value <= alpha)? " upperbound" : ""))
|
|
||||||
<< " time " << current_search_time()
|
|
||||||
<< " nodes " << TM.nodes_searched()
|
|
||||||
<< " nps " << nps()
|
|
||||||
<< " pv ";
|
|
||||||
|
|
||||||
for (int j = 0; ss[0].pv[j] != MOVE_NONE && j < PLY_MAX; j++)
|
// Raise alpha to setup proper non-pv search upper bound, note
|
||||||
cout << ss[0].pv[j] << " ";
|
// that we can end up with alpha >= beta and so get a fail high.
|
||||||
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
if (UseLogFile)
|
|
||||||
{
|
|
||||||
ValueType type = (value >= beta ? VALUE_TYPE_LOWER
|
|
||||||
: (value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT));
|
|
||||||
|
|
||||||
LogFile << pretty_pv(pos, current_search_time(), Iteration,
|
|
||||||
TM.nodes_searched(), value, type, ss[0].pv) << endl;
|
|
||||||
}
|
|
||||||
if (value > alpha)
|
if (value > alpha)
|
||||||
alpha = value;
|
alpha = value;
|
||||||
}
|
}
|
||||||
|
@ -1010,7 +968,7 @@ namespace {
|
||||||
{
|
{
|
||||||
cout << "info multipv " << j + 1
|
cout << "info multipv " << j + 1
|
||||||
<< " score " << value_to_string(rml.get_move_score(j))
|
<< " score " << value_to_string(rml.get_move_score(j))
|
||||||
<< " depth " << ((j <= i)? Iteration : Iteration - 1)
|
<< " depth " << (j <= i ? Iteration : Iteration - 1)
|
||||||
<< " time " << current_search_time()
|
<< " time " << current_search_time()
|
||||||
<< " nodes " << TM.nodes_searched()
|
<< " nodes " << TM.nodes_searched()
|
||||||
<< " nps " << nps()
|
<< " nps " << nps()
|
||||||
|
@ -1021,7 +979,7 @@ namespace {
|
||||||
|
|
||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
alpha = rml.get_move_score(Min(i, MultiPV-1));
|
alpha = rml.get_move_score(Min(i, MultiPV - 1));
|
||||||
}
|
}
|
||||||
} // PV move or new best move
|
} // PV move or new best move
|
||||||
|
|
||||||
|
@ -1186,7 +1144,7 @@ namespace {
|
||||||
// if the move fails high will be re-searched at full depth.
|
// if the move fails high will be re-searched at full depth.
|
||||||
bool doFullDepthSearch = true;
|
bool doFullDepthSearch = true;
|
||||||
|
|
||||||
if ( depth >= 3*OnePly
|
if ( depth >= 3 * OnePly
|
||||||
&& !dangerous
|
&& !dangerous
|
||||||
&& !captureOrPromotion
|
&& !captureOrPromotion
|
||||||
&& !move_is_castle(move)
|
&& !move_is_castle(move)
|
||||||
|
@ -2574,6 +2532,36 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print_pv_info() prints to standard output and eventually to log file information on
|
||||||
|
// the current PV line. It is called at each iteration or after a new pv is found.
|
||||||
|
|
||||||
|
void print_pv_info(const Position& pos, SearchStack ss[], Value alpha, Value beta, Value value) {
|
||||||
|
|
||||||
|
cout << "info depth " << Iteration
|
||||||
|
<< " score " << value_to_string(value)
|
||||||
|
<< ((value >= beta) ? " lowerbound" :
|
||||||
|
((value <= alpha)? " upperbound" : ""))
|
||||||
|
<< " time " << current_search_time()
|
||||||
|
<< " nodes " << TM.nodes_searched()
|
||||||
|
<< " nps " << nps()
|
||||||
|
<< " pv ";
|
||||||
|
|
||||||
|
for (int j = 0; ss[0].pv[j] != MOVE_NONE && j < PLY_MAX; j++)
|
||||||
|
cout << ss[0].pv[j] << " ";
|
||||||
|
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
if (UseLogFile)
|
||||||
|
{
|
||||||
|
ValueType type = (value >= beta ? VALUE_TYPE_LOWER
|
||||||
|
: (value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT));
|
||||||
|
|
||||||
|
LogFile << pretty_pv(pos, current_search_time(), Iteration,
|
||||||
|
TM.nodes_searched(), value, type, ss[0].pv) << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// init_thread() is the function which is called when a new thread is
|
// init_thread() is the function which is called when a new thread is
|
||||||
// launched. It simply calls the idle_loop() function with the supplied
|
// launched. It simply calls the idle_loop() function with the supplied
|
||||||
// threadID. There are two versions of this function; one for POSIX
|
// threadID. There are two versions of this function; one for POSIX
|
||||||
|
|
Loading…
Add table
Reference in a new issue