UCILoader 1.1.2
Small C++ library that allows user to connect to a chess engines via UCI protocol.
Loading...
Searching...
No Matches
EngineConnection.h
1#pragma once
2
3#include "ProcessWrapper.h"
4#include "Parser.h"
5#include "EngineEvent.h"
6#include "Logger.h"
7#include <mutex>
8#include <atomic>
9#include <unordered_map>
10#include <condition_variable>
11
12namespace UCILoader {
19 enum SearchStatusCode {
21 InitialisingSearch,
23 OnGoing,
25 Terminated,
27 TimedOut,
29 Stopped,
31 ResultReady
32 };
33
48 template<class Move>
49 struct SearchResult {
51 Move* bestMove;
54 };
55
65 template<class Move>
66 void destroySearchResultStruct(SearchResult<Move>& _search_result) {
67 if (_search_result.bestMove) {
68 delete _search_result.bestMove;
69 _search_result.bestMove = nullptr;
70 }
71
72 if (_search_result.ponderMove) {
73 delete _search_result.ponderMove;
74 _search_result.ponderMove = nullptr;
75 }
76 }
77
87 std::mutex statusLock;
88 SearchStatusCode status =InitialisingSearch;
89 std::condition_variable var;
90 public:
96 void set(SearchStatusCode code) {
97 std::unique_lock<std::mutex> guard(statusLock);
98 this->status = code;
99 var.notify_all();
100 }
101
111 SearchStatusCode swapIfOngoing(SearchStatusCode newStatus) {
112 std::unique_lock<std::mutex> guard(statusLock);
113
114 SearchStatusCode oldStatus = status;
115
116 if (status == OnGoing) {
117 status = newStatus;
118 }
119
120 return oldStatus;
121 }
122
128 SearchStatusCode get() {
129 std::unique_lock<std::mutex> guard(statusLock);
130 return status;
131 }
132
141 SearchStatusCode waitFor(const std::chrono::milliseconds& dur) {
142
143 std::unique_lock<std::mutex> guard(statusLock);
144
145
146 if (status != OnGoing)
147 return status;
148
149
150 var.wait_for(guard, dur);
151
152 if (status == OnGoing)
153 status = TimedOut;
154
155 return status;
156 }
157
164 const SearchStatusCode & operator= (const SearchStatusCode& value) {
165 set(value);
166 return value;
167 }
168
169 bool operator == (const SearchStatusCode& value) {
170 return value == get();
171 }
172
173 bool operator != (const SearchStatusCode& value) {
174 return value != get();
175 }
176 };
177
178 template <class Move> class EngineInstance;
179
198 template<class Move>
200 public:
204 class ResultNotReadyException : public std::exception {};
205 private:
206
208
209 std::mutex lock;
210 SearchResult<Move> result = { nullptr, nullptr };
211 SearchStatusWrapper status;
212
213
214 std::shared_ptr<ProcessWrapper> engine;
215
216 void receiveBestMoveSignal(const Move* bestMove, const Move* ponderMove);
217 SearchStatusCode getStatusNoLock();
218 public:
220
226 SearchConnection(std::shared_ptr<ProcessWrapper> engine) : engine(engine) {};
227
233 SearchStatusCode getStatus();
234
253 void stop();
261 void ponderhit();
276 void waitFor(const std::chrono::milliseconds& time);
283 void timeOutIfNotFinished();
284 };
285
286
287
288 template<class Move>
289 inline void SearchConnection<Move>::receiveBestMoveSignal(const Move* bestMove, const Move* ponderMove){
290 assert(bestMove != nullptr);
291 std::lock_guard<std::mutex> guard(lock);
292 status = ResultReady;
293
294 result.bestMove = new Move(*bestMove);
295 if (ponderMove) result.ponderMove = new Move(*ponderMove);
296 }
297
298 template<class Move>
299 inline SearchStatusCode SearchConnection<Move>::getStatusNoLock()
300 {
301 if (status == ResultReady || status == Terminated || status == TimedOut) // final statuses
302 return status.get();
303
304
305 if (!engine->healthCheck()) {
306 status = Terminated;
307 return status.get();
308 }
309
310 return status.get();
311 }
312
313 template<class Move>
314 inline SearchConnection<Move>::~SearchConnection()
315 {
316 destroySearchResultStruct(result);
317 }
318 template<class Move>
319 inline SearchStatusCode SearchConnection<Move>::getStatus()
320 {
321 std::lock_guard<std::mutex> guard(lock);
322 return getStatusNoLock();
323 }
324 template<class Move>
326 {
327 std::lock_guard<std::mutex> guard(lock);
328 if (status != ResultReady)
330
331 return result;
332 }
333 template<class Move>
335 {
336 std::lock_guard<std::mutex> guard(lock);
337 SearchStatusCode currentStatus = getStatusNoLock();
338 if (currentStatus == ResultReady || currentStatus == Terminated)
339 return;
340
341 status = Stopped;
342 engine->getWriter()->write("stop\n", 5);
343 }
344
345 template<class Move>
347 {
348 std::lock_guard<std::mutex> guard(lock);
349 SearchStatusCode currentStatus = getStatusNoLock();
350 if (currentStatus != OnGoing)
351 return;
352
353 engine->getWriter()->write("ponderhit\n", 10);
354 }
355
356 template<class Move>
357 inline void SearchConnection<Move>::waitFor(const std::chrono::milliseconds& time)
358 {
359 SearchStatusCode returnCode = status.waitFor(time);
360 }
361
362 template<class Move>
364 {
365 SearchStatusCode returnCode = status.swapIfOngoing(TimedOut);
366 }
367
385 std::shared_ptr<AbstractPipeWriter> writer;
386 Option value;
387
388 void tryWrite(const std::string& value);
389 void tryWrite(const char* text);
390 void assertType(const OptionType& type) const;
391 void validateSpinCandidate(const int32_t& value) const;
392 void validateComboCandidate(const std::string& value) const;
393 void parse(const std::string& s);
394
395 int32_t parseInteger(const std::string& value); // throws ParsingError
396
397 public:
403 class WrongTypeError : public std::exception {};
415 class NotSupportedValueException : public std::exception {};
421 class ParsingError : public std::exception {};
422
423 EngineOptionProxy() : value(), writer(nullptr) {};
424 EngineOptionProxy(const Option& option, std::shared_ptr<AbstractPipeWriter> pipeWriter) : value(option), writer(pipeWriter) {};
425 EngineOptionProxy(const EngineOptionProxy& other) : value(other.value), writer(other.writer) {};
426
432 inline OptionType type() const { return value.type(); };
433
439 inline const std::string& id() const { return value.id(); };
447 inline const Option& getAsOption() const { return value; };
448
454 void click();
455
468 const std::string& operator = (const std::string& value);
469
482 const char* operator = (const char* value);
483
495 const int32_t& operator= (const int32_t& number);
496
505 const bool& operator= (const bool& value);
506
513 operator bool();
514
521 operator int();
522
529 operator std::string();
530 };
531
541 public:
547 virtual void consume(const Option& o) = 0;
548 };
549
579 private:
580 using Map = std::unordered_map<std::string, EngineOptionProxy>;
581 std::shared_ptr<AbstractPipeWriter> writer;
582 Map proxies;
583
584 void consume(const Option& option) override {
585 proxies.insert({ option.id(), EngineOptionProxy(option, writer) });
586 }
587
588 public:
589 using map_iterator = Map::iterator;
590
591 class iterator {
592 private:
593 map_iterator _it;
594 public:
595 iterator(const map_iterator& val) {
596 _it = val;
597 };
598 bool operator != (const iterator& other) {
599 return _it != other._it;
600 }
601
602 bool operator ==(const iterator& other) {
603 return !(*this != other);
604 }
605
606 iterator & operator++() {
607 _it++;
608 return *this;
609 }
610 EngineOptionProxy& operator*() {
611 return _it->second;
612 }
613 const EngineOptionProxy& operator*() const {
614 return _it->second;
615 }
616 };
617
618 explicit EngineOptionsMap(const std::shared_ptr<AbstractPipeWriter>& writer)
619 : writer(writer) {
620 }
621
622 EngineOptionProxy& get(const std::string& id) {
623 return proxies.at(id);
624 }
625
626 const EngineOptionProxy& get(const std::string& id) const {
627 return proxies.at(id);
628 }
629
636 bool contains(const std::string& id) const {
637 return proxies.count(id);
638 }
639
645 iterator begin() { return iterator(proxies.begin()); }
646
652 iterator end() { return iterator(proxies.end()); }
653
661 EngineOptionProxy& operator[](const std::string & id) {
662 return get(id);
663 }
664
672 const EngineOptionProxy& operator[](const std::string & id) const {
673 return get(id);
674 }
675
676 };
677
722 template <class Move>
724
725 struct InstancePrivate {
726 std::shared_ptr<SearchConnection<Move>> currentConnection = nullptr;
727 std::shared_ptr<ProcessWrapper> processWrapper;
728 std::unique_ptr<Logger> logger;
729 bool receivedReadyOk = false;
730 std::atomic_bool quitCommandSend;
731 std::string name = "<empty>";
732 std::string author = "<empty>";
733 std::condition_variable conditional_var;
734 EngineInstance<Move> * instance;
735 std::mutex lock;
736
737 InstancePrivate(std::shared_ptr<ProcessWrapper> engineProcess, std::shared_ptr<Marschaler<Move>> moveMarshaler, std::shared_ptr<PatternMatcher> moveValidator, std::unique_ptr<Logger> && logger, EngineInstance<Move>* instance);
738 void sendToEngine(const std::string& msg);
739 void logFromEngine(const std::string & msg);
740 void tryReportEngineCrash();
741 void emit(const EngineEvent* event);
742 };
743
744 std::shared_ptr<InstancePrivate> core;
745 void detachInstance();
746 public:
747
748 class _CommandHandler : public AbstractEngineHandler<Move> {
749 std::shared_ptr<InstancePrivate> core;
750 public:
751 _CommandHandler(std::shared_ptr<InstancePrivate> core) : core(core) {};
752 void onEngineName(const std::string& name) override;
753 void onEngineAuthor(const std::string& author) override;
754 void onUCIOK() override;
755 void onReadyOK() override;
756 void onBestMove(const Move& bestMove) override;
757 void onBestMove(const Move& bestMove, const Move& ponderMove) override;
758 void onInfo(const std::vector<Info<Move>>& infos) override;
759 void onCopyProtection(ProcedureStatus status) override;
760 void onRegistration(ProcedureStatus status) override;
761 void onOption(const Option& option) override;
762 void onError(const std::string& errorMsg) override;
763 };
764
765 EngineInstance(std::shared_ptr<ProcessWrapper> engineProcess, std::shared_ptr<Marschaler<Move>> moveMarshaler, std::shared_ptr<PatternMatcher> moveValidator, std::unique_ptr<Logger> && logger) :
766 options(engineProcess->getWriter())
767 {
768 core = std::make_shared<InstancePrivate>(engineProcess, moveMarshaler, moveValidator, std::move(logger), this);
769 std::shared_ptr<AbstractEngineHandler<Move>> handler = std::static_pointer_cast<AbstractEngineHandler<Move>>(std::make_shared<EngineInstance<Move>::_CommandHandler>(core));
770 auto parser = std::make_shared<UCIParser<Move>>(handler, moveMarshaler, moveValidator);
771 auto corePtr = core;
772 engineProcess->listen([parser, corePtr](std::string line) {
773 corePtr->logFromEngine(line);
774 parser->parseLine(line);
775 },
776 [corePtr](){corePtr->tryReportEngineCrash();});
777 core->sendToEngine("uci\n");
778 };
779
781 quit();
782 detachInstance();
783 }
784
791 class TimeoutException : public std::exception {};
792
799 class EngineBusyException : public std::exception{};
800
807
824 void sync(std::chrono::milliseconds timeout = std::chrono::milliseconds(10000));
825
832 void ucinewgame();
833
843 std::chrono::milliseconds ping(std::chrono::milliseconds timeout = std::chrono::milliseconds(10000));
849 std::shared_ptr<SearchConnection<Move>> getCurrentSearch();
850
881 std::shared_ptr<SearchConnection<Move>> search(const GoParams<Move>& params, const PositionFormatter& pos,
882 const std::vector<Move> moves = {});
883
893 std::string getName();
894
904 std::string getAuthor();
905
914 bool healthCheck();
915
931 void quit();
932 };
933
934 template <class Move>
935 inline EngineInstance<Move>::InstancePrivate::InstancePrivate(std::shared_ptr<ProcessWrapper> engineProcess, std::shared_ptr<Marschaler<Move>> moveMarshaler, std::shared_ptr<PatternMatcher> moveValidator, std::unique_ptr<Logger> &&logger, UCILoader::EngineInstance<Move> * instance) :
936 processWrapper(engineProcess), logger(std::move(logger)), quitCommandSend(false), instance(instance) {
937 }
938
939 template <class Move>
940 inline void EngineInstance<Move>::InstancePrivate::sendToEngine(const std::string &msg)
941 {
942 processWrapper->getWriter()->write(msg.c_str(), msg.size());
943 logger->log(Logger::ToEngine, msg);
944 }
945
946 template <class Move>
947 inline void EngineInstance<Move>::InstancePrivate::logFromEngine(const std::string &msg){
948 logger->log(UCILoader::Logger::FromEngine, msg + "\n");
949 }
950
951 template <class Move>
952 inline void EngineInstance<Move>::detachInstance()
953 {
954 std::unique_lock<std::mutex> guard(core->lock);
955 core->instance = nullptr;
956 }
957
958 template <class Move>
959 inline void EngineInstance<Move>::sync(std::chrono::milliseconds timeout)
960 {
961 std::unique_lock<std::mutex> guard(core->lock);
962 core->receivedReadyOk = false;
963
964 try {
965 core->sendToEngine("isready\n");
966 }
967 catch (PipeClosedException e) {
968 throw TimeoutException();
969 }
970
971 core->conditional_var.wait_for(guard, timeout);
972 if (!core->receivedReadyOk) {
973 core->processWrapper->kill();
974 throw TimeoutException();
975 }
976
977 auto e = NamedEngineEvents::makeSynchronizedEvent();
978 emit(&e);
979 }
980 template<class Move>
981 inline std::chrono::milliseconds EngineInstance<Move>::ping(std::chrono::milliseconds timeout)
982 {
983 auto start = std::chrono::steady_clock::now();
984 sync(timeout);
985 return std::chrono::milliseconds((std::chrono::steady_clock::now() - start).count()/1000000);
986 }
987
988 template<class Move>
989 inline std::shared_ptr<SearchConnection<Move>> EngineInstance<Move>::getCurrentSearch()
990 {
991 std::unique_lock<std::mutex> guard(core->lock);
992 return core->currentConnection;
993 }
994 template<class Move>
995 inline std::shared_ptr<SearchConnection<Move>> EngineInstance<Move>::search(const GoParams<Move>& params, const PositionFormatter& pos,
996 const std::vector<Move> moves)
997 {
998 std::unique_lock<std::mutex> guard(core->lock);
999
1000 if (core->currentConnection != nullptr)
1001 throw EngineBusyException();
1002
1003 core->currentConnection = std::make_shared<SearchConnection<Move>>(core->processWrapper);
1004
1005 core->sendToEngine(UciFormatter<Move>::position(pos, moves));
1006 core->sendToEngine(UciFormatter<Move>::go(params));
1007 core->currentConnection->status.set(OnGoing);
1008
1009 auto event = NamedEngineEvents::makeSearchStartedEvent();
1010 emit(&event);
1011 return core->currentConnection;
1012 }
1013 template<class Move>
1015 {
1016 std::unique_lock<std::mutex> guard(core->lock);
1017 return core->name;
1018 }
1019
1020 template<class Move>
1022 {
1023 std::unique_lock<std::mutex> guard(core->lock);
1024 return core->author;
1025 }
1026
1027 template<class Move>
1029 {
1030 std::unique_lock<std::mutex> guard(core->lock);
1031
1032 if (core->quitCommandSend)
1033 return;
1034
1035 core->quitCommandSend = true;
1036 try {
1037 core->sendToEngine("quit\n");
1038 }
1039 catch (PipeClosedException ignored) {
1040 // If we got here, the engine process in in unstable state, but since we are already killing it, we can ignore it.
1041 };
1042
1043
1044 int counter = 0;
1045
1046 while (core->processWrapper->healthCheck()) {
1047
1048 if (counter == 10) {
1049 core->processWrapper->kill();
1050 break;
1051 }
1052 std::this_thread::sleep_for(std::chrono::milliseconds(100));
1053 ++counter;
1054 };
1055 }
1056
1057 template<class Move>
1059 if (quitCommandSend == false) {
1060 auto event = NamedEngineEvents::makeEngineCrashedEvent();
1061 emit(&event);
1062 };
1063 }
1064
1065 template <class Move>
1066 inline void EngineInstance<Move>::InstancePrivate::emit(const EngineEvent *event) {
1067 if(instance)
1068 instance->emit(event);
1069 };
1070
1071 template<class Move>
1073 return core->processWrapper->healthCheck();
1074 }
1075
1076 template<class Move>
1078 core->sendToEngine("ucinewgame\n");
1079 }
1080
1081 template<class Move>
1082 inline void EngineInstance<Move>::_CommandHandler::onEngineName(const std::string& name)
1083 {
1084 std::unique_lock<std::mutex> guard(core->lock);
1085 core->name = name;
1086 }
1087
1088 template<class Move>
1089 inline void EngineInstance<Move>::_CommandHandler::onEngineAuthor(const std::string& author)
1090 {
1091 std::unique_lock<std::mutex> guard(core->lock);
1092 core->author = author;
1093 }
1094
1095 template<class Move>
1096 inline void EngineInstance<Move>::_CommandHandler::onUCIOK()
1097 {
1098 // TODO: do something
1099 }
1100
1101 template<class Move>
1102 inline void EngineInstance<Move>::_CommandHandler::onReadyOK()
1103 {
1104 std::unique_lock<std::mutex> guard(core->lock);
1105 core->receivedReadyOk = true;
1106 core->conditional_var.notify_all();
1107 }
1108
1109 template<class Move>
1110 inline void EngineInstance<Move>::_CommandHandler::onBestMove(const Move& bestMove)
1111 {
1112 std::unique_lock<std::mutex> guard(core->lock);
1113 static auto searchCompletedEvent = NamedEngineEvents::makeSearchCompletedEvent();
1114
1115 if (core->currentConnection != nullptr) {
1116 core->currentConnection->receiveBestMoveSignal(&bestMove, nullptr);
1117 core->currentConnection = nullptr;
1118 core->emit(&searchCompletedEvent);
1119 }
1120 }
1121
1122 template<class Move>
1123 inline void EngineInstance<Move>::_CommandHandler::onBestMove(const Move& bestMove, const Move& ponderMove)
1124 {
1125 std::unique_lock<std::mutex> guard(core->lock);
1126 static auto searchCompletedEvent = NamedEngineEvents::makeSearchCompletedEvent();
1127 if (core->currentConnection != nullptr) {
1128 core->currentConnection->receiveBestMoveSignal(&bestMove, &ponderMove);
1129 core->currentConnection = nullptr;
1130 core->emit(&searchCompletedEvent);
1131 }
1132 }
1133
1134 template<class Move>
1135 inline void EngineInstance<Move>::_CommandHandler::onInfo(const std::vector<Info<Move>>& infos)
1136 {
1137 std::unique_lock<std::mutex>guard(core->lock);
1138
1139 auto clampEvent = UCILoader::NamedEngineEvents::makeInfoClampEvent<Move>(infos);
1140 core->emit(&clampEvent);
1141 for (auto& info : infos) {
1142 auto infoEvent = UCILoader::NamedEngineEvents::makeInfoEvent<Move>(info);
1143 core->emit(&infoEvent);
1144 }
1145 }
1146
1147 template<class Move>
1148 inline void EngineInstance<Move>::_CommandHandler::onCopyProtection(ProcedureStatus status)
1149 {
1150 }
1151
1152 template<class Move>
1153 inline void EngineInstance<Move>::_CommandHandler::onRegistration(ProcedureStatus status)
1154 {
1155 }
1156
1157 template<class Move>
1158 inline void EngineInstance<Move>::_CommandHandler::onOption(const Option& option)
1159 {
1160 std::unique_lock<std::mutex> guard(core->lock);
1161 if (core->instance){
1162 IOptionConsumer* consumer = (IOptionConsumer*)(&core->instance->options);
1163 consumer->consume(option);
1164 };
1165
1166 }
1167
1168 template<class Move>
1169 inline void EngineInstance<Move>::_CommandHandler::onError(const std::string& errorMsg)
1170 {
1171 core->logger->log(Logger::FromParser, errorMsg + "\n");
1172 }
1173
1210 template <class Move>
1212 std::shared_ptr<PatternMatcher> moveValidator;
1213 std::shared_ptr<Marschaler<Move>> moveMarshaler;
1214 public:
1221 EngineInstanceBuilder(std::shared_ptr<PatternMatcher> validator, std::shared_ptr<Marschaler<Move>> marschaler) :
1222 moveValidator(validator), moveMarshaler(marschaler) {};
1223
1239 EngineInstance<Move>* build(ProcessWrapper* engineProcess);
1240
1268 EngineInstance<Move>* build(ProcessWrapper* engineProcess, LoggerBuilder logger);
1269 };
1270
1271 template<class Move>
1273 return build(engineProcess, Loggers::toNoting());
1274 };
1275
1276 template<class Move>
1278 {
1279 std::shared_ptr<ProcessWrapper> proces(engineProcess);
1280 return new EngineInstance<Move>(proces, moveMarshaler, moveValidator, std::move(logger.build()));
1281 }
1282
1283}
Base class for events emitted by an EngineInstance.
Definition: EngineEvent.h:42
Factory builder for creating EngineInstance objects.
Definition: EngineConnection.h:1211
EngineInstanceBuilder(std::shared_ptr< PatternMatcher > validator, std::shared_ptr< Marschaler< Move > > marschaler)
Constructor for the builder.
Definition: EngineConnection.h:1221
EngineInstance< Move > * build(ProcessWrapper *engineProcess)
Build an EngineInstance with default logging (no-op logger).
Definition: EngineConnection.h:1272
Exception thrown when attempting to start a search while one is already in progress.
Definition: EngineConnection.h:799
Exception thrown when a sync() or ping() operation times out.
Definition: EngineConnection.h:791
Top-level interface for managing and interacting with a UCI chess engine.
Definition: EngineConnection.h:723
std::string getName()
Get the engine's name as declared via the id name command.
Definition: EngineConnection.h:1014
bool healthCheck()
Check the health status of the underlying engine process.
Definition: EngineConnection.h:1072
std::shared_ptr< SearchConnection< Move > > getCurrentSearch()
Get the currently active search connection.
Definition: EngineConnection.h:989
void ucinewgame()
Send the ucinewgame command to the engine.
Definition: EngineConnection.h:1077
void sync(std::chrono::milliseconds timeout=std::chrono::milliseconds(10000))
Synchronize engine state with local representation.
Definition: EngineConnection.h:959
std::chrono::milliseconds ping(std::chrono::milliseconds timeout=std::chrono::milliseconds(10000))
Measure engine latency by performing a ping operation.
Definition: EngineConnection.h:981
void quit()
Manually terminate the engine process.
Definition: EngineConnection.h:1028
std::string getAuthor()
Get the engine author's name as declared via the id author command.
Definition: EngineConnection.h:1021
std::shared_ptr< SearchConnection< Move > > search(const GoParams< Move > &params, const PositionFormatter &pos, const std::vector< Move > moves={})
Start a new search operation with specified parameters.
Definition: EngineConnection.h:995
EngineOptionsMap options
Map of available engine options.
Definition: EngineConnection.h:806
Exception thrown when setting an option to an unsupported value.
Definition: EngineConnection.h:415
Exception thrown when parsing fails for a miscellaneus reason.
Definition: EngineConnection.h:421
Exception thrown when an operation is incompatible with the option type.
Definition: EngineConnection.h:403
Proxy object for interacting with a UCI engine option.
Definition: EngineConnection.h:384
OptionType type() const
Get the option type.
Definition: EngineConnection.h:432
const Option & getAsOption() const
Get the full Option object with all metadata.
Definition: EngineConnection.h:447
const std::string & operator=(const std::string &value)
Set option value from a string.
Definition: EngineConnection.cpp:94
void click()
Activate a button option.
Definition: EngineConnection.cpp:88
const std::string & id() const
Get the option name.
Definition: EngineConnection.h:439
Container and iterator for engine option proxies.
Definition: EngineConnection.h:578
bool contains(const std::string &id) const
Check if the engine has an option with the specified name.
Definition: EngineConnection.h:636
const EngineOptionProxy & operator[](const std::string &id) const
Access option by name using bracket notation (const version).
Definition: EngineConnection.h:672
iterator end()
Get iterator to one past the last option.
Definition: EngineConnection.h:652
EngineOptionProxy & operator[](const std::string &id)
Access option by name using bracket notation.
Definition: EngineConnection.h:661
iterator begin()
Get iterator to the first option.
Definition: EngineConnection.h:645
Base class for objects that emit engine events.
Definition: EngineEvent.h:494
Internal interface for consuming option updates from the engine.
Definition: EngineConnection.h:540
virtual void consume(const Option &o)=0
Process a newly discovered engine option.
Builder class for constructing and composing loggers with traits.
Definition: Logger.h:158
std::unique_ptr< Logger > build()
Build and return the final logger instance.
Definition: Logger.cpp:227
@ ToEngine
Message sent from the application to the chess engine.
Definition: Logger.h:38
@ FromParser
Message generated or parsed by the UCI parser.
Definition: Logger.h:40
@ FromEngine
Message received from the chess engine.
Definition: Logger.h:39
Definition: Parser.h:34
Exception thrown when a pipe operation fails due to pipe closure.
Definition: AbstractPipe.h:21
Definition: UCI.h:363
Cross-platform wrapper for managing a chess engine process.
Definition: ProcessWrapper.h:88
Exception thrown when attempting to retrieve results before search completes.
Definition: EngineConnection.h:204
Manages and controls an ongoing chess engine search operation.
Definition: EngineConnection.h:199
void ponderhit()
Send a ponderhit command to the engine.
Definition: EngineConnection.h:346
SearchConnection(std::shared_ptr< ProcessWrapper > engine)
Constructor for SearchConnection.
Definition: EngineConnection.h:226
void stop()
Send a stop command to halt the engine's search.
Definition: EngineConnection.h:334
void waitFor(const std::chrono::milliseconds &time)
Block until the search completes or timeout expires.
Definition: EngineConnection.h:357
const SearchResult< Move > & getResult()
Retrieve the search result.
Definition: EngineConnection.h:325
SearchStatusCode getStatus()
Get the current status of the search operation.
Definition: EngineConnection.h:319
void timeOutIfNotFinished()
Set status to TimedOut if search is still ongoing.
Definition: EngineConnection.h:363
Thread-safe wrapper for managing SearchStatusCode state.
Definition: EngineConnection.h:86
void set(SearchStatusCode code)
Set the search status to the specified code.
Definition: EngineConnection.h:96
const SearchStatusCode & operator=(const SearchStatusCode &value)
Assignment operator for convenient status setting.
Definition: EngineConnection.h:164
SearchStatusCode waitFor(const std::chrono::milliseconds &dur)
Block until the search status changes or timeout expires.
Definition: EngineConnection.h:141
SearchStatusCode get()
Get the current search status.
Definition: EngineConnection.h:128
SearchStatusCode swapIfOngoing(SearchStatusCode newStatus)
Atomically swap status if current status is OnGoing.
Definition: EngineConnection.h:111
LoggerBuilder toNoting()
Create a logger that discards all messages.
Definition: Logger.cpp:171
Container for the result of a chess engine search operation.
Definition: EngineConnection.h:49
Move * ponderMove
[Optional] Move the engine wishes to ponder on, or nullptr if not provided by the engine
Definition: EngineConnection.h:53
Move * bestMove
The best move chosen by the engine for the given position.
Definition: EngineConnection.h:51