} // 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) {
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
}
-/// 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();
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;
};
void init();
void clear();
-template<bool Root = true> uint64_t perft(Position& pos, Depth depth);
} // namespace Search
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;
// 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) {
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();
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;
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