void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus);
+ // perft() is our utility to verify move generation. All the leaf nodes up
+ // to the given depth are generated and counted, and the sum is returned.
+ template<bool Root>
+ uint64_t perft(Position& pos, Depth depth) {
+
+ StateInfo st;
+ uint64_t cnt, nodes = 0;
+ const bool leaf = (depth == 2 * ONE_PLY);
+
+ for (const auto& m : MoveList<LEGAL>(pos))
+ {
+ if (Root && depth <= ONE_PLY)
+ cnt = 1, nodes++;
+ else
+ {
+ pos.do_move(m, st);
+ cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY);
+ nodes += cnt;
+ pos.undo_move(m);
+ }
+ if (Root)
+ sync_cout << UCI::move(m, pos.is_chess960()) << ": " << cnt << sync_endl;
+ }
+ return nodes;
+ }
+
} // namespace
}
-/// Search::clear() resets search state to its initial value, to obtain reproducible results
+/// Search::clear() resets search state to its initial value
void Search::clear() {
+ Threads.main()->wait_for_search_finished();
+
+ Time.availableNodes = 0;
TT.clear();
for (Thread* th : Threads)
}
-/// Search::perft() is our utility to verify move generation. All the leaf nodes
-/// up to the given depth are generated and counted, and the sum is returned.
-template<bool Root>
-uint64_t Search::perft(Position& pos, Depth depth) {
-
- StateInfo st;
- uint64_t cnt, nodes = 0;
- const bool leaf = (depth == 2 * ONE_PLY);
-
- for (const auto& m : MoveList<LEGAL>(pos))
- {
- if (Root && depth <= ONE_PLY)
- cnt = 1, nodes++;
- else
- {
- pos.do_move(m, st);
- cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY);
- nodes += cnt;
- pos.undo_move(m);
- }
- if (Root)
- sync_cout << UCI::move(m, pos.is_chess960()) << ": " << cnt << sync_endl;
- }
- return nodes;
-}
-
-template uint64_t Search::perft<true>(Position&, Depth);
-
-
/// MainThread::search() is called by the main thread when the program receives
/// the UCI 'go' command. It searches from the root position and outputs the "bestmove".
void MainThread::search() {
+ if (Limits.perft)
+ {
+ nodes = perft<true>(rootPos, Limits.perft * ONE_PLY);
+ sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
+ return;
+ }
+
Color us = rootPos.side_to_move();
Time.init(Limits, us, rootPos.game_ply());
TT.new_search();
if (rootMoves.empty())
{
- rootMoves.push_back(RootMove(MOVE_NONE));
+ rootMoves.emplace_back(MOVE_NONE);
sync_cout << "info depth 0 score "
<< UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
<< sync_endl;
// 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 Threads.stop).
- if (!Threads.stop && (Limits.ponder || Limits.infinite))
- {
- Threads.stopOnPonderhit = true;
- wait(Threads.stop);
- }
+ Threads.stopOnPonderhit = true;
+
+ while (!Threads.stop && (Threads.ponder || Limits.infinite))
+ {} // Busy wait for a stop or a ponder reset
- // Stop the threads if not already stopped
+ // Stop the threads if not already stopped (also raise the stop if
+ // "ponderhit" just reset Threads.ponder).
Threads.stop = true;
// Wait until all threads have finished
bestValue = delta = alpha = -VALUE_INFINITE;
beta = VALUE_INFINITE;
- completedDepth = DEPTH_ZERO;
if (mainThread)
{
{
// 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)
+ if (Threads.ponder)
Threads.stopOnPonderhit = true;
else
Threads.stop = true;
Value bestValue, value, ttValue, eval;
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture;
- Piece moved_piece;
+ Piece movedPiece;
int moveCount, quietCount;
// Step 1. Initialize node
extension = DEPTH_ZERO;
captureOrPromotion = pos.capture_or_promotion(move);
- moved_piece = pos.moved_piece(move);
+ movedPiece = pos.moved_piece(move);
givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates()
? pos.check_squares(type_of(pos.piece_on(from_sq(move)))) & to_sq(move)
// Countermoves based pruning
if ( lmrDepth < 3
- && (*contHist[0])[moved_piece][to_sq(move)] < CounterMovePruneThreshold
- && (*contHist[1])[moved_piece][to_sq(move)] < CounterMovePruneThreshold)
+ && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold
+ && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold)
continue;
// Futility pruning: parent node
// Update the current move (this must be done after singular extension search)
ss->currentMove = move;
- ss->contHistory = &thisThread->contHistory[moved_piece][to_sq(move)];
+ ss->contHistory = &thisThread->contHistory[movedPiece][to_sq(move)];
// Step 14. Make the move
pos.do_move(move, st, givesCheck);
r -= 2 * ONE_PLY;
ss->statScore = thisThread->mainHistory[~pos.side_to_move()][from_to(move)]
- + (*contHist[0])[moved_piece][to_sq(move)]
- + (*contHist[1])[moved_piece][to_sq(move)]
- + (*contHist[3])[moved_piece][to_sq(move)]
+ + (*contHist[0])[movedPiece][to_sq(move)]
+ + (*contHist[1])[movedPiece][to_sq(move)]
+ + (*contHist[3])[movedPiece][to_sq(move)]
- 4000;
// Decrease/increase reduction by comparing opponent's stat score
}
// An engine may not stop pondering until told so by the GUI
- if (Limits.ponder)
+ if (Threads.ponder)
return;
- if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
+ if ( (Limits.use_time_management() && elapsed > Time.maximum())
|| (Limits.movetime && elapsed >= Limits.movetime)
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
Threads.stop = true;