namespace Search {
- SignalsType Signals;
LimitsType Limits;
}
// History and stats update bonus, based on depth
int stat_bonus(Depth depth) {
- int d = depth / ONE_PLY ;
+ int d = depth / ONE_PLY;
return d > 17 ? 0 : d * d + 2 * d - 2;
}
void update_pv(Move* pv, Move move, Move* childPv);
void update_cm_stats(Stack* ss, Piece pc, Square s, int bonus);
void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus);
- void check_time();
} // namespace
for (Thread* th : Threads)
{
- th->resetCalls = true;
th->counterMoves.fill(MOVE_NONE);
th->history.fill(0);
th->counterMoveHistory[NO_PIECE][0].fill(CounterMovePruneThreshold - 1);
}
+ Threads.main()->callsCnt = 0;
Threads.main()->previousScore = VALUE_INFINITE;
}
Color us = rootPos.side_to_move();
Time.init(Limits, us, rootPos.game_ply());
+ TT.new_search();
int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
DrawValue[ us] = VALUE_DRAW - Value(contempt);
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
// When we reach the maximum depth, we can arrive here without a raise of
- // Signals.stop. However, if we are pondering or in an infinite search,
+ // Threads.stop. However, if we are pondering or in an infinite search,
// the UCI protocol states that we shouldn't print the best move before the
// GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
- // until the GUI sends one of those commands (which also raises Signals.stop).
- if (!Signals.stop && (Limits.ponder || Limits.infinite))
+ // until the GUI sends one of those commands (which also raises Threads.stop).
+ if (!Threads.stop && (Limits.ponder || Limits.infinite))
{
- Signals.stopOnPonderhit = true;
- wait(Signals.stop);
+ Threads.stopOnPonderhit = true;
+ wait(Threads.stop);
}
// Stop the threads if not already stopped
- Signals.stop = true;
+ Threads.stop = true;
// Wait until all threads have finished
for (Thread* th : Threads)
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
std::memset(ss-4, 0, 7 * sizeof(Stack));
- for(int i = 4; i > 0; i--)
+ for (int i = 4; i > 0; i--)
(ss-i)->history = &this->counterMoveHistory[NO_PIECE][0]; // Use as sentinel
bestValue = delta = alpha = -VALUE_INFINITE;
EasyMove.clear();
mainThread->easyMovePlayed = mainThread->failedLow = false;
mainThread->bestMoveChanges = 0;
- TT.new_search();
}
size_t multiPV = Options["MultiPV"];
// Iterative deepening loop until requested to stop or the target depth is reached
while ( (rootDepth += ONE_PLY) < DEPTH_MAX
- && !Signals.stop
- && (!Limits.depth || Threads.main()->rootDepth / ONE_PLY <= Limits.depth))
+ && !Threads.stop
+ && !(Limits.depth && mainThread && rootDepth / ONE_PLY > Limits.depth))
{
// Distribute search depths across the threads
if (idx)
rm.previousScore = rm.score;
// MultiPV loop. We perform a full root search for each PV line
- for (PVIdx = 0; PVIdx < multiPV && !Signals.stop; ++PVIdx)
+ for (PVIdx = 0; PVIdx < multiPV && !Threads.stop; ++PVIdx)
{
+ // Reset UCI info selDepth for each depth and each PV line
+ selDepth = 0;
+
// Reset aspiration window starting size
if (rootDepth >= 5 * ONE_PLY)
{
// If search has been stopped, we break immediately. Sorting and
// writing PV back to TT is safe because RootMoves is still
// valid, although it refers to the previous iteration.
- if (Signals.stop)
+ if (Threads.stop)
break;
// When failing high/low give some update (without cluttering
if (mainThread)
{
mainThread->failedLow = true;
- Signals.stopOnPonderhit = false;
+ Threads.stopOnPonderhit = false;
}
}
else if (bestValue >= beta)
if (!mainThread)
continue;
- if (Signals.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)
+ if (Threads.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
}
- if (!Signals.stop)
+ if (!Threads.stop)
completedDepth = rootDepth;
if (!mainThread)
if ( Limits.mate
&& bestValue >= VALUE_MATE_IN_MAX_PLY
&& VALUE_MATE - bestValue <= 2 * Limits.mate)
- Signals.stop = true;
+ Threads.stop = true;
// Do we have time for the next iteration? Can we stop searching now?
if (Limits.use_time_management())
{
- if (!Signals.stop && !Signals.stopOnPonderhit)
+ if (!Threads.stop && !Threads.stopOnPonderhit)
{
// Stop the search if only one legal move is available, or if all
// of the available time has been used, or if we matched an easyMove
// If we are allowed to ponder do not stop the search now but
// keep pondering until the GUI sends "ponderhit" or "stop".
if (Limits.ponder)
- Signals.stopOnPonderhit = true;
+ Threads.stopOnPonderhit = true;
else
- Signals.stop = true;
+ Threads.stop = true;
}
}
Depth extension, newDepth;
Value bestValue, value, ttValue, eval;
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
- bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets;
+ bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture;
Piece moved_piece;
int moveCount, quietCount;
ss->ply = (ss-1)->ply + 1;
// Check for the available remaining time
- if (thisThread->resetCalls.load(std::memory_order_relaxed))
- {
- thisThread->resetCalls = false;
-
- // At low node count increase the checking rate to about 0.1% of nodes
- // otherwise use a default value.
- thisThread->callsCnt = Limits.nodes ? std::min(4096, int(Limits.nodes / 1024))
- : 4096;
- }
-
- if (--thisThread->callsCnt <= 0)
- {
- for (Thread* th : Threads)
- th->resetCalls = true;
-
- check_time();
- }
+ if (thisThread == Threads.main())
+ static_cast<MainThread*>(thisThread)->check_time();
// Used to send selDepth info to GUI
- if (PvNode && thisThread->maxPly < ss->ply)
- thisThread->maxPly = ss->ply;
+ if (PvNode && thisThread->selDepth < ss->ply)
+ thisThread->selDepth = ss->ply;
if (!rootNode)
{
// Step 2. Check for aborted search and immediate draw
- if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
+ if (Threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
: DrawValue[pos.side_to_move()];
if (err != TB::ProbeState::FAIL)
{
- thisThread->tbHits++;
+ thisThread->tbHits.fetch_add(1, std::memory_order_relaxed);
int drawScore = TB::UseRule50 ? 1 : 0;
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
{
Value rbeta = std::min(beta + 200, VALUE_INFINITE);
- Depth rdepth = depth - 4 * ONE_PLY;
- assert(rdepth >= ONE_PLY);
assert(is_ok((ss-1)->currentMove));
MovePicker mp(pos, ttMove, rbeta - ss->staticEval);
ss->currentMove = move;
ss->history = &thisThread->counterMoveHistory[pos.moved_piece(move)][to_sq(move)];
+ assert(depth >= 5 * ONE_PLY);
pos.do_move(move, st);
- value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode, false);
+ value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, depth - 4 * ONE_PLY, !cutNode, false);
pos.undo_move(move);
if (value >= rbeta)
return value;
&& (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 3 * ONE_PLY;
skipQuiets = false;
+ ttCapture = false;
// Step 11. Loop through moves
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
continue;
}
+ if (move == ttMove && captureOrPromotion)
+ ttCapture = true;
+
// Update the current move (this must be done after singular extension search)
ss->currentMove = move;
ss->history = &thisThread->counterMoveHistory[moved_piece][to_sq(move)];
r -= r ? ONE_PLY : DEPTH_ZERO;
else
{
+ // Increase reduction if ttMove is a capture
+ if (ttCapture)
+ r += ONE_PLY;
+
// Increase reduction for cut nodes
if (cutNode)
r += 2 * ONE_PLY;
// Finished searching the move. If a stop occurred, the return value of
// the search cannot be trusted, and we return immediately without
// updating best move, PV and TT.
- if (Signals.stop.load(std::memory_order_relaxed))
+ if (Threads.stop.load(std::memory_order_relaxed))
return VALUE_ZERO;
if (rootNode)
if (moveCount == 1 || value > alpha)
{
rm.score = value;
+ rm.selDepth = thisThread->selDepth;
rm.pv.resize(1);
assert((ss+1)->pv);
// completed. But in this case bestValue is valid because we have fully
// searched our subtree, and we can anyhow save the result in TT.
/*
- if (Signals.stop)
+ if (Threads.stop)
return VALUE_DRAW;
*/
return best;
}
+} // namespace
// check_time() is used to print debug info and, more importantly, to detect
// when we are out of available time and thus stop the search.
- void check_time() {
+ void MainThread::check_time() {
+
+ if (--callsCnt > 0)
+ return;
+
+ // At low node count increase the checking rate to about 0.1% of nodes
+ // otherwise use a default value.
+ callsCnt = Limits.nodes ? std::min(4096, int(Limits.nodes / 1024)) : 4096;
static TimePoint lastInfoTime = now();
if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
|| (Limits.movetime && elapsed >= Limits.movetime)
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
- Signals.stop = true;
+ Threads.stop = true;
}
-} // namespace
-
/// UCI::pv() formats PV information according to the UCI protocol. UCI requires
/// that all (if any) unsearched PV lines are sent using a previous search score.
ss << "info"
<< " depth " << d / ONE_PLY
- << " seldepth " << pos.this_thread()->maxPly
+ << " seldepth " << rootMoves[i].selDepth
<< " multipv " << i + 1
<< " score " << UCI::value(v);