uint64_t nodes = 0;
TimePoint elapsed = now();
+ Position pos;
for (size_t i = 0; i < fens.size(); ++i)
{
- Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
+ StateListPtr states(new std::vector<StateInfo>(1));
+ pos.set(fens[i], Options["UCI_Chess960"], &states->back(), Threads.main());
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
else
{
- Search::StateStackPtr st;
limits.startTime = now();
- Threads.start_thinking(pos, limits, st);
+ Threads.start_thinking(pos, states, limits);
Threads.main()->wait_for_search_finished();
nodes += Threads.nodes_searched();
}
string fen = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";
- return Position(fen, false, nullptr).material_key();
+ StateInfo st;
+ return Position().set(fen, false, &st, nullptr).material_key();
}
} // namespace
}
-/// Position::operator=() creates a copy of 'pos' but detaching the state pointer
-/// from the source to be self-consistent and not depending on any external data.
-
-Position& Position::operator=(const Position& pos) {
-
- std::memcpy(this, &pos, sizeof(Position));
- std::memcpy(&startState, st, sizeof(StateInfo));
- st = &startState;
- nodes = 0;
-
- assert(pos_is_ok());
-
- return *this;
-}
-
-
-/// Position::clear() erases the position object to a pristine state, with an
-/// empty board, white to move, and no castling rights.
-
-void Position::clear() {
-
- std::memset(this, 0, sizeof(Position));
- startState.epSquare = SQ_NONE;
- st = &startState;
-
- for (int i = 0; i < PIECE_TYPE_NB; ++i)
- for (int j = 0; j < 16; ++j)
- pieceList[WHITE][i][j] = pieceList[BLACK][i][j] = SQ_NONE;
-}
-
-
/// Position::set() initializes the position object with the given FEN string.
/// This function is not very robust - make sure that input FENs are correct,
/// this is assumed to be the responsibility of the GUI.
-void Position::set(const string& fenStr, bool isChess960, Thread* th) {
+Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Thread* th) {
/*
A FEN string defines a particular position using only the ASCII character set.
Square sq = SQ_A8;
std::istringstream ss(fenStr);
- clear();
+ std::memset(this, 0, sizeof(Position));
+ std::memset(si, 0, sizeof(StateInfo));
+ std::fill_n(&pieceList[0][0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE);
+ st = si;
+
ss >> std::noskipws;
// 1. Piece placement
if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)))
st->epSquare = SQ_NONE;
}
+ else
+ st->epSquare = SQ_NONE;
// 5-6. Halfmove clock and fullmove number
ss >> std::skipws >> st->rule50 >> gamePly;
set_state(st);
assert(pos_is_ok());
+
+ return *this;
}
std::getline(ss, token); // Half and full moves
f += token;
- set(f, is_chess960(), this_thread());
+ set(f, is_chess960(), st, this_thread());
assert(pos_is_ok());
}
#include <cassert>
#include <cstddef> // For offsetof()
+#include <memory> // For std::unique_ptr
#include <string>
+#include <vector>
#include "bitboard.h"
#include "types.h"
StateInfo* previous;
};
+typedef std::unique_ptr<std::vector<StateInfo>> StateListPtr;
+
/// Position class stores information regarding the board representation as
/// pieces, side to move, hash keys, castling info, etc. Important methods are
public:
static void init();
- Position() = default; // To define the global object RootPos
+ Position() = default;
Position(const Position&) = delete;
- Position(const Position& pos, Thread* th) { *this = pos; thisThread = th; }
- Position(const std::string& f, bool c960, Thread* th) { set(f, c960, th); }
- Position& operator=(const Position&); // To assign RootPos from UCI
+ Position& operator=(const Position&) = delete;
// FEN string input/output
- void set(const std::string& fenStr, bool isChess960, Thread* th);
+ Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
const std::string fen() const;
// Position representation
private:
// Initialization helpers (used while setting up a position)
- void clear();
void set_castling_right(Color c, Square rfrom);
void set_state(StateInfo* si) const;
int castlingRightsMask[SQUARE_NB];
Square castlingRookSquare[CASTLING_RIGHT_NB];
Bitboard castlingPath[CASTLING_RIGHT_NB];
- StateInfo startState;
uint64_t nodes;
int gamePly;
Color sideToMove;
SignalsType Signals;
LimitsType Limits;
- StateStackPtr SetupStates;
}
namespace Tablebases {
}
for (Thread* th : Threads)
- {
- th->maxPly = 0;
- th->rootDepth = DEPTH_ZERO;
if (th != this)
- {
- th->rootPos = Position(rootPos, th);
- th->rootMoves = rootMoves;
th->start_searching();
- }
- }
Thread::search(); // Let's start searching!
}
Move Skill::pick_best(size_t multiPV) {
- const Search::RootMoveVector& rootMoves = Threads.main()->rootMoves;
+ const RootMoves& rootMoves = Threads.main()->rootMoves;
static PRNG rng(now()); // PRNG sequence should be non-deterministic
// RootMoves are already sorted by score in descending order
std::stringstream ss;
int elapsed = Time.elapsed() + 1;
- const Search::RootMoveVector& rootMoves = pos.this_thread()->rootMoves;
+ const RootMoves& rootMoves = pos.this_thread()->rootMoves;
size_t PVIdx = pos.this_thread()->PVIdx;
size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size());
uint64_t nodes_searched = Threads.nodes_searched();
#define SEARCH_H_INCLUDED
#include <atomic>
-#include <memory> // For std::unique_ptr
-#include <stack>
#include <vector>
#include "misc.h"
std::vector<Move> pv;
};
-typedef std::vector<RootMove> RootMoveVector;
+typedef std::vector<RootMove> RootMoves;
/// LimitsType struct stores information sent by GUI about available time to
/// search the current move, maximum depth/time, if we are in analysis mode or
struct LimitsType {
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
- nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movestogo =
- depth = movetime = mate = infinite = ponder = 0;
+ nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
+ npmsec = movestogo = depth = movetime = mate = infinite = ponder = 0;
}
bool use_time_management() const {
std::atomic_bool stop, stopOnPonderhit;
};
-typedef std::unique_ptr<std::stack<StateInfo>> StateStackPtr;
-
extern SignalsType Signals;
extern LimitsType Limits;
-extern StateStackPtr SetupStates;
void init();
void clear();
//
// A return value false indicates that not all probes were successful and that
// no moves were filtered out.
-bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Value& score)
+bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score)
{
int success;
//
// A return value false indicates that not all probes were successful and that
// no moves were filtered out.
-bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves, Value& score)
+bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score)
{
int success;
void init(const std::string& path);
int probe_wdl(Position& pos, int *success);
int probe_dtz(Position& pos, int *success);
-bool root_probe(Position& pos, Search::RootMoveVector& rootMoves, Value& score);
-bool root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves, Value& score);
+bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
+bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);
}
#include "thread.h"
#include "uci.h"
-using namespace Search;
-
ThreadPool Threads; // Global object
/// Thread constructor launches the thread and then waits until it goes to sleep
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
/// and starts a new search, then returns immediately.
-void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
- StateStackPtr& states) {
+void ThreadPool::start_thinking(const Position& pos, StateListPtr& states,
+ const Search::LimitsType& limits) {
main()->wait_for_search_finished();
- Signals.stopOnPonderhit = Signals.stop = false;
-
- main()->rootMoves.clear();
- main()->rootPos = pos;
- Limits = limits;
- if (states.get()) // If we don't set a new position, preserve current state
- {
- SetupStates = std::move(states); // Ownership transfer here
- assert(!states.get());
- }
+ Search::Signals.stopOnPonderhit = Search::Signals.stop = false;
+ Search::Limits = limits;
+ Search::RootMoves rootMoves;
for (const auto& m : MoveList<LEGAL>(pos))
if ( limits.searchmoves.empty()
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
- main()->rootMoves.push_back(RootMove(m));
+ rootMoves.push_back(Search::RootMove(m));
+
+ // After ownership transfer 'states' becomes empty, so if we stop the search
+ // and call 'go' again without setting a new position states.get() == NULL.
+ assert(states.get() || setupStates.get());
+
+ if (states.get())
+ setupStates = std::move(states); // Ownership transfer, states is now empty
+
+ for (Thread* th : Threads)
+ {
+ th->maxPly = 0;
+ th->rootDepth = DEPTH_ZERO;
+ th->rootMoves = rootMoves;
+ th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
+ }
main()->start_searching();
}
int maxPly, callsCnt;
Position rootPos;
- Search::RootMoveVector rootMoves;
+ Search::RootMoves rootMoves;
Depth rootDepth;
HistoryStats history;
MoveStats counterMoves;
void exit(); // be initialized and valid during the whole thread lifetime.
MainThread* main() { return static_cast<MainThread*>(at(0)); }
- void start_thinking(const Position&, const Search::LimitsType&, Search::StateStackPtr&);
+ void start_thinking(const Position&, StateListPtr&, const Search::LimitsType&);
void read_uci_options();
int64_t nodes_searched();
+
+private:
+ StateListPtr setupStates;
};
extern ThreadPool Threads;
enum TimeType { OptimumTime, MaxTime };
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
- const double MaxRatio = 7.09; // When in trouble, we can step over reserved time with this ratio
+ const double MaxRatio = 7.09; // When in trouble, we can step over reserved time with this ratio
const double StealRatio = 0.35; // However we must not steal time from remaining moves over this ratio
// FEN string of the initial position, normal chess
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
- // Stack to keep track of the position states along the setup moves (from the
+ // A list to keep track of the position states along the setup moves (from the
// start position to the position just before the search starts). Needed by
// 'draw by repetition' detection.
- Search::StateStackPtr SetupStates;
+ StateListPtr States(new std::vector<StateInfo>(1));
// position() is called when engine receives the "position" UCI command.
else
return;
- pos.set(fen, Options["UCI_Chess960"], Threads.main());
- SetupStates = Search::StateStackPtr(new std::stack<StateInfo>);
+ States = StateListPtr(new std::vector<StateInfo>(1));
+ pos.set(fen, Options["UCI_Chess960"], &States->back(), Threads.main());
// Parse move list (if any)
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
{
- SetupStates->push(StateInfo());
- pos.do_move(m, SetupStates->top(), pos.gives_check(m, CheckInfo(pos)));
+ States->push_back(StateInfo());
+ pos.do_move(m, States->back(), pos.gives_check(m, CheckInfo(pos)));
}
}
else if (token == "infinite") limits.infinite = 1;
else if (token == "ponder") limits.ponder = 1;
- Threads.start_thinking(pos, limits, SetupStates);
+ Threads.start_thinking(pos, States, limits);
}
} // namespace
void UCI::loop(int argc, char* argv[]) {
- Position pos(StartFEN, false, Threads.main()); // The root position
+ Position pos;
string token, cmd;
+ pos.set(StartFEN, false, &States->back(), Threads.main());
+
for (int i = 1; i < argc; ++i)
cmd += std::string(argv[i]) + " ";