Belofte version 2.1.8
A promising chess program using the UCI or Winboard interface
belofte.cpp
Go to the documentation of this file.
1/**
2 * @file belofte.cpp
3 * @brief main entry point, user interface
4 * @copyright This program is distributed under the GNU GPL Version 2,
5 * June 1991 General Public License. See COPYING.md for more
6 * information. SPDX-License-Identifier: GPL-2.0-only
7 * Part of belofte - A Promising Chess Program
8 * @author Yves De Billoez
9 * @date 01/10/2004 initial version: 0.1
10 * @date 12/05/2020 start of version 2.0
11 * @date 23/07/2024 latest version: 2.1.8
12 */
13
14/**
15 * The main program
16 */
17
18#include "belofte.h"
19
20//-----------------------------------------------------------------------
21
22static void platform_ctor();
23static void platform_dtor();
24
25/**
26 * Main entry point
27 * @param argc The number of parameters
28 * @param argv The strings pointing to each parameter
29 */
30
31int main(int argc, char *argv[])
32{
33 // initialize appInstance and normalised name of application
34 App().setName(argv[0]);
35 App().setConfig("enginename", MYFULLNAME " (" MYOS "/" MYPLATFORM ")" );
36 App().setConfig("about", MYFULLNAME " by " MYAUTHOR " " DEVDATES ", " MYLICENSE);
37 App().setConfig("author", "by " MYAUTHOR " " DEVDATES ", " MYLICENSE);
38
40
41 // initialize speedy structures
42 // even if norandom selected, required for hash init
43 std::srand(static_cast<unsigned int> (std::time(nullptr)));
45
46 // initialize appInstance
47#if defined(BELOFTE_UCIMODE)
48 App().setMode("uci");
49#else
50 App();
51#endif
52
53 // during initialisation, no interactive commands are read
55
56 // initialize static structures taking time
58
59 // avoid crash by initialising (not in spec!)
60 Game()->newGame();
63
64 if (argc > 1) {
65 for (int i = 1; i < argc; i++) {
66 std::string arg = argv[i];
67 if (arg == "--help") {
68 /// @todo allow aliases on commands
69 AppEI()->execute("usage", argv[0]);
70 goto belofte_exit;
71 } else if (arg == "--version") {
72 /// @todo allow aliases on commands
73 AppEI()->execute("about", "");
74 goto belofte_exit;
75 } else if (arg == "-xboard") {
76 // Arena default parameter for belofte is -xboard instead of --xboard
77 AppEI()->execute("xboard", "");
78 } else if ((arg == "bench") || (arg == "--bench")) {
79 AppEI()->execute("bench", "");
80 goto belofte_exit;
81 } else if (arg.substr(0, 1) == "@") {
82 if (arg.length() > 1) {
83 AppEI()->execute("@", arg);
84 } else {
85 // space in between @ and filename
86 if (i + 1 >= argc) {
87 App().bout << "Use filename with @" << std::endl;
88 goto belofte_exit;
89 }
90 arg = argv[++i];
91 AppEI()->execute("@", arg);
92 }
93 } else if (arg.substr(0, 2) == "--") {
94 try {
95 /// @todo parse all next argument(s) before those preceeded by --
96 AppEI()->execute(arg.substr(2), "");
97 } catch (const quitCommandException&) {
98 goto belofte_exit;
99 } catch (const std::logic_error& e) {
100 std::cout << "Logic Error: " << e.what() << std::endl;
101 } catch (...) {
102 std::cout << "Error: Uncatched exception" << std::endl;
103 }
104 } else {
105 // no -- or @, so filename expected
106 AppEI()->execute("exec", arg);
107 }
108 }
109 }
110
111 // default operation, used passed file or look for .rc file
112 if (!App().m_reader.isFileAttached()) {
114 // execute belofte-version-x.rc if present
115 AppEI()->execute("exec", App().getName() + ".rc");
116 }
117
118 try {
119 App().m_reader.runner();
120 } catch (const std::logic_error& e) {
121 std::cout << "Logic Error: " << e.what() << std::endl;
122 } catch (...) {
123 std::cout << "Error: Uncatched exception" << std::endl;
124 }
125
126belofte_exit:
127 // during program exit, no interactive commands are read
129
130 // call some dtor's
131 bPiece_dtor();
133
134 return 0;
135}
136
137//-----------------------------------------------------------------------
138
141
142//-----------------------------------------------------------------------
143// global verbs valid in all cases
144
145void engineInterface::execute(std::string const& command, std::string const& params)
146{
147 if (command != "") {
148 if (engineInterface::m_engineCommands.find(command)
151 v->execute(params);
152 } else if (params != "") {
153 sendError("unknown command", command + " " + params);
154 } else {
155 sendError("unknown command", command);
156 }
157 }
158}
159
160void engineInterface::initCommand(std::vector<engineUserCommand *> cmds)
161{
162 for (size_t i = 0; i < cmds.size(); i++) {
163 if (engineInterface::m_engineCommands.find(cmds[i]->m_name)
165 // do not initialize twice
166 engineInterface::m_engineCommands[cmds[i]->m_name] = cmds[i];
167 }
168 }
169}
170
171void engineInterface::attachCommand(belofte::stringList const& sCommands,
172 bool const published)
173{
174 if (published) {
175 // TOFIX: if not published, add command to list anyway
176 for (size_t i = 0; i < sCommands.size(); i++) {
177 m_allowedCommands[sCommands[i]] = published;
178 }
179 }
180}
181
182//-----------------------------------------------------------------------
183
184#if defined(__GNUC__)
185#pragma GCC diagnostic push
186#pragma GCC diagnostic ignored "-Weffc++"
187#endif
188
190 : m_filename{""}
191{
192}
193
194#if defined(__GNUC__)
195#pragma GCC diagnostic pop
196#endif
197
203
205{
206 while (true) {
207 if (!isFileAttached()) AppEI()->sendPrompt();
208 try {
210 AppEI()->execute(cmd.m_command, cmd.m_args);
211 } catch (const quitCommandException&) {
212 // quit requested
213 break;
214 } catch (const noCommandException&) {
215 // skip comments and empty lines
216 } catch (...) { throw; // push other exceptions down
217 }
218 }
219}
220
221std::string commandReader::readLine()
222{
223 std::string line;
224
225 while (line.empty()) {
226 if (!isFileAttached()) {
227 if (!std::getline(std::cin, line)) throw noCommandException();
228 } else {
229 if (!std::getline(m_inputfile, line)) {
230 detach();
231 throw noCommandException();
232 }
233 }
234 if (!line.empty()) {
235 AppEI()->sendDebug(2, line);
236 if ((line[0] == '#')
237 || (line[0] == '=')
238 || (line[0] == ';')) line = "";
239 }
240 }
241
242 return line;
243}
244
246{
247 std::string line = readLine();
248
249 if (line == "__END__") {
250 detach();
251 throw noCommandException();
252 }
253 if (line.empty()) throw noCommandException();
254
255 cmdParam cmd;
256 std::stringstream ss(line);
257 std::getline(ss, cmd.m_command, ' ');
258 std::getline(ss, cmd.m_args);
259
260 /// @attention Bughouse moves use @ character as well
261 if ((cmd.m_command.substr(0,1) == "@") && (cmd.m_command.length() > 1)) {
262 // @file passed, move file to arg and truncate command
263 cmd.m_args = cmd.m_command.substr(1);
264 cmd.m_command = "@";
265 }
266
267 return cmd;
268}
269
270bool commandReader::attach(std::string const& ifile)
271{
272 m_filename = ifile;
273 m_inputfile.open(m_filename.c_str(), std::ios_base::in);
274 return isFileAttached();
275}
276
278{
279 if (m_filename == "") return false;
280 if (!m_inputfile) return false;
281 if (m_inputfile.eof()) detach();
282 return m_inputfile.is_open();
283}
284
286{
287 m_inputfile.close();
288 m_filename = "";
289}
290
291/** no interactive input, mainly during start and '@' execute
292 */
294{
295 if (isFileAttached()) return true;
296 return m_isBatch;
297}
298
300{
301 m_isBatch = true;
302}
303
305{
306 m_isBatch = false;
307}
308
309//-----------------------------------------------------------------------
310
311/** Common commands to all modes
312 */
313engineInterface::engineInterface(std::string const& n, std::string const& h)
314 : m_name{n}
315 , m_hint{h}
316 , m_allowedCommands{}
317{
318 initCommand({new cmd_about(), new cmd_accepted(), new cmd_again(),
319 new cmd_alg(), new cmd_bd(), new cmd_belofte(), new cmd_black(),
320 new cmd_bench(), new cmd_computer(),
321 new cmd_debug(), new cmd_dot(), new cmd_easy(),
322 new cmd_echo(), new cmd_epd(), new cmd_epdpos(), new cmd_eval(),
323 new cmd_evaltype(), new cmd_exec(), new cmd_execat(), new cmd_exit(),
324 new cmd_expect(), new cmd_export(), new cmd_fd(),
325 new cmd_force(), new cmd_game(),
326 new cmd_go(), new cmd_hard(), new cmd_help(), new cmd_info(),
327 new cmd_playother(), new cmd_isready(), new cmd_level(), new cmd_ls(),
328 new cmd_new(), new cmd_nopost(),
329 new cmd_option(), new cmd_otim(), new cmd_perft(),
330 new cmd_ping(), new cmd_ponderhit(), new cmd_position(),
331 new cmd_post(), new cmd_protover(),
332 new cmd_questionmark(), new cmd_quit(), new cmd_rejected(),
333 new cmd_random(), new cmd_remove(),
334 new cmd_result(), new cmd_save(), new cmd_sd(), new cmd_st(),
335 new cmd_setboard(), new cmd_setoption(), new cmd_stop(),
336 new cmd_time(), new cmd_uci(), new cmd_ucinewgame(), new cmd_undo(),
337 new cmd_usage(), new cmd_usermove(), new cmd_white(),
338 new cmd_UCI_Opponent(), new cmd_name(),
340 new cmd_xboard()});
341}
342
344{
345 m_allowedCommands.clear();
346 engineCommands_t::iterator itr = engineInterface::m_engineCommands.begin();
347 while (itr != engineInterface::m_engineCommands.end()) {
348 delete itr->second;
349 itr = engineInterface::m_engineCommands.erase(itr);
350 }
352}
353
354//-----------------------------------------------------------------------
355
357 : engineInterface("belofte", "Swith to xboard or UCI protocol")
358{
359 attachCommand({"usage", "version", "exec", "ls"}, false);
360 attachCommand({"about", "xboard", "uci", "help", "bench", "perft"});
361}
362
366
367UCIMode::UCIMode(std::string const& n)
368 : engineInterface(n)
369{
370 attachCommand({"belofte"}, false);
371 attachCommand({"uci", "setoption", "isready", "position", "go",
372 "stop", "ucinewgame", "ponderhit"});
373}
374
378
379XboardMode::XboardMode(std::string const& n)
380 : engineInterface(n, "No xboard prompt")
381{
382 attachCommand({"accepted", "belofte", "black", "option", "otim", "ping",
383 "time", "rejected", "white"}, false);
384 attachCommand({"bd", "undo", "new", "setboard", "usermove", "game",
385 "remove", "force", "level", "post", "nopost", "random",
386 "easy", "hard", "go", "?", "result", "sd", "st", "protover"});
387}
388
392
393//-----------------------------------------------------------------------
394
396 : bout{std::cout}
397 , sout{std::cout}
398 , m_reader{}
399 , m_hashEngine{}
400 , m_debuginterface{}
401 , m_ui{nullptr}
402 , m_game{new bGame()}
403 , m_settings{{}}
404 , m_stringsettings{{}}
405 , m_engineInterfaces{{}}
406 , m_interfaceName{""}
407{
408 m_engineInterfaces["belofte"] = new BelofteMode();
409 m_engineInterfaces["xboard"] = new XboardMode();
410 m_engineInterfaces["uci"] = new UCIMode();
411 // set default startup mode
412 setMode("belofte");
413}
414
416{
417 engineInterfaces_t::iterator itr = m_engineInterfaces.begin();
418 while (itr != m_engineInterfaces.end()) {
419 delete itr->second;
420 itr = m_engineInterfaces.erase(itr);
421 }
422 m_engineInterfaces.clear();
423}
424
425std::string const appInstance::setMode(std::string const& iName)
426{
427 std::string sOldName = m_interfaceName;
428 m_interfaceName = iName;
429 m_ui = m_engineInterfaces[m_interfaceName];
430 return sOldName;
431}
432
433void appInstance::setConfig(std::string const& s, int64_t v)
434{
435 m_settings[s] = v;
436}
437
438int64_t appInstance::getConfig(std::string const& s, int64_t v)
439{
440 if (m_settings.find(s) != m_settings.end()) return m_settings[s];
441 return v;
442}
443
444void appInstance::setConfig(std::string const& s, std::string const& v)
445{
446 m_stringsettings[s] = v;
447}
448
449std::string appInstance::getConfig(std::string const& s, std::string const& v)
450{
451 if (m_stringsettings.find(s) != m_stringsettings.end()) return m_stringsettings[s];
452 return v;
453}
454
455/** @brief set name of executable based on argv[0]
456 * Remove leading / and \ characters
457 * Remove trailing .exe if present
458 */
459void appInstance::setName(char *sName)
460{
461 std::string sExename;
462
463 std::string sFile(sName);
464 sExename = sFile.substr(sFile.find_last_of("/\\") + 1);
465
466 // remove .exe
467 if (sExename.find(".exe") != std::string::npos)
468 sExename.erase(sExename.find(".exe"));
469
470 App().setConfig("exename", sExename);
471}
472
473std::string appInstance::getName() const
474{
475 return App().getConfig("exename", MYLCNAME "-" MYVERSION);
476}
477
478// --------------------------------------------------------------------
479
481{
482 static appInstance& instance = *new appInstance();
483 return instance;
484}
485
487{
488 return App().m_ui;
489}
490
492{
493 return App().m_game;
494}
495
496// --------------------------------------------------------------------
497
498static void platform_ctor()
499{
500#if defined(BELOFTE_NOSIGNALS)
501 // disable signals
502 signal(SIGTERM, SIG_IGN);
503 signal(SIGINT, SIG_IGN);
504#endif
505 // #if defined(_WIN32) || defined(WIN32)
506 // setlocale(LC_ALL, ".UTF8");
507 /// @todo remove following line ASAP, this violates all C++ standards
508 // SetConsoleOutputCP(CP_UTF8); // select unicode compatiblity
509 // call system("chcp 65001")
510 // #endif
511}
512
513static void platform_dtor()
514{
515}
516
517// eof
int main(int argc, char *argv[])
Main entry point.
Definition belofte.cpp:31
appInstance & App()
Definition belofte.cpp:480
static void platform_ctor()
The main program.
Definition belofte.cpp:498
static void platform_dtor()
Definition belofte.cpp:513
engineInterface * AppEI()
Definition belofte.cpp:486
bGame * Game()
Definition belofte.cpp:491
This is the main include file, needs to be included before any other include.
#define MYAUTHOR
Definition belofte.h:35
appInstance & App()
Definition belofte.cpp:480
#define MYLCNAME
Definition belofte.h:32
engineInterface * AppEI()
Definition belofte.cpp:486
#define MYFULLNAME
Definition belofte.h:49
#define MYLICENSE
Definition belofte.h:41
#define DEVDATES
Definition belofte.h:39
#define MYVERSION
Definition belofte.h:33
std::map< std::string, engineUserCommand * > engineCommands_t
Definition belofte.h:144
~BelofteMode() override
Definition belofte.cpp:363
implementation of specific implementation
Definition belofte.h:249
~UCIMode() override
Definition belofte.cpp:375
UCIMode(std::string const &n="uci")
Definition belofte.cpp:367
~XboardMode() override
Definition belofte.cpp:389
XboardMode(std::string const &n="xboard")
Definition belofte.cpp:379
Singleton implementation of application.
Definition belofte.h:305
bGame * m_game
Definition belofte.h:336
engineInterface * m_ui
Definition belofte.h:335
void setName(char *sName)
set name of executable based on argv[0] Remove leading / and \ characters Remove trailing ....
Definition belofte.cpp:459
bel_hash m_hashEngine
read input
Definition belofte.h:333
void setConfig(std::string const &s, int64_t v)
Definition belofte.cpp:433
outputWriter bout
Definition belofte.h:330
int64_t getConfig(std::string const &s, int64_t v)
Definition belofte.cpp:438
std::string getName() const
Definition belofte.cpp:473
std::string const setMode(std::string const &iName)
Definition belofte.cpp:425
commandReader m_reader
searching output
Definition belofte.h:332
game representation, singleton
Definition game.h:20
void newGame()
Definition game.cpp:28
bLevel & getLevel()
Definition game.h:53
void setFENInitialPos()
Definition game.cpp:46
void setDepthCommand(depth_t const d)
Definition level.cpp:250
void delayed_ctor()
Definition bel_hash.cpp:21
implementation of single command
Definition usercmd.h:98
Definition usercmd.h:382
command and parameters
Definition usercmd.h:35
std::string m_command
Definition usercmd.h:48
std::string m_args
Definition usercmd.h:49
bool isBatchMode()
no interactive input, mainly during start and '@' execute
Definition belofte.cpp:293
void clearBatchMode()
Definition belofte.cpp:304
void runner(void)
Definition belofte.cpp:204
bool isFileAttached()
Definition belofte.cpp:277
cmdParam getCommand()
Definition belofte.cpp:245
bool attach(std::string const &ifile)
Definition belofte.cpp:270
void detach()
Definition belofte.cpp:285
void setBatchMode()
Definition belofte.cpp:299
implementation of user interface
Definition belofte.h:183
virtual ~engineInterface()
Definition belofte.cpp:343
engineInterface(std::string const &n, std::string const &h="")
Common commands to all modes.
Definition belofte.cpp:313
void attachCommand(belofte::stringList const &sCommands, bool const published=true)
Definition belofte.cpp:171
virtual void sendDebug(int const l, std::string const &info)
Definition belofte.h:209
static engineCommands_t m_engineCommands
Definition belofte.h:140
void execute(std::string const &command, std::string const &params)
Definition belofte.cpp:145
virtual void sendError(std::string const &error, std::string const &description)
Definition usercmd.cpp:156
virtual void sendPrompt()
Definition belofte.h:201
basic format for single command
Definition usercmd.h:13
virtual void execute(std::string const &args)
Definition usercmd.cpp:23
constexpr depth_t DEFAULT_DEPTH
Definition level.h:12
#define MYPLATFORM
Definition myplatform.h:73
#define MYOS
Definition myplatform.h:117
void bPiece_dtor()
Definition piece.cpp:120
void bPiece_ctor()
Definition piece.cpp:34