BenBot 1.7.5
A chess engine
Loading...
Searching...
No Matches
EngineBase.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 <array>
23#include <atomic>
24#include <cassert>
25#include <functional>
28#include <span>
29#include <string>
30#include <string_view>
31#include <utility>
32
33namespace chess::game {
34struct Position;
35} // namespace chess::game
36
37namespace chess::uci {
38
39using game::Position;
40using std::string_view;
41
45struct EngineCommand final {
47 using Callback = std::function<void(string_view)>;
48
52 string_view name;
53
58
60 string_view description;
61
67 string_view argsHelp;
68
70 [[nodiscard]] static auto void_cb(std::function<void()>&& func) -> Callback
71 {
72 return [callback = std::move(func)]([[maybe_unused]] const string_view args) {
73 callback();
74 };
75 }
76};
77
91struct EngineBase {
92 EngineBase() = default;
93
94 virtual ~EngineBase();
95
96 EngineBase(const EngineBase&) = delete;
98 EngineBase& operator=(const EngineBase&) = delete;
100
105 [[nodiscard]] virtual auto get_name() const -> std::string = 0;
106
108 [[nodiscard]] virtual auto get_author() const -> string_view = 0;
109
114 virtual void wait() { }
115
119 [[nodiscard]] virtual auto is_searching() const noexcept -> bool = 0;
120
129 virtual void new_game([[maybe_unused]] bool firstCall) { }
130
132 virtual void abort_search() { }
133
138 virtual void ponder_hit() { }
139
141 virtual void set_position([[maybe_unused]] const Position& pos) { }
142
147 virtual void go([[maybe_unused]] const GoCommandOptions& opts) = 0;
148
155 void handle_command(string_view command);
156
163 void loop();
164
168 virtual void handle_registration([[maybe_unused]] const RegisterOptions& opts) { }
169
171 using CommandList = std::span<const EngineCommand>;
172
174 [[nodiscard]] auto get_standard_uci_commands() const noexcept -> CommandList
175 {
176 return standardUCICommands;
177 }
178
180 [[nodiscard]] virtual auto get_custom_uci_commands() const noexcept -> CommandList
181 {
182 return { };
183 }
184
186 using OptionList = std::span<Option*>;
187
189 [[nodiscard]] virtual auto get_custom_uci_options() noexcept -> OptionList
190 {
191 return { };
192 }
193
195 [[nodiscard]] auto get_standard_uci_options() noexcept -> OptionList
196 {
197 return standardUCIOptions;
198 }
199
201 [[nodiscard]] auto is_debug_mode() const noexcept -> bool
202 {
203 return debugMode.load(std::memory_order_relaxed);
204 }
205
207 void set_debug_mode(const bool shouldDebug) noexcept
208 {
209 debugMode.store(shouldDebug, std::memory_order_relaxed);
210 }
211
219 void set_sanitize_positions(const bool shouldSanitize) noexcept
220 {
221 sanitizeIncomingPositions.store(shouldSanitize, std::memory_order_release);
222 }
223
225 virtual void resize_transposition_table([[maybe_unused]] const size_t sizeMB) { }
226
228 virtual void set_ponder([[maybe_unused]] const bool shouldPonder) { }
229
232
235 "Hash",
236 1, 2048, 16,
237 "Sets the transposition table size (in MB)",
238 [this](const int sizeMB) {
239 assert(sizeMB >= 0);
240 resize_transposition_table(static_cast<size_t>(sizeMB));
241 }
242 };
243
251 "Ponder",
252 false,
253 "Controls whether pondering is allowed.",
254 [this](const bool shouldPonder) { set_ponder(shouldPonder); }
255 };
256
258
259private:
260 void respond_to_uci();
261 void respond_to_isready();
262 void respond_to_newgame();
263 void handle_quit();
264 void handle_setpos(string_view arguments);
265 void handle_setoption(string_view arguments);
266
267 static_assert(
268 std::atomic_bool::is_always_lock_free,
269 "Platform doesn't support lock-free atomic operations");
270
271 std::atomic_bool shouldExit { false }; // used as flag for exiting the loop() function
272 std::atomic_bool initialized { false };
273 std::atomic_bool debugMode { false };
274 std::atomic_bool sanitizeIncomingPositions { false };
275
276 Position position;
277
278 std::array<EngineCommand, 11uz> standardUCICommands {
279 EngineCommand {
280 .name = "uci",
281 .action = EngineCommand::void_cb([this] { respond_to_uci(); }),
282 .description = "Initialize UCI communication",
283 .argsHelp = { } },
284 EngineCommand {
285 .name = "isready",
286 .action = EngineCommand::void_cb([this] { respond_to_isready(); }),
287 .description = "Wait for engine to complete background tasks",
288 .argsHelp = { } },
289 EngineCommand {
290 .name = "ucinewgame",
291 .action = EngineCommand::void_cb([this] { respond_to_newgame(); }),
292 .description = "Initialize a new game",
293 .argsHelp = { } },
294 EngineCommand {
295 .name = "quit",
296 .action = EngineCommand::void_cb([this] { handle_quit(); }),
297 .description = "Exit the engine as quickly as possible",
298 .argsHelp = { } },
299 EngineCommand {
300 .name = "stop",
301 .action = EngineCommand::void_cb([this] { abort_search(); }),
302 .description = "Abort the current search, if any",
303 .argsHelp = { } },
304 EngineCommand {
305 .name = "ponderhit",
306 .action = EngineCommand::void_cb([this] { ponder_hit(); }),
307 .description = "Indicate that the user played the ponder move",
308 .argsHelp = { } },
309 EngineCommand {
310 .name = "position",
311 .action = [this](const string_view args) { handle_setpos(args); },
312 .description = "Set the position on the engine's internal board",
313 .argsHelp = "[startpos|fen <fen>] [moves <move...>]" },
314 EngineCommand {
315 .name = "go",
316 .action = [this](const string_view args) { go(parse_go_options(args, position)); },
317 .description = "Start a search",
318 .argsHelp = { } },
319 EngineCommand {
320 .name = "setoption",
321 .action = [this](const string_view args) { handle_setoption(args); },
322 .description = "Set UCI option values",
323 .argsHelp = "[name <name>] [value <value>]" },
324 EngineCommand {
325 .name = "debug",
326 .action = [this](const string_view args) noexcept { set_debug_mode(args == "on"); },
327 .description = "Enable/disable engine debug mode",
328 .argsHelp = "[on|off]" },
329 EngineCommand {
330 .name = "register",
331 .action = [this](const string_view args) {
333 },
334 .description = "Handle license registration",
335 .argsHelp = { } }
336 };
337
338 std::array<Option*, 2uz> standardUCIOptions {
340 };
341};
342
343} // namespace chess::uci
optional< RegisterNowOptions > RegisterOptions
auto parse_go_options(string_view options, const Position &currentPosition) -> GoCommandOptions
auto parse_register_options(string_view options) -> RegisterOptions
virtual void set_ponder(const bool shouldPonder)
virtual auto get_author() const -> string_view=0
virtual void handle_registration(const RegisterOptions &opts)
virtual void ponder_hit()
std::span< const EngineCommand > CommandList
virtual auto get_name() const -> std::string=0
std::span< Option * > OptionList
EngineBase(EngineBase &&)=delete
virtual void resize_transposition_table(const size_t sizeMB)
virtual void set_position(const Position &pos)
void handle_command(string_view command)
virtual void go(const GoCommandOptions &opts)=0
void set_sanitize_positions(const bool shouldSanitize) noexcept
virtual auto is_searching() const noexcept -> bool=0
virtual auto get_custom_uci_commands() const noexcept -> CommandList
EngineBase & operator=(EngineBase &&)=delete
virtual void new_game(bool firstCall)
auto get_standard_uci_commands() const noexcept -> CommandList
virtual void abort_search()
EngineBase & operator=(const EngineBase &)=delete
auto is_debug_mode() const noexcept -> bool
EngineBase(const EngineBase &)=delete
void set_debug_mode(const bool shouldDebug) noexcept
auto get_standard_uci_options() noexcept -> OptionList
virtual auto get_custom_uci_options() noexcept -> OptionList
std::function< void(string_view)> Callback
static auto void_cb(std::function< void()> &&func) -> Callback