#include "evaluate.h"
#include "history.h"
#include "misc.h"
-#include "move.h"
#include "movegen.h"
#include "movepick.h"
#include "search.h"
#include "tt.h"
#include "ucioption.h"
-using std::cout;
-using std::endl;
-using std::string;
-using Search::Signals;
-using Search::Limits;
-
namespace Search {
volatile SignalsType Signals;
LimitsType Limits;
std::vector<Move> RootMoves;
- Position* RootPosition;
+ Position RootPosition;
}
+using std::cout;
+using std::endl;
+using std::string;
+using namespace Search;
+
namespace {
// Set to true to force running with one thread. Used for debugging
Move id_loop(Position& pos, Move rootMoves[], Move* ponderMove);
template <NodeType NT>
- Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth);
+ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
template <NodeType NT>
- Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth);
+ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta, Value *bValue);
bool connected_moves(const Position& pos, Move m1, Move m2);
void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount);
void do_skill_level(Move* best, Move* ponder);
- int elapsed_search_time(int set = 0);
+ int elapsed_time(bool reset = false);
string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
string speed_to_uci(int64_t nodes);
string pv_to_uci(const Move pv[], int pvNum, bool chess960);
// we simply create and use a standard MovePicker object.
template<bool SpNode> struct MovePickerExt : public MovePicker {
- MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
+ MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, Stack* ss, Value b)
: MovePicker(p, ttm, d, h, ss, b) {}
};
// In case of a SpNode we use split point's shared MovePicker object as moves source
template<> struct MovePickerExt<true> : public MovePicker {
- MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
+ MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, Stack* ss, Value b)
: MovePicker(p, ttm, d, h, ss, b), mp(ss->sp->mp) {}
Move get_next_move() { return mp->get_next_move(); }
}
-/// think() is the external interface to Stockfish's search, and is called when
-/// the program receives the UCI 'go' command. It initializes various global
-/// variables, and calls id_loop(). It returns false when a "quit" command is
-/// received during the search.
+/// think() is the external interface to Stockfish's search, and is called by the
+/// main thread when the program receives the UCI 'go' command. It searches from
+/// RootPosition and at the end prints the "bestmove" to output.
void Search::think() {
static Book book; // Defined static to initialize the PRNG only once
- Position& pos = *RootPosition;
+ Position& pos = RootPosition;
- // Save "search start" time and reset elapsed time to zero
- elapsed_search_time(get_system_time());
+ // Reset elapsed search time
+ elapsed_time(true);
// Set output stream mode: normal or chess960. Castling notation is different
cout << set960(pos.is_chess960());
// Write current search final statistics to log file
if (Options["Use Search Log"].value<bool>())
{
- int e = elapsed_search_time();
+ int e = elapsed_time();
Log log(Options["Search Log Filename"].value<string>());
log << "Nodes: " << pos.nodes_searched()
Move id_loop(Position& pos, Move rootMoves[], Move* ponderMove) {
- SearchStack ss[PLY_MAX_PLUS_2];
+ Stack ss[PLY_MAX_PLUS_2];
Value bestValues[PLY_MAX_PLUS_2];
int bestMoveChanges[PLY_MAX_PLUS_2];
int depth, aspirationDelta;
bool bestMoveNeverChanged = true;
// Initialize stuff before a new search
- memset(ss, 0, 4 * sizeof(SearchStack));
+ memset(ss, 0, 4 * sizeof(Stack));
TT.new_search();
H.clear();
*ponderMove = bestMove = skillBest = skillPonder = MOVE_NONE;
// if we have a fail high/low and we are deep in the search. UCI
// protocol requires to send all the PV lines also if are still
// to be searched and so refer to the previous search's score.
- if ((bestValue > alpha && bestValue < beta) || elapsed_search_time() > 2000)
+ if ((bestValue > alpha && bestValue < beta) || elapsed_time() > 2000)
for (int i = 0; i < std::min(UCIMultiPV, (int)Rml.size()); i++)
{
bool updated = (i <= MultiPVIdx);
if (Options["Use Search Log"].value<bool>())
{
Log log(Options["Search Log Filename"].value<string>());
- log << pretty_pv(pos, depth, bestValue, elapsed_search_time(), &Rml[0].pv[0]) << endl;
+ log << pretty_pv(pos, depth, bestValue, elapsed_time(), &Rml[0].pv[0]) << endl;
}
// Filter out startup noise when monitoring best move stability
// 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 (elapsed_search_time() > (TimeMgr.available_time() * 62) / 100)
+ if (elapsed_time() > (TimeMgr.available_time() * 62) / 100)
stop = true;
// Stop search early if one move seems to be much better than others
if ( depth >= 10
&& !stop
&& ( bestMoveNeverChanged
- || elapsed_search_time() > (TimeMgr.available_time() * 40) / 100))
+ || elapsed_time() > (TimeMgr.available_time() * 40) / 100))
{
Value rBeta = bestValue - EasyMoveMargin;
(ss+1)->excludedMove = bestMove;
{
// If we are allowed to ponder do not stop the search now but
// keep pondering until GUI sends "ponderhit" or "stop".
- if (Limits.ponder) // FIXME racing
+ if (Limits.ponder)
Signals.stopOnPonderhit = true;
else
Signals.stop = true;
// here: This is taken care of after we return from the split point.
template <NodeType NT>
- Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) {
+ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
const bool PvNode = (NT == PV || NT == Root || NT == SplitPointPV || NT == SplitPointRoot);
const bool SpNode = (NT == SplitPointPV || NT == SplitPointNonPV || NT == SplitPointRoot);
nodes = pos.nodes_searched();
// For long searches send current move info to GUI
- if (pos.thread() == 0 && elapsed_search_time() > 2000)
+ if (pos.thread() == 0 && elapsed_time() > 2000)
cout << "info" << depth_to_uci(depth)
<< " currmove " << move
<< " currmovenumber " << moveCount + MultiPVIdx << endl;
// less than ONE_PLY).
template <NodeType NT>
- Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) {
+ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
const bool PvNode = (NT == PV);
// current_search_time() returns the number of milliseconds which have passed
// since the beginning of the current search.
- int elapsed_search_time(int set) {
+ int elapsed_time(bool reset) {
static int searchStartTime;
- if (set)
- searchStartTime = set;
+ if (reset)
+ searchStartTime = get_system_time();
return get_system_time() - searchStartTime;
}
string speed_to_uci(int64_t nodes) {
std::stringstream s;
- int t = elapsed_search_time();
+ int t = elapsed_time();
s << " nodes " << nodes
<< " nps " << (t > 0 ? int(nodes * 1000 / t) : 0)
assert(!do_terminate);
// Copy split point position and search stack and call search()
- SearchStack ss[PLY_MAX_PLUS_2];
+ Stack ss[PLY_MAX_PLUS_2];
SplitPoint* tsp = splitPoint;
Position pos(*tsp->pos, threadID);
- memcpy(ss, tsp->ss - 1, 4 * sizeof(SearchStack));
+ memcpy(ss, tsp->ss - 1, 4 * sizeof(Stack));
(ss+1)->sp = tsp;
if (tsp->nodeType == Root)
void do_timer_event() {
static int lastInfoTime;
- int e = elapsed_search_time();
+ int e = elapsed_time();
// Print debug information every one second
if (!lastInfoTime || get_system_time() - lastInfoTime >= 1000)