Depth PassedPawnExtension[2], PawnEndgameExtension[2], MateThreatExtension[2];
// Minimum depth for use of singular extension
- const Depth SingularExtensionDepth[2] = { 7 * OnePly /* non-PV */, 6 * OnePly /* PV */};
+ const Depth SingularExtensionDepth[2] = { 8 * OnePly /* non-PV */, 6 * OnePly /* PV */};
// If the TT move is at least SingularExtensionMargin better then the
// remaining ones we will extend it.
// Multi-threads related variables
Depth MinimumSplitDepth;
int MaxThreadsPerSplitPoint;
- ThreadsManager TM;
+ ThreadsManager ThreadsMgr;
// Node counters, used only by thread[0] but try to keep in different cache
// lines (64 bytes each) from the heavy multi-thread read accessed variables.
/// init_threads(), exit_threads() and nodes_searched() are helpers to
/// give accessibility to some TM methods from outside of current file.
-void init_threads() { TM.init_threads(); }
-void exit_threads() { TM.exit_threads(); }
-int64_t nodes_searched() { return TM.nodes_searched(); }
+void init_threads() { ThreadsMgr.init_threads(); }
+void exit_threads() { ThreadsMgr.exit_threads(); }
+int64_t nodes_searched() { return ThreadsMgr.nodes_searched(); }
/// init_search() is called during startup. It initializes various lookup tables
int perft(Position& pos, Depth depth)
{
+ MoveStack mlist[256];
StateInfo st;
- Move move;
+ Move m;
int sum = 0;
- MovePicker mp(pos, MOVE_NONE, depth, H);
+
+ // Generate all legal moves
+ MoveStack* last = generate_moves(pos, mlist);
// If we are at the last ply we don't need to do and undo
// the moves, just to count them.
- if (depth <= OnePly) // Replace with '<' to test also qsearch
- {
- while (mp.get_next_move()) sum++;
- return sum;
- }
+ if (depth <= OnePly)
+ return int(last - mlist);
// Loop through all legal moves
CheckInfo ci(pos);
- while ((move = mp.get_next_move()) != MOVE_NONE)
+ for (MoveStack* cur = mlist; cur != last; cur++)
{
- pos.do_move(move, st, ci, pos.move_is_check(move, ci));
+ m = cur->move;
+ pos.do_move(m, st, ci, pos.move_is_check(m, ci));
sum += perft(pos, depth - OnePly);
- pos.undo_move(move);
+ pos.undo_move(m);
}
return sum;
}
// Initialize global search variables
StopOnPonderhit = AbortSearch = Quit = AspirationFailLow = false;
NodesSincePoll = 0;
- TM.resetNodeCounters();
+ ThreadsMgr.resetNodeCounters();
SearchStartTime = get_system_time();
ExactMaxTime = maxTime;
MaxDepth = maxDepth;
// Set the number of active threads
int newActiveThreads = get_option_value_int("Threads");
- if (newActiveThreads != TM.active_threads())
+ if (newActiveThreads != ThreadsMgr.active_threads())
{
- TM.set_active_threads(newActiveThreads);
- init_eval(TM.active_threads());
+ ThreadsMgr.set_active_threads(newActiveThreads);
+ init_eval(ThreadsMgr.active_threads());
}
// Wake up sleeping threads
- TM.wake_sleeping_threads();
+ ThreadsMgr.wake_sleeping_threads();
// Set thinking time
int myTime = time[pos.side_to_move()];
int myIncrement = increment[pos.side_to_move()];
if (UseTimeManagement)
- TimeMgr.update(myTime, myIncrement, movesToGo, pos.startpos_ply_counter());
+ TimeMgr.init(myTime, myIncrement, movesToGo, pos.startpos_ply_counter());
// Set best NodesBetweenPolls interval to avoid lagging under
// heavy time pressure.
if (UseLogFile)
LogFile.close();
- TM.put_threads_to_sleep();
+ ThreadsMgr.put_threads_to_sleep();
return !Quit;
}
<< "\ninfo depth " << 1
<< " score " << value_to_uci(rml.get_move_score(0))
<< " time " << current_search_time()
- << " nodes " << TM.nodes_searched()
+ << " nodes " << ThreadsMgr.nodes_searched()
<< " nps " << nps()
<< " pv " << rml.get_move(0) << "\n";
stopSearch = true;
// Stop search early if one move seems to be much better than the others
- int64_t nodes = TM.nodes_searched();
+ int64_t nodes = ThreadsMgr.nodes_searched();
if ( Iteration >= 8
&& EasyMove == pv[0]
&& ( ( rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100
- && current_search_time() > TimeMgr.optimumSearchTime / 16)
+ && current_search_time() > TimeMgr.available_time() / 16)
||( rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100
- && current_search_time() > TimeMgr.optimumSearchTime / 32)))
+ && current_search_time() > TimeMgr.available_time() / 32)))
stopSearch = true;
// Add some extra time if the best move has changed during the last two iterations
if (Iteration > 5 && Iteration <= 50)
- TimeMgr.best_move_changes(BestMoveChangesByIteration[Iteration],
- BestMoveChangesByIteration[Iteration-1]);
+ TimeMgr.pv_unstability(BestMoveChangesByIteration[Iteration],
+ BestMoveChangesByIteration[Iteration-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
wait_for_stop_or_ponderhit();
else
// Print final search statistics
- cout << "info nodes " << TM.nodes_searched()
+ cout << "info nodes " << ThreadsMgr.nodes_searched()
<< " nps " << nps()
<< " time " << current_search_time() << endl;
if (dbg_show_hit_rate)
dbg_print_hit_rate(LogFile);
- LogFile << "\nNodes: " << TM.nodes_searched()
+ LogFile << "\nNodes: " << ThreadsMgr.nodes_searched()
<< "\nNodes/second: " << nps()
<< "\nBest move: " << move_to_san(p, pv[0]);
alpha = *alphaPtr;
beta = *betaPtr;
isCheck = pos.is_check();
+ depth = (Iteration - 2) * OnePly + InitialDepth;
// Step 1. Initialize node (polling is omitted at root)
ss->currentMove = ss->bestMove = MOVE_NONE;
FirstRootMove = (i == 0);
// Save the current node count before the move is searched
- nodes = TM.nodes_searched();
+ nodes = ThreadsMgr.nodes_searched();
// Reset beta cut-off counters
- TM.resetBetaCounters();
+ ThreadsMgr.resetBetaCounters();
// Pick the next root move, and print the move and the move number to
// the standard output.
captureOrPromotion = pos.move_is_capture_or_promotion(move);
// Step 11. Decide the new search depth
- depth = (Iteration - 2) * OnePly + InitialDepth;
ext = extension<PV>(pos, move, captureOrPromotion, moveIsCheck, false, false, &dangerous);
newDepth = depth + ext;
// Remember beta-cutoff and searched nodes counts for this move. The
// info is used to sort the root moves for the next iteration.
int64_t our, their;
- TM.get_beta_counters(pos.side_to_move(), our, their);
+ ThreadsMgr.get_beta_counters(pos.side_to_move(), our, their);
rml.set_beta_counters(i, our, their);
- rml.set_move_nodes(i, TM.nodes_searched() - nodes);
+ rml.set_move_nodes(i, ThreadsMgr.nodes_searched() - nodes);
assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE);
assert(value < beta);
<< " score " << value_to_uci(rml.get_move_score(j))
<< " depth " << (j <= i ? Iteration : Iteration - 1)
<< " time " << current_search_time()
- << " nodes " << TM.nodes_searched()
+ << " nodes " << ThreadsMgr.nodes_searched()
<< " nps " << nps()
<< " pv ";
assert(beta > alpha && beta <= VALUE_INFINITE);
assert(PvNode || alpha == beta - 1);
assert(ply > 0 && ply < PLY_MAX);
- assert(pos.thread() >= 0 && pos.thread() < TM.active_threads());
+ assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
Move movesSearched[256];
EvalInfo ei;
StateInfo st;
- const TTEntry *tte, *ttx;
+ const TTEntry *tte;
Key posKey;
Move ttMove, move, excludedMove, threatMove;
Depth ext, newDepth;
oldAlpha = alpha;
// Step 1. Initialize node and poll. Polling can abort search
- TM.incrementNodeCounter(threadID);
+ ThreadsMgr.incrementNodeCounter(threadID);
ss->currentMove = ss->bestMove = threatMove = MOVE_NONE;
(ss+2)->killers[0] = (ss+2)->killers[1] = (ss+2)->mateKiller = MOVE_NONE;
}
// Step 2. Check for aborted search and immediate draw
- if (AbortSearch || TM.thread_should_stop(threadID))
+ if (AbortSearch || ThreadsMgr.thread_should_stop(threadID))
return Value(0);
if (pos.is_draw() || ply >= PLY_MAX - 1)
// Expensive mate threat detection (only for PV nodes)
if (PvNode)
- mateThreat = pos.has_mate_threat(opposite_color(pos.side_to_move()));
+ mateThreat = pos.has_mate_threat();
// Initialize a MovePicker object for the current position
MovePicker mp = MovePicker(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
// Loop through all legal moves until no moves remain or a beta cutoff occurs
while ( bestValue < beta
&& (move = mp.get_next_move()) != MOVE_NONE
- && !TM.thread_should_stop(threadID))
+ && !ThreadsMgr.thread_should_stop(threadID))
{
assert(move_is_ok(move));
&& move == tte->move()
&& ext < OnePly)
{
- // Avoid to do an expensive singular extension search on nodes where
- // such search have already been done in the past, so assume the last
- // singular extension search result is still valid.
- if ( !PvNode
- && depth < SingularExtensionDepth[PvNode] + 5 * OnePly
- && (ttx = TT.retrieve(pos.get_exclusion_key())) != NULL)
- {
- if (is_upper_bound(ttx->type()))
- ext = OnePly;
-
- singularExtensionNode = false;
- }
-
Value ttValue = value_from_tt(tte->value(), ply);
- if (singularExtensionNode && abs(ttValue) < VALUE_KNOWN_WIN)
+ if (abs(ttValue) < VALUE_KNOWN_WIN)
{
Value b = ttValue - SingularExtensionMargin;
ss->excludedMove = move;
// Step 18. Check for split
if ( depth >= MinimumSplitDepth
- && TM.active_threads() > 1
+ && ThreadsMgr.active_threads() > 1
&& bestValue < beta
- && TM.available_thread_exists(threadID)
+ && ThreadsMgr.available_thread_exists(threadID)
&& !AbortSearch
- && !TM.thread_should_stop(threadID)
+ && !ThreadsMgr.thread_should_stop(threadID)
&& Iteration <= 99)
- TM.split<FakeSplit>(pos, ss, ply, &alpha, beta, &bestValue, depth,
- threatMove, mateThreat, &moveCount, &mp, PvNode);
+ ThreadsMgr.split<FakeSplit>(pos, ss, ply, &alpha, beta, &bestValue, depth,
+ threatMove, mateThreat, &moveCount, &mp, PvNode);
}
// Step 19. Check for mate and stalemate
// Step 20. Update tables
// If the search is not aborted, update the transposition table,
// history counters, and killer moves.
- if (AbortSearch || TM.thread_should_stop(threadID))
+ if (AbortSearch || ThreadsMgr.thread_should_stop(threadID))
return bestValue;
ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
// Update killers and history only for non capture moves that fails high
if (bestValue >= beta)
{
- TM.incrementBetaCounter(pos.side_to_move(), depth, threadID);
+ ThreadsMgr.incrementBetaCounter(pos.side_to_move(), depth, threadID);
if (!pos.move_is_capture_or_promotion(move))
{
update_history(pos, move, depth, movesSearched, moveCount);
assert(PvNode || alpha == beta - 1);
assert(depth <= 0);
assert(ply > 0 && ply < PLY_MAX);
- assert(pos.thread() >= 0 && pos.thread() < TM.active_threads());
+ assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
EvalInfo ei;
StateInfo st;
const TTEntry* tte;
Value oldAlpha = alpha;
- TM.incrementNodeCounter(pos.thread());
+ ThreadsMgr.incrementNodeCounter(pos.thread());
ss->bestMove = ss->currentMove = MOVE_NONE;
// Check for an instant draw or maximum ply reached
template <NodeType PvNode>
void sp_search(SplitPoint* sp, int threadID) {
- assert(threadID >= 0 && threadID < TM.active_threads());
- assert(TM.active_threads() > 1);
+ assert(threadID >= 0 && threadID < ThreadsMgr.active_threads());
+ assert(ThreadsMgr.active_threads() > 1);
StateInfo st;
Move move;
while ( sp->bestValue < sp->beta
&& (move = sp->mp->get_next_move()) != MOVE_NONE
- && !TM.thread_should_stop(threadID))
+ && !ThreadsMgr.thread_should_stop(threadID))
{
moveCount = ++sp->moveCount;
lock_release(&(sp->lock));
// Step 17. Check for new best move
lock_grab(&(sp->lock));
- if (value > sp->bestValue && !TM.thread_should_stop(threadID))
+ if (value > sp->bestValue && !ThreadsMgr.thread_should_stop(threadID))
{
sp->bestValue = value;
&& pos.type_of_piece_on(move_to(m)) != PAWN
&& pos.see_sign(m) >= 0)
{
- result += OnePly/2;
+ result += OnePly / 2;
*dangerous = true;
}
if ( m != MOVE_NULL
&& before != VALUE_NONE
&& after != VALUE_NONE
- && pos.captured_piece() == NO_PIECE_TYPE
+ && pos.captured_piece_type() == PIECE_TYPE_NONE
&& !move_is_special(m))
H.set_gain(pos.piece_on(move_to(m)), move_to(m), -(before + after));
}
int nps() {
int t = current_search_time();
- return (t > 0 ? int((TM.nodes_searched() * 1000) / t) : 0);
+ return (t > 0 ? int((ThreadsMgr.nodes_searched() * 1000) / t) : 0);
}
if (dbg_show_hit_rate)
dbg_print_hit_rate();
- cout << "info nodes " << TM.nodes_searched() << " nps " << nps()
+ cout << "info nodes " << ThreadsMgr.nodes_searched() << " nps " << nps()
<< " time " << t << endl;
}
&& !AspirationFailLow
&& t > TimeMgr.available_time();
- bool noMoreTime = t > TimeMgr.maximumSearchTime
+ bool noMoreTime = t > TimeMgr.maximum_time()
|| stillAtFirstMove;
if ( (Iteration >= 3 && UseTimeManagement && noMoreTime)
|| (ExactMaxTime && t >= ExactMaxTime)
- || (Iteration >= 3 && MaxNodes && TM.nodes_searched() >= MaxNodes))
+ || (Iteration >= 3 && MaxNodes && ThreadsMgr.nodes_searched() >= MaxNodes))
AbortSearch = true;
}
&& !AspirationFailLow
&& t > TimeMgr.available_time();
- bool noMoreTime = t > TimeMgr.maximumSearchTime
+ bool noMoreTime = t > TimeMgr.maximum_time()
|| stillAtFirstMove;
if (Iteration >= 3 && UseTimeManagement && (noMoreTime || StopOnPonderhit))
<< " score " << value_to_uci(value)
<< (value >= beta ? " lowerbound" : value <= alpha ? " upperbound" : "")
<< " time " << current_search_time()
- << " nodes " << TM.nodes_searched()
+ << " nodes " << ThreadsMgr.nodes_searched()
<< " nps " << nps()
<< " pv ";
value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT;
LogFile << pretty_pv(pos, current_search_time(), Iteration,
- TM.nodes_searched(), value, t, pv) << endl;
+ ThreadsMgr.nodes_searched(), value, t, pv) << endl;
}
}
void* init_thread(void *threadID) {
- TM.idle_loop(*(int*)threadID, NULL);
+ ThreadsMgr.idle_loop(*(int*)threadID, NULL);
return NULL;
}
DWORD WINAPI init_thread(LPVOID threadID) {
- TM.idle_loop(*(int*)threadID, NULL);
+ ThreadsMgr.idle_loop(*(int*)threadID, NULL);
return 0;
}