BenBot 1.7.5
A chess engine
Loading...
Searching...
No Matches
Perft.hpp
Go to the documentation of this file.
1/*
2 * ======================================================================================
3 *
4 * ░▒▓███████▓▒░░▒▓████████▓▒░▒▓███████▓▒░ ░▒▓███████▓▒░ ░▒▓██████▓▒░▒▓████████▓▒░
5 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
6 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
7 * ░▒▓███████▓▒░░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
8 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
9 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
10 * ░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓███████▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░
11 *
12 * ======================================================================================
13 */
14
19
20#pragma once
21
22#include <cstddef> // IWYU pragma: keep - for size_t;
26#include <utility>
27#include <vector>
28
29namespace chess::moves {
30
31using std::size_t;
32
38struct [[nodiscard]] PerftResult final {
40 size_t nodes { 0uz };
41
43 size_t captures { 0uz };
44
46 size_t enPassantCaptures { 0uz };
47
49 size_t castles { 0uz };
50
52 size_t promotions { 0uz };
53
55 size_t checks { 0uz };
56
58 size_t checkmates { 0uz };
59
61 size_t stalemates { 0uz };
62
64 using RootNodeInfo = std::pair<moves::Move, size_t>;
65
70 std::vector<RootNodeInfo> rootNodes;
71
73 constexpr auto operator+=(const PerftResult& rhs) noexcept -> PerftResult&;
74};
75
81template <bool IsRoot = true>
82[[nodiscard]] auto perft(
83 size_t depth,
84 const game::Position& startingPosition)
85 -> PerftResult;
86
87/*
88 ___ ,--,
89 ,---, ,--.'|_ ,--, ,--.'|
90 ,---.'| | | :,' ,--.'| | | :
91 | | : : : ' : | |, : : ' .--.--.
92 | | | ,---. .;__,' / ,--.--. `--'_ | ' | / / '
93 ,--.__| | / \ | | | / \ ,' ,'| ' | | | : /`./
94 / ,' | / / |:__,'| : .--. .-. | ' | | | | : | : ;_
95. ' / |. ' / | ' : |__ \__\/: . . | | : ' : |__ \ \ `.
96' ; |: |' ; /| | | '.'| ," .--.; | ' : |__ | | '.'| `----. \
97| | '/ '' | / | ; : ;/ / ,. | | | '.'|; : ;/ /`--' /__ ___ ___
98| : :|| : | | , /; : .' \; : ;| , /'--'. / .\/ .\/ .\
99 \ \ / \ \ / ---`-' | , .-./| , / ---`-' `--'---'\ ; \ ; \ ; |
100 `----' `----' `--`---' ---`-' `--" `--" `--"
101
102 */
103
104constexpr auto PerftResult::operator+=(const PerftResult& rhs) noexcept -> PerftResult&
105{
106 nodes += rhs.nodes;
107 captures += rhs.captures;
108 enPassantCaptures += rhs.enPassantCaptures;
109 castles += rhs.castles;
110 promotions += rhs.promotions;
111 checks += rhs.checks;
112 checkmates += rhs.checkmates;
113 stalemates += rhs.stalemates;
114
115 return *this;
116}
117
118template <bool IsRoot>
119auto perft( // NOLINT(readability-function-cognitive-complexity)
120 const size_t depth,
121 const game::Position& startingPosition)
122 -> PerftResult
123{
124 if (depth == 0uz)
125 return {
126 .nodes = 1uz,
127 .captures = 0uz,
128 .enPassantCaptures = 0uz,
129 .castles = 0uz,
130 .promotions = 0uz,
131 .checks = 0uz,
132 .checkmates = 0uz,
133 .stalemates = 0uz,
134 .rootNodes = { }
135 };
136
137 PerftResult result;
138
139 for (const auto move : generate(startingPosition)) {
140 const auto newPosition = after_move(startingPosition, move);
141
142 // we want stats only for leaf nodes
143 if (depth == 1uz) {
144 if (startingPosition.is_capture(move)) {
145 ++result.captures;
146
147 if (startingPosition.is_en_passant(move))
148 ++result.enPassantCaptures;
149 }
150
151 if (move.is_castling())
152 ++result.castles;
153
154 if (move.is_promotion())
155 ++result.promotions;
156
157 const bool isCheck = newPosition.is_check();
158
159 if (isCheck)
160 ++result.checks;
161
162 if (not any_legal_moves(newPosition)) {
163 if (isCheck)
164 ++result.checkmates;
165 else
166 ++result.stalemates;
167 }
168 }
169
170 const auto childResult = perft<false>(depth - 1uz, newPosition);
171
172 if constexpr (IsRoot) {
173 result.rootNodes.emplace_back(move, childResult.nodes);
174 }
175
176 result += childResult;
177 }
178
179 return result;
180}
181
182} // namespace chess::moves
auto perft(const size_t depth, const game::Position &startingPosition) -> PerftResult
Definition Perft.hpp:119
auto any_legal_moves(const Position &position) -> bool
Definition MoveGen.hpp:777
void generate(const Position &position, std::output_iterator< Move > auto outputIt)
Definition MoveGen.hpp:734
std::vector< RootNodeInfo > rootNodes
Definition Perft.hpp:70
std::pair< moves::Move, size_t > RootNodeInfo
Definition Perft.hpp:64
constexpr auto operator+=(const PerftResult &rhs) noexcept -> PerftResult &
Definition Perft.hpp:104