mirror of
https://github.com/sockspls/badfish
synced 2025-04-29 16:23:09 +00:00
Restore perft
Rewrite perft to be placed naturally inside new bench code. In particular we don't have special custom code to run perft anymore but perft is just a new parameter of 'go' command. So user API is now changed, old style command: $perft 5 becomes $go perft 4 No functional change.
This commit is contained in:
parent
444d99b6d2
commit
45e254a0a0
5 changed files with 52 additions and 53 deletions
|
@ -86,11 +86,16 @@ const vector<string> Defaults = {
|
|||
} // namespace
|
||||
|
||||
/// setup_bench() builds a list of UCI commands to be run by bench. There
|
||||
/// are five parameters: TT size, number of search threads that should
|
||||
/// be used, the limit value spent for each position (optional, default is
|
||||
/// depth 13), an optional file name where to look for positions in FEN
|
||||
/// format (defaults are the positions defined above) and the type of the
|
||||
/// limit value: depth (default), time in millisecs or number of nodes.
|
||||
/// are five parameters: TT size in MB, number of search threads that
|
||||
/// should be used, the limit value spent for each position, a file name
|
||||
/// where to look for positions in FEN format and the type of the limit:
|
||||
/// depth, perft, nodes and movetime (in millisecs).
|
||||
///
|
||||
/// bench -> search default positions up to depth 13
|
||||
/// bench 64 1 15 -> search default positions up to depth 15 (TT = 64MB)
|
||||
/// bench 64 4 5000 current movetime -> search current position with 4 threads for 5 sec
|
||||
/// bench 64 1 100000 default nodes -> search default positions for 100K nodes each
|
||||
/// bench 16 1 5 default perft -> run a perft 5 on default positions
|
||||
|
||||
std::vector<string> setup_bench(const Position& current , istream& is) {
|
||||
|
||||
|
|
|
@ -154,6 +154,32 @@ namespace {
|
|||
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
|
||||
|
||||
|
||||
|
@ -209,40 +235,18 @@ void Search::clear() {
|
|||
}
|
||||
|
||||
|
||||
/// 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();
|
||||
|
|
|
@ -78,15 +78,16 @@ 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 = 0;
|
||||
npmsec = movestogo = depth = movetime = mate = perft = infinite = 0;
|
||||
}
|
||||
|
||||
bool use_time_management() const {
|
||||
return !(mate | movetime | depth | nodes | infinite);
|
||||
return !(mate | movetime | depth | nodes | perft | infinite);
|
||||
}
|
||||
|
||||
std::vector<Move> searchmoves;
|
||||
int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite;
|
||||
int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth,
|
||||
movetime, mate, perft, infinite;
|
||||
int64_t nodes;
|
||||
TimePoint startTime;
|
||||
};
|
||||
|
@ -95,7 +96,6 @@ extern LimitsType Limits;
|
|||
|
||||
void init();
|
||||
void clear();
|
||||
template<bool Root = true> uint64_t perft(Position& pos, Depth depth);
|
||||
|
||||
} // namespace Search
|
||||
|
||||
|
|
16
src/uci.cpp
16
src/uci.cpp
|
@ -128,6 +128,7 @@ namespace {
|
|||
else if (token == "nodes") is >> limits.nodes;
|
||||
else if (token == "movetime") is >> limits.movetime;
|
||||
else if (token == "mate") is >> limits.mate;
|
||||
else if (token == "perft") is >> limits.perft;
|
||||
else if (token == "infinite") limits.infinite = 1;
|
||||
else if (token == "ponder") ponderMode = true;
|
||||
|
||||
|
@ -137,7 +138,7 @@ namespace {
|
|||
|
||||
// bench() is called when engine receives the "bench" command. Firstly
|
||||
// a list of UCI commands is setup according to bench parameters, then
|
||||
// it is run one by one printing summaries at the end.
|
||||
// it is run one by one printing a summary at the end.
|
||||
|
||||
void bench(Position& pos, istream& args, StateListPtr& states) {
|
||||
|
||||
|
@ -145,7 +146,7 @@ namespace {
|
|||
uint64_t num, nodes = 0, cnt = 1;
|
||||
|
||||
vector<string> list = setup_bench(pos, args);
|
||||
num = count_if (list.begin(), list.end(), [](string s) { return s.find("go ") == 0; });
|
||||
num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0; });
|
||||
|
||||
TimePoint elapsed = now();
|
||||
|
||||
|
@ -235,17 +236,6 @@ void UCI::loop(int argc, char* argv[]) {
|
|||
else if (token == "bench") bench(pos, is, states);
|
||||
else if (token == "d") sync_cout << pos << sync_endl;
|
||||
else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl;
|
||||
else if (token == "perft")
|
||||
{
|
||||
int depth;
|
||||
stringstream ss;
|
||||
|
||||
is >> depth;
|
||||
ss << Options["Hash"] << " " << Options["Threads"]
|
||||
<< " " << depth << " current perft";
|
||||
|
||||
// TODO benchmark(pos, ss);
|
||||
}
|
||||
else
|
||||
sync_cout << "Unknown command: " << cmd << sync_endl;
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ cat << EOF > perft.exp
|
|||
set timeout 10
|
||||
lassign \$argv pos depth result
|
||||
spawn ./stockfish
|
||||
send "position \$pos\\n perft \$depth\\n"
|
||||
expect "Nodes searched ? \$result" {} timeout {exit 1}
|
||||
send "position \$pos\\ngo perft \$depth\\n"
|
||||
expect "Nodes searched? \$result" {} timeout {exit 1}
|
||||
send "quit\\n"
|
||||
expect eof
|
||||
EOF
|
||||
|
|
Loading…
Add table
Reference in a new issue