From: Marco Costalba Date: Tue, 15 Aug 2017 08:05:22 +0000 (-0700) Subject: Restore perft X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=45e254a0a0d4cbc574e5a65bd4584036b01091b6 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. --- diff --git a/src/benchmark.cpp b/src/benchmark.cpp index c1c74f7b..c9a5933d 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -86,11 +86,16 @@ const vector 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 setup_bench(const Position& current , istream& is) { diff --git a/src/search.cpp b/src/search.cpp index 7b3fd18b..6bd84226 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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 + 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(pos)) + { + if (Root && depth <= ONE_PLY) + cnt = 1, nodes++; + else + { + pos.do_move(m, st); + cnt = leaf ? MoveList(pos).size() : perft(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 -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(pos)) - { - if (Root && depth <= ONE_PLY) - cnt = 1, nodes++; - else - { - pos.do_move(m, st); - cnt = leaf ? MoveList(pos).size() : perft(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(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(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(); diff --git a/src/search.h b/src/search.h index bbdbdfd9..2e08b550 100644 --- a/src/search.h +++ b/src/search.h @@ -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 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 uint64_t perft(Position& pos, Depth depth); } // namespace Search diff --git a/src/uci.cpp b/src/uci.cpp index cf54497d..4a7a9456 100644 --- a/src/uci.cpp +++ b/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 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; diff --git a/tests/perft.sh b/tests/perft.sh index f3d5b88b..d4022211 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -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