// Step 9. Internal iterative deepening
// Minimum depth for use of internal iterative deepening
- const Depth IIDDepth[2] = { 8 * ONE_PLY /* non-PV */, 5 * ONE_PLY /* PV */};
+ const Depth IIDDepth[] = { 8 * ONE_PLY, 5 * ONE_PLY };
// At Non-PV nodes we do an internal iterative deepening search
// when the static evaluation is bigger then beta - IIDMargin.
// Step 11. Decide the new search depth
- // Extensions. Configurable UCI options. Array index 0 is used at
- // non-PV nodes, index 1 at PV nodes.
- Depth CheckExtension[2], PawnPushTo7thExtension[2];
- Depth PassedPawnExtension[2], PawnEndgameExtension[2];
+ // Extensions. Array index 0 is used for non-PV nodes, index 1 for PV nodes
+ const Depth CheckExtension[] = { ONE_PLY / 2, ONE_PLY / 1 };
+ const Depth PawnEndgameExtension[] = { ONE_PLY / 1, ONE_PLY / 1 };
+ const Depth PawnPushTo7thExtension[] = { ONE_PLY / 2, ONE_PLY / 2 };
+ const Depth PassedPawnExtension[] = { DEPTH_ZERO, ONE_PLY / 2 };
// Minimum depth for use of singular extension
- const Depth SingularExtensionDepth[2] = { 8 * ONE_PLY /* non-PV */, 6 * ONE_PLY /* PV */};
+ const Depth SingularExtensionDepth[] = { 8 * ONE_PLY, 6 * ONE_PLY };
// Step 12. Futility pruning
Value FutilityMarginsMatrix[16][64]; // [depth][moveNumber]
int FutilityMoveCountArray[32]; // [depth]
- inline Value futility_margin(Depth d, int mn) { return d < 7 * ONE_PLY ? FutilityMarginsMatrix[Max(d, 1)][Min(mn, 63)] : 2 * VALUE_INFINITE; }
- inline int futility_move_count(Depth d) { return d < 16 * ONE_PLY ? FutilityMoveCountArray[d] : 512; }
+ inline Value futility_margin(Depth d, int mn) {
+
+ return d < 7 * ONE_PLY ? FutilityMarginsMatrix[Max(d, 1)][Min(mn, 63)]
+ : 2 * VALUE_INFINITE;
+ }
+
+ inline int futility_move_count(Depth d) {
+
+ return d < 16 * ONE_PLY ? FutilityMoveCountArray[d] : MAX_MOVES;
+ }
// Step 14. Reduced search
SearchLimits Limits;
// Log file
- bool UseLogFile;
std::ofstream LogFile;
// Skill level adjustment
int64_t perft(Position& pos, Depth depth) {
- MoveStack mlist[MOVES_MAX];
+ MoveStack mlist[MAX_MOVES];
StateInfo st;
Move m;
int64_t sum = 0;
}
// Read UCI options
- CheckExtension[1] = Options["Check Extension (PV nodes)"].value<Depth>();
- CheckExtension[0] = Options["Check Extension (non-PV nodes)"].value<Depth>();
- PawnPushTo7thExtension[1] = Options["Pawn Push to 7th Extension (PV nodes)"].value<Depth>();
- PawnPushTo7thExtension[0] = Options["Pawn Push to 7th Extension (non-PV nodes)"].value<Depth>();
- PassedPawnExtension[1] = Options["Passed Pawn Extension (PV nodes)"].value<Depth>();
- PassedPawnExtension[0] = Options["Passed Pawn Extension (non-PV nodes)"].value<Depth>();
- PawnEndgameExtension[1] = Options["Pawn Endgame Extension (PV nodes)"].value<Depth>();
- PawnEndgameExtension[0] = Options["Pawn Endgame Extension (non-PV nodes)"].value<Depth>();
- UCIMultiPV = Options["MultiPV"].value<int>();
- SkillLevel = Options["Skill level"].value<int>();
- UseLogFile = Options["Use Search Log"].value<bool>();
+ UCIMultiPV = Options["MultiPV"].value<int>();
+ SkillLevel = Options["Skill level"].value<int>();
read_evaluation_uci_options(pos.side_to_move());
}
// Write to log file and keep it open to be accessed during the search
- if (UseLogFile)
+ if (Options["Use Search Log"].value<bool>())
{
std::string name = Options["Search Log Filename"].value<std::string>();
LogFile.open(name.c_str(), std::ios::out | std::ios::app);
- LogFile << "\nSearching: " << pos.to_fen()
- << "\ninfinite: " << Limits.infinite
- << " ponder: " << Limits.ponder
- << " time: " << Limits.time
- << " increment: " << Limits.increment
- << " moves to go: " << Limits.movesToGo
- << endl;
+ if (LogFile.is_open())
+ LogFile << "\nSearching: " << pos.to_fen()
+ << "\ninfinite: " << Limits.infinite
+ << " ponder: " << Limits.ponder
+ << " time: " << Limits.time
+ << " increment: " << Limits.increment
+ << " moves to go: " << Limits.movesToGo
+ << endl;
}
// We're ready to start thinking. Call the iterative deepening loop function
cout << "info" << speed_to_uci(pos.nodes_searched()) << endl;
// Write final search statistics and close log file
- if (UseLogFile)
+ if (LogFile.is_open())
{
int t = current_search_time();
return MOVE_NONE;
}
- // Iterative deepening loop
- while (++depth <= PLY_MAX && (!Limits.maxDepth || depth <= Limits.maxDepth) && !StopRequest)
+ // Iterative deepening loop until requested to stop or target depth reached
+ while (!StopRequest && ++depth <= PLY_MAX && (!Limits.maxDepth || depth <= Limits.maxDepth))
{
Rml.bestMoveChanges = 0;
cout << set960(pos.is_chess960()) << "info depth " << depth << endl;
for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++)
cout << Rml[i].pv_info_to_uci(pos, depth, selDepth, alpha, beta, i) << endl;
- if (UseLogFile)
+ if (LogFile.is_open())
LogFile << pretty_pv(pos, depth, value, current_search_time(), Rml[0].pv) << endl;
// Init easyMove after first iteration or drop if differs from the best move
else if (bestMove != easyMove)
easyMove = MOVE_NONE;
- if (Limits.useTimeManagement() && !StopRequest)
+ // Check for some early stop condition
+ if (!StopRequest && Limits.useTimeManagement())
{
- // Time to stop?
- bool noMoreTime = false;
-
// Stop search early when the last two iterations returned a mate score
if ( depth >= 5
- && abs(bestValues[depth]) >= abs(VALUE_MATE) - 100
- && abs(bestValues[depth - 1]) >= abs(VALUE_MATE) - 100)
- noMoreTime = true;
+ && abs(bestValues[depth]) >= VALUE_MATE_IN_PLY_MAX
+ && abs(bestValues[depth - 1]) >= VALUE_MATE_IN_PLY_MAX)
+ StopRequest = true;
// Stop search early if one move seems to be much better than the
- // others or if there is only a single legal move. In this latter
- // case we search up to Iteration 8 anyway to get a proper score.
+ // others or if there is only a single legal move. Also in the latter
+ // case we search up to some depth anyway to get a proper score.
if ( depth >= 7
&& easyMove == bestMove
&& ( Rml.size() == 1
&& current_search_time() > TimeMgr.available_time() / 16)
||( Rml[0].nodes > (pos.nodes_searched() * 98) / 100
&& current_search_time() > TimeMgr.available_time() / 32)))
- noMoreTime = true;
+ StopRequest = true;
- // Add some extra time if the best move has changed during the last two iterations
+ // Take in account some extra time if the best move has changed
if (depth > 4 && depth < 50)
- TimeMgr.pv_instability(bestMoveChanges[depth], bestMoveChanges[depth-1]);
+ TimeMgr.pv_instability(bestMoveChanges[depth], bestMoveChanges[depth - 1]);
- // Stop search if most of MaxSearchTime is consumed at the end of the
- // iteration. We probably don't have enough time to search the first
- // move at the next iteration anyway.
- if (current_search_time() > (TimeMgr.available_time() * 80) / 128)
- noMoreTime = true;
+ // Stop search if most of available time is already consumed. We probably don't
+ // have enough time to search the first move at the next iteration anyway.
+ if (current_search_time() > (TimeMgr.available_time() * 62) / 100)
+ StopRequest = true;
- if (noMoreTime)
+ // If we are allowed to ponder do not stop the search now but keep pondering
+ if (StopRequest && Limits.ponder)
{
- if (Limits.ponder)
- StopOnPonderhit = true;
- else
- break;
+ StopRequest = false;
+ StopOnPonderhit = true;
}
}
}
- // When using skills fake best and ponder moves with the sub-optimal ones
+ // When using skills overwrite best and ponder moves with the sub-optimal ones
if (SkillLevelEnabled)
{
if (skillBest == MOVE_NONE) // Still unassigned ?
assert(PvNode || alpha == beta - 1);
assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
- Move movesSearched[MOVES_MAX];
+ Move movesSearched[MAX_MOVES];
int64_t nodes;
StateInfo st;
const TTEntry *tte;
void RootMoveList::init(Position& pos, Move searchMoves[]) {
- MoveStack mlist[MOVES_MAX];
+ MoveStack mlist[MAX_MOVES];
Move* sm;
clear();