diff --git a/src/Makefile b/src/Makefile
index 9680ca7f..907b6155 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -63,7 +63,7 @@ HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h \
nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h nnue/nnue_architecture.h \
nnue/nnue_common.h nnue/nnue_feature_transformer.h position.h \
search.h syzygy/tbprobe.h thread.h thread_win32_osx.h timeman.h \
- tt.h tune.h types.h uci.h ucioption.h
+ tt.h tune.h types.h uci.h ucioption.h perft.h
OBJS = $(notdir $(SRCS:.cpp=.o))
diff --git a/src/perft.h b/src/perft.h
new file mode 100644
index 00000000..2edc3ad0
--- /dev/null
+++ b/src/perft.h
@@ -0,0 +1,69 @@
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef PERFT_H_INCLUDED
+#define PERFT_H_INCLUDED
+
+#include
+
+#include "movegen.h"
+#include "position.h"
+#include "types.h"
+#include "uci.h"
+
+namespace Stockfish {
+
+// 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;
+ ASSERT_ALIGNED(&st, Eval::NNUE::CacheLineSize);
+
+ uint64_t cnt, nodes = 0;
+ const bool leaf = (depth == 2);
+
+ for (const auto& m : MoveList(pos))
+ {
+ if (Root && depth <= 1)
+ cnt = 1, nodes++;
+ else
+ {
+ pos.do_move(m, st);
+ cnt = leaf ? MoveList(pos).size() : perft(pos, depth - 1);
+ nodes += cnt;
+ pos.undo_move(m);
+ }
+ if (Root)
+ sync_cout << UCI::move(m, pos.is_chess960()) << ": " << cnt << sync_endl;
+ }
+ return nodes;
+}
+
+inline void perft(const std::string& fen, Depth depth, bool isChess960) {
+ StateListPtr states(new std::deque(1));
+ Position p;
+ p.set(fen, isChess960, &states->back());
+
+ uint64_t nodes = perft(p, depth);
+ sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
+}
+}
+
+#endif // PERFT_H_INCLUDED
diff --git a/src/search.cpp b/src/search.cpp
index f4b37253..086bff34 100644
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -122,37 +122,8 @@ void update_all_stats(const Position& pos,
int captureCount,
Depth depth);
-// 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;
- ASSERT_ALIGNED(&st, Eval::NNUE::CacheLineSize);
-
- uint64_t cnt, nodes = 0;
- const bool leaf = (depth == 2);
-
- for (const auto& m : MoveList(pos))
- {
- if (Root && depth <= 1)
- cnt = 1, nodes++;
- else
- {
- pos.do_move(m, st);
- cnt = leaf ? MoveList(pos).size() : perft(pos, depth - 1);
- nodes += cnt;
- pos.undo_move(m);
- }
- if (Root)
- sync_cout << UCI::move(m, pos.is_chess960()) << ": " << cnt << sync_endl;
- }
- return nodes;
-}
-
} // namespace
-
Search::Worker::Worker(SharedState& sharedState,
std::unique_ptr sm,
size_t thread_id) :
@@ -173,13 +144,6 @@ void Search::Worker::start_searching() {
return;
}
- if (limits.perft)
- {
- nodes = perft(rootPos, limits.perft);
- sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
- return;
- }
-
main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options);
tt.new_search();
diff --git a/src/uci.cpp b/src/uci.cpp
index 2a55fbfa..e6107d47 100644
--- a/src/uci.cpp
+++ b/src/uci.cpp
@@ -39,6 +39,7 @@
#include "syzygy/tbprobe.h"
#include "types.h"
#include "ucioption.h"
+#include "perft.h"
namespace Stockfish {
@@ -172,7 +173,6 @@ void UCI::loop() {
void UCI::go(Position& pos, std::istringstream& is, StateListPtr& states) {
-
Search::LimitsType limits;
std::string token;
bool ponderMode = false;
@@ -211,6 +211,12 @@ void UCI::go(Position& pos, std::istringstream& is, StateListPtr& states) {
Eval::NNUE::verify(options, evalFiles);
+ if (limits.perft)
+ {
+ perft(pos.fen(), limits.perft, options["UCI_Chess960"]);
+ return;
+ }
+
threads.start_thinking(options, pos, states, limits, ponderMode);
}