mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 08:43: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
|
} // namespace
|
||||||
|
|
||||||
/// setup_bench() builds a list of UCI commands to be run by bench. There
|
/// 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
|
/// are five parameters: TT size in MB, number of search threads that
|
||||||
/// be used, the limit value spent for each position (optional, default is
|
/// should be used, the limit value spent for each position, a file name
|
||||||
/// depth 13), an optional file name where to look for positions in FEN
|
/// where to look for positions in FEN format and the type of the limit:
|
||||||
/// format (defaults are the positions defined above) and the type of the
|
/// depth, perft, nodes and movetime (in millisecs).
|
||||||
/// limit value: depth (default), time in millisecs or number of nodes.
|
///
|
||||||
|
/// 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) {
|
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_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);
|
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
|
} // 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
|
/// 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".
|
/// the UCI 'go' command. It searches from the root position and outputs the "bestmove".
|
||||||
|
|
||||||
void MainThread::search() {
|
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();
|
Color us = rootPos.side_to_move();
|
||||||
Time.init(Limits, us, rootPos.game_ply());
|
Time.init(Limits, us, rootPos.game_ply());
|
||||||
TT.new_search();
|
TT.new_search();
|
||||||
|
|
|
@ -78,15 +78,16 @@ struct LimitsType {
|
||||||
|
|
||||||
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
|
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
|
||||||
nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
|
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 {
|
bool use_time_management() const {
|
||||||
return !(mate | movetime | depth | nodes | infinite);
|
return !(mate | movetime | depth | nodes | perft | infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Move> searchmoves;
|
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;
|
int64_t nodes;
|
||||||
TimePoint startTime;
|
TimePoint startTime;
|
||||||
};
|
};
|
||||||
|
@ -95,7 +96,6 @@ extern LimitsType Limits;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void clear();
|
void clear();
|
||||||
template<bool Root = true> uint64_t perft(Position& pos, Depth depth);
|
|
||||||
|
|
||||||
} // namespace Search
|
} // namespace Search
|
||||||
|
|
||||||
|
|
14
src/uci.cpp
14
src/uci.cpp
|
@ -128,6 +128,7 @@ namespace {
|
||||||
else if (token == "nodes") is >> limits.nodes;
|
else if (token == "nodes") is >> limits.nodes;
|
||||||
else if (token == "movetime") is >> limits.movetime;
|
else if (token == "movetime") is >> limits.movetime;
|
||||||
else if (token == "mate") is >> limits.mate;
|
else if (token == "mate") is >> limits.mate;
|
||||||
|
else if (token == "perft") is >> limits.perft;
|
||||||
else if (token == "infinite") limits.infinite = 1;
|
else if (token == "infinite") limits.infinite = 1;
|
||||||
else if (token == "ponder") ponderMode = true;
|
else if (token == "ponder") ponderMode = true;
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ namespace {
|
||||||
|
|
||||||
// bench() is called when engine receives the "bench" command. Firstly
|
// bench() is called when engine receives the "bench" command. Firstly
|
||||||
// a list of UCI commands is setup according to bench parameters, then
|
// 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) {
|
void bench(Position& pos, istream& args, StateListPtr& states) {
|
||||||
|
|
||||||
|
@ -235,17 +236,6 @@ void UCI::loop(int argc, char* argv[]) {
|
||||||
else if (token == "bench") bench(pos, is, states);
|
else if (token == "bench") bench(pos, is, states);
|
||||||
else if (token == "d") sync_cout << pos << sync_endl;
|
else if (token == "d") sync_cout << pos << sync_endl;
|
||||||
else if (token == "eval") sync_cout << Eval::trace(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
|
else
|
||||||
sync_cout << "Unknown command: " << cmd << sync_endl;
|
sync_cout << "Unknown command: " << cmd << sync_endl;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ cat << EOF > perft.exp
|
||||||
set timeout 10
|
set timeout 10
|
||||||
lassign \$argv pos depth result
|
lassign \$argv pos depth result
|
||||||
spawn ./stockfish
|
spawn ./stockfish
|
||||||
send "position \$pos\\n perft \$depth\\n"
|
send "position \$pos\\ngo perft \$depth\\n"
|
||||||
expect "Nodes searched? \$result" {} timeout {exit 1}
|
expect "Nodes searched? \$result" {} timeout {exit 1}
|
||||||
send "quit\\n"
|
send "quit\\n"
|
||||||
expect eof
|
expect eof
|
||||||
|
|
Loading…
Add table
Reference in a new issue