15 #include "book_make.h"
\r
16 #include "book_merge.h"
\r
24 #include "mainloop.h"
\r
26 #include "move_gen.h"
\r
33 #include "xboard2uci.h"
\r
34 #include "uci2uci.h"
\r
42 static const char * const Version = "1.4.45b";
\r
43 static const char * const HelpMessage = "\
\r
45 * polyglot [configfile] [-noini] [-ec engine] [-ed enginedirectory] [-en enginename] [-log] [-lf logfile] [-hash value] [-bk book] [-pg <name>=<value>]* [-uci <name>=<value>]*\n\
\r
46 * polyglot make-book [-pgn inputfile] [-bin outputfile] [-max-ply ply] [-min-game games] [-min-score score] [-only-white] [-only-black] [-uniform]\n\
\r
47 * polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\
\r
48 * polyglot info-book [-bin inputfile] [-exact]\n\
\r
49 * polyglot dump-book [-bin inputfile] -color color [-out outputfile]\n\
\r
50 * polyglot [configfile] epd-test [engineoptions] [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\
\r
51 * polyglot perft [-fen fen] [-max-depth depth]\
\r
54 static const int SearchDepth = 63;
\r
55 static const double SearchTime = 3600.0;
\r
56 static const int StringSize = 4096;
\r
58 static const char * const IniIntro=
\r
59 "; This ini file is used internally by PolyGlot\n"
\r
60 "; to remember the settings for the UCI engine\n"
\r
61 "; whose name is \"%s\".\n"
\r
63 "; The values for these settings would be typicallly\n"
\r
64 "; obtained from the engine settings dialog\n"
\r
65 "; in WinBoard/xboard 4.4.0 and higher.\n"
\r
67 "; It is allowed to manually edit this file\n"
\r
68 "; and you may safely delete it as well.\n"
\r
77 static void init_book ();
\r
78 static void stop_search ();
\r
84 static void arg_shift_left(char **argv, int index){
\r
86 for(i=index; argv[i]!=NULL; i++){
\r
93 static void write_ini(const char *filename,
\r
94 option_list_t *pg_options,
\r
95 option_list_t *uci_options){
\r
97 char tmp[StringSize];
\r
99 time_t t=time(NULL);
\r
100 f=fopen(filename,"w");
\r
102 // alas this does nothing....
\r
103 gui_send(GUI,"tellusererror write_ini(): %s: %s.",filename,strerror(errno));
\r
104 // but at least we log the error
\r
105 my_log("POLYGLOT write_ini(): %s: %s.\n",filename,strerror(errno));
\r
108 fprintf(f,"; %s\n",ctime(&t));
\r
109 fprintf(f,IniIntro,option_get_string(Option,"EngineName"));
\r
110 fprintf(f,"[PolyGlot]\n");
\r
111 fprintf(f,"EngineName=%s\n",
\r
112 option_get_string(Option,"EngineName"));
\r
113 fprintf(f,"EngineCommand=%s\n",
\r
114 option_get_string(Option,"EngineCommand"));
\r
115 fprintf(f,"EngineDir=%s\n",
\r
116 option_get_string(Option,"EngineDir"));
\r
117 option_start_iter(pg_options);
\r
118 while((opt=option_next(pg_options))){
\r
119 if(!my_string_equal(opt->value,opt->default_)&&
\r
121 (opt->mode & XBOARD)){
\r
122 snprintf(tmp,sizeof(tmp),"%s=%s\n",opt->name,opt->value);
\r
123 tmp[sizeof(tmp)-1]='\0';
\r
124 fprintf(f,"%s",tmp);
\r
127 fprintf(f,"[Engine]\n");
\r
128 option_start_iter(uci_options);
\r
129 while((opt=option_next(uci_options))){
\r
130 if(!my_string_equal(opt->value,opt->default_)&&
\r
132 snprintf(tmp,sizeof(tmp),"%s=%s\n",opt->name,opt->value);
\r
133 tmp[sizeof(tmp)-1]='\0';
\r
134 fprintf(f,"%s",tmp);
\r
142 static void write_ini_ex(const char *filename,
\r
144 ini_entry_t *entry;
\r
145 char tmp[StringSize];
\r
147 time_t t=time(NULL);
\r
148 f=fopen(filename,"w");
\r
150 // alas this does nothing....
\r
151 gui_send(GUI,"tellusererror write_ini(): %s: %s.",filename,strerror(errno));
\r
152 // but at least we log the error
\r
153 my_log("POLYGLOT write_ini(): %s: %s.\n",filename,strerror(errno));
\r
156 fprintf(f,"; %s\n",ctime(&t));
\r
157 fprintf(f,IniIntro,option_get_string(Option,"EngineName"));
\r
158 fprintf(f,"[PolyGlot]\n");
\r
159 fprintf(f,"EngineName=%s\n",
\r
160 option_get_string(Option,"EngineName"));
\r
161 fprintf(f,"EngineCommand=%s\n",
\r
162 option_get_string(Option,"EngineCommand"));
\r
163 fprintf(f,"EngineDir=%s\n",
\r
164 option_get_string(Option,"EngineDir"));
\r
165 ini_start_iter(ini);
\r
166 while((entry=ini_next(ini))){
\r
167 if(my_string_case_equal(entry->section,"polyglot")){
\r
168 snprintf(tmp,sizeof(tmp),"%s=%s\n",
\r
171 tmp[sizeof(tmp)-1]='\0';
\r
172 fprintf(f,"%s",tmp);
\r
175 fprintf(f,"[Engine]\n");
\r
176 ini_start_iter(ini);
\r
177 while((entry=ini_next(ini))){
\r
178 if(my_string_case_equal(entry->section,"engine")){
\r
179 snprintf(tmp,sizeof(tmp),"%s=%s\n",
\r
182 tmp[sizeof(tmp)-1]='\0';
\r
183 fprintf(f,"%s",tmp);
\r
192 int main(int argc, char * argv[]) {
\r
193 ini_t ini[1],ini_save[1];
\r
194 ini_entry_t *entry;
\r
197 bool NoIni, Persist;
\r
198 char persist_path[StringSize];
\r
201 printf("PolyGlot %s by Fabien Letouzey.\n",Version);
\r
203 printf("PolyGlot %s by Fabien Letouzey (debug build).\n",Version);
\r
206 if(argc>=2 && ((my_string_case_equal(argv[1],"help")) || (my_string_case_equal(argv[1],"-help")) || (my_string_case_equal(argv[1],"--help")) || (my_string_case_equal(argv[1],"-h")) || my_string_case_equal(argv[1],"/?"))){
\r
207 printf("%s\n",HelpMessage);
\r
208 return EXIT_SUCCESS;
\r
227 ini_init(ini_save);
\r
231 if (argc >= 2 && my_string_equal(argv[1],"make-book")) {
\r
232 book_make(argc,argv);
\r
233 return EXIT_SUCCESS;
\r
236 if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {
\r
237 book_merge(argc,argv);
\r
238 return EXIT_SUCCESS;
\r
241 if (argc >= 2 && my_string_equal(argv[1],"dump-book")) {
\r
242 book_dump(argc,argv);
\r
243 return EXIT_SUCCESS;
\r
246 if (argc >= 2 && my_string_equal(argv[1],"info-book")) {
\r
247 book_info(argc,argv);
\r
248 return EXIT_SUCCESS;
\r
253 if (argc >= 2 && my_string_equal(argv[1],"perft")) {
\r
254 do_perft(argc,argv);
\r
255 return EXIT_SUCCESS;
\r
258 // TODO: If logging is enabled on the command line turn it on NOW
\r
259 // and do not allow it to be overridden later.
\r
261 // What is the config file? This is very hacky right now.
\r
263 // Do we want a config file at all?
\r
267 while((arg=argv[arg_index++])){
\r
268 if(my_string_equal(arg,"-noini")){
\r
273 arg_shift_left(argv,arg_index-1);
\r
275 option_set(Option,"OptionFile","<empty>");
\r
278 // Ok see if first argument looks like config file
\r
280 if(argv[1] && !my_string_equal(argv[1],"epd-test") && !(argv[1][0]=='-')){
\r
281 // first argument must be config file
\r
283 option_set(Option,"OptionFile",argv[1]);
\r
287 arg_shift_left(argv,1);
\r
289 // Config file is the default.
\r
290 // This has already been set above or in "option_init_pg()"
\r
294 // if we use a config file: load it!
\r
296 if(!my_string_equal(option_get_string(Option,"OptionFile"),"<empty>")){
\r
297 if(ini_parse(ini,option_get_string(Option,"OptionFile"))){
\r
298 my_fatal("main(): Can't open file \"%s\": %s\n",
\r
299 option_get_string(Option,"OptionFile"),
\r
303 // remind the reader of what options are in effect
\r
305 my_log("POLYGLOG Options from ini file\n");
\r
308 // extract PG options
\r
310 ini_start_iter(ini);
\r
311 while((entry=ini_next(ini))){
\r
312 if(my_string_case_equal(entry->section,"polyglot")){
\r
313 option_set(Option,entry->name,entry->value);
\r
314 option_set_default(Option,entry->name,entry->value);
\r
318 // start logging if required
\r
320 if (option_get_bool(Option,"Log")) {
\r
321 my_log_open(option_get_string(Option,"LogFile"));
\r
324 // log welcome stuff
\r
327 my_log("PolyGlot %s by Fabien Letouzey\n",Version);
\r
329 my_log("PolyGlot %s by Fabien Letouzey (debug build)\n",Version);
\r
331 my_log("POLYGLOT *** START ***\n");
\r
332 my_log("POLYGLOT INI file \"%s\"\n",option_get_string(Option,"OptionFile"));
\r
334 // open book (presumably this should go else where)
\r
338 // scavenge command line for options necessary to start the engine
\r
341 while((arg=argv[arg_index])){
\r
342 if(my_string_equal(arg,"-ec") && argv[arg_index+1]){
\r
343 option_set(Option,"EngineCommand",argv[arg_index+1]);
\r
344 arg_shift_left(argv,arg_index);
\r
345 arg_shift_left(argv,arg_index);
\r
348 if(my_string_equal(arg,"-ed") && argv[arg_index+1]){
\r
349 option_set(Option,"EngineDir",argv[arg_index+1]);
\r
350 arg_shift_left(argv,arg_index);
\r
351 arg_shift_left(argv,arg_index);
\r
354 if(my_string_equal(arg,"-en") && argv[arg_index+1]){
\r
355 option_set(Option,"EngineName",argv[arg_index+1]);
\r
356 arg_shift_left(argv,arg_index);
\r
357 arg_shift_left(argv,arg_index);
\r
365 engine_open(Engine);
\r
366 if(!engine_active(Engine)){
\r
367 my_fatal("Could not start \"%s\"\n",option_get(Option,"EngineCommand"));
\r
370 // switch to UCI mode if necessary
\r
372 if (option_get_bool(Option,"UCI")) {
\r
373 my_log("POLYGLOT *** Switching to UCI mode ***\n");
\r
376 // initialize uci parsing and send uci command.
\r
377 // Parse options and wait for uciok
\r
379 uci_open(Uci,Engine);
\r
381 // get engine name from engine if not supplied in config file
\r
383 if (my_string_equal(option_get_string(Option,"EngineName"),"<empty>")) {
\r
384 option_set(Option,"EngineName",Uci->name);
\r
387 // what is the name of the persist file?
\r
389 if(my_string_equal(option_get_string(Option,"PersistFile"),"<empty>")){
\r
390 char tmp[StringSize];
\r
391 snprintf(tmp,sizeof(tmp),"%s.ini",
\r
392 option_get_string(Option,"EngineName"));
\r
393 tmp[sizeof(tmp)-1]='\0';
\r
394 option_set(Option,"PersistFile",tmp);
\r
397 // Load the persist file
\r
399 my_path_join(persist_path,
\r
400 option_get_string(Option,"PersistDir"),
\r
401 option_get_string(Option,"PersistFile"));
\r
403 my_log("POLYGLOT PersistFile=%s\n",persist_path);
\r
404 if(ini_parse(ini_save,persist_path)){
\r
405 my_log("POLYGLOT Unable to open PersistFile\n");
\r
408 // Do we want to use the persist file?
\r
410 entry=ini_find(ini_save,"polyglot","Persist");
\r
412 Persist=option_get_bool(Option,"Persist");
\r
414 Persist=(my_string_case_equal(entry->value,"false") ||
\r
415 my_string_equal(entry->value,"0"))?FALSE:TRUE;
\r
418 // if "Persist" now happens to be false, forget about the
\r
422 my_log("POLYGLOT Ignoring PersistFile");
\r
423 ini_clear(ini_save);
\r
426 option_set(Option,"Persist",Persist?"true":"false");
\r
428 // parse the command line and merge remaining options
\r
431 while((arg=argv[arg_index])){
\r
432 if(my_string_equal(arg,"-log")){
\r
433 ini_insert_ex(ini_save,"PolyGlot","Log","true");
\r
434 arg_shift_left(argv,arg_index);
\r
437 if(my_string_equal(arg,"-lf") && argv[arg_index+1]){
\r
438 ini_insert_ex(ini_save,"PolyGlot","LogFile",argv[arg_index+1]);
\r
439 arg_shift_left(argv,arg_index);
\r
440 arg_shift_left(argv,arg_index);
\r
443 if(my_string_equal(arg,"-hash") && argv[arg_index+1]){
\r
444 ini_insert_ex(ini_save,"Engine","Hash",argv[arg_index+1]);
\r
445 arg_shift_left(argv,arg_index);
\r
446 arg_shift_left(argv,arg_index);
\r
449 if(my_string_equal(arg,"-bk") && argv[arg_index+1]){
\r
450 ini_insert_ex(ini_save,"PolyGlot","Book","true");
\r
451 ini_insert_ex(ini_save,"PolyGlot","BookFile",argv[arg_index+1]);
\r
452 arg_shift_left(argv,arg_index);
\r
453 arg_shift_left(argv,arg_index);
\r
456 if((my_string_equal(arg,"-pg")||my_string_equal(arg,"-uci")) &&
\r
459 char section[StringSize];
\r
460 char name[StringSize];
\r
461 char value[StringSize];
\r
462 ret=ini_line_parse(argv[arg_index++],section,name,value);
\r
463 if(ret==NAME_VALUE){
\r
464 if(my_string_equal(arg,"-pg")){
\r
465 ini_insert_ex(ini_save,"PolyGlot",name,value);
\r
467 ini_insert_ex(ini_save,"Engine",name,value);
\r
470 arg_shift_left(argv,arg_index);
\r
471 arg_shift_left(argv,arg_index);
\r
477 // remind the reader once again about options
\r
479 my_log("POLYGLOG Options from PersistFile and command line\n");
\r
480 ini_disp(ini_save);
\r
482 // Extract PG options; this time do not set the default.
\r
483 // polyglot_set_option() performs the necessary actions such
\r
484 // as opening the log file/opening book etcetera.
\r
485 // Ignore EngineName, EngineCommand and EngineDir
\r
486 // as these are really meant as comments.
\r
488 ini_start_iter(ini_save);
\r
489 while((entry=ini_next(ini_save))){
\r
490 if(my_string_case_equal(entry->section,"polyglot")){
\r
491 if(my_string_case_equal(entry->value,"EngineName"))
\r
493 if(my_string_case_equal(entry->value,"EngineCommand"))
\r
495 if(my_string_case_equal(entry->value,"EngineDir"))
\r
497 polyglot_set_option(entry->name,entry->value);
\r
501 // done initializing
\r
505 // collect engine options from config file(s) and send to engine
\r
507 ini_start_iter(ini);
\r
508 while((entry=ini_next(ini))){
\r
509 if(my_string_case_equal(entry->section,"engine")){
\r
510 // also updates value in Uci->option
\r
511 uci_send_option(Uci,entry->name,"%s",entry->value);
\r
512 // since this comes from the ini file, also update default
\r
513 option_set_default(Uci->option,entry->name,entry->value);
\r
514 // this is inherited, it probably does not work correctly
\r
515 if(my_string_case_equal(entry->name,"MultiPV") &&
\r
516 atoi(entry->value)>1){
\r
517 Uci->multipv_mode=TRUE;
\r
521 ini_start_iter(ini_save);
\r
522 while((entry=ini_next(ini_save))){
\r
523 if(my_string_case_equal(entry->section,"engine")){
\r
524 // also updates value in Uci->option
\r
525 uci_send_option(Uci,entry->name,"%s",entry->value);
\r
526 // this is inherited, it probably does not work correctly
\r
527 if(my_string_case_equal(entry->name,"MultiPV") &&
\r
528 atoi(entry->value)>1){
\r
529 Uci->multipv_mode=TRUE;
\r
537 if (argv[1] && my_string_equal(argv[1],"epd-test")){
\r
539 while((arg=argv[argc++]));
\r
540 epd_test(argc-1,argv);
\r
541 return EXIT_SUCCESS;
\r
544 // Anything that hasn't been parsed yet is a syntax error
\r
547 my_fatal("main(): Unknown option: %s\n",argv[1]);
\r
553 return EXIT_SUCCESS;
\r
556 // polyglot_set_option()
\r
558 void polyglot_set_option(const char *name, const char *value){ // this must be cleaned up!
\r
560 my_log("POLYGLOT Setting PolyGlot option %s=\"%s\"\n",name,value);
\r
561 if(my_string_case_equal(name,"Defaults")){
\r
562 option_start_iter(Uci->option);
\r
563 while((opt=option_next(Uci->option))){
\r
564 if(!IS_BUTTON(opt)){
\r
565 // also sets opt->value
\r
566 uci_send_option(Uci,opt->name,opt->default_);
\r
569 option_start_iter(Option);
\r
570 while((opt=option_next(Option))){
\r
571 if(!IS_BUTTON(opt)){
\r
572 polyglot_set_option(opt->name,opt->default_);
\r
575 xboard2uci_send_options();
\r
577 option_set(Option,name,value);
\r
578 if(option_get_bool(Option,"Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){
\r
579 my_log("POLYGLOT *** SETTING BOOK ***\n");
\r
580 my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile"));
\r
583 book_open(option_get_string(Option,"BookFile"));
\r
584 if(!book_is_open()){
\r
585 my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string(Option,"BookFile"));
\r
587 }else if(option_get_bool(Option,"Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){
\r
588 my_log("POLYGLOT *** SWITCHING LOGFILE ***\n");
\r
589 my_log("POLYGLOT LOGFILE \"%s\"\n",option_get_string(Option,"LogFile"));
\r
591 my_log_open(option_get_string(Option,"LogFile"));
\r
592 }else if(option_get_bool(Option,"UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){
\r
593 my_log("POLYGLOT Adjust Engine Piority\n");
\r
594 engine_set_nice_value(Engine,atoi(option_get_string(Option,"NiceValue")));
\r
595 }else if(my_string_case_equal(name,"Book") && !option_get_bool(Option,"Book")){
\r
598 }else if(my_string_case_equal(name,"UseNice") && !option_get_bool(Option,"UseNice")){
\r
599 my_log("POLYGLOT Adjust Engine Piority\n");
\r
600 engine_set_nice_value(Engine,0);
\r
601 }else if(my_string_case_equal(name,"Log") && !option_get_bool(Option,"Log")){
\r
602 my_log("POLYGLOT QUIT LOGGING\n");
\r
610 static void init_book(){
\r
612 if (option_get_bool(Option,"Book")){
\r
613 my_log("POLYGLOT *** SETTING BOOK ***\n");
\r
614 my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile"));
\r
615 book_open(option_get_string(Option,"BookFile"));
\r
616 if(!book_is_open()){
\r
617 my_log("POLYGLOT Unable to open book \"%s\"\n",
\r
618 option_get_string(Option,"BookFile"));
\r
629 char persist_path[StringSize];
\r
634 my_log("POLYGLOT *** QUIT ***\n");
\r
639 engine_send(Engine,"quit");
\r
640 my_log("POLYGLOT Closing engine\n");
\r
641 engine_close(Engine);
\r
644 ret=my_mkdir(option_get(Option,"PersistDir"));
\r
646 my_log("POLYGLOT quit(): %s: %s\n",option_get(Option,"PersistDir"),strerror(errno));
\r
648 // PersistFile can be named "<empty>" in case of a crash before the
\r
649 // engine is started.
\r
650 if(!my_string_case_equal(option_get(Option,"PersistFile"),
\r
652 my_path_join(persist_path,
\r
653 option_get(Option,"PersistDir"),
\r
654 option_get(Option,"PersistFile"));
\r
655 if(option_get_bool(Option,"Persist")){
\r
656 write_ini(persist_path,
\r
657 Option,Uci->option);
\r
658 }else if(!my_string_case_equal(option_get_default(Option,"Persist"),
\r
659 option_get_string(Option,"Persist"))){
\r
661 ini_insert_ex(empty,"PolyGlot","Persist","false");
\r
662 write_ini_ex(persist_path,empty);
\r
664 write_ini_ex(persist_path,empty);
\r
666 my_log("POLYGLOT Calling exit\n");
\r
668 exit(EXIT_SUCCESS);
\r
673 static void stop_search() {
\r
675 if (Init && Uci->searching) {
\r
677 ASSERT(Uci->searching);
\r
678 ASSERT(Uci->pending_nb>=1);
\r
680 my_log("POLYGLOT STOP SEARCH\n");
\r
682 if (option_get_bool(Option,"SyncStop")) {
\r
683 uci_send_stop_sync(Uci);
\r
685 uci_send_stop(Uci);
\r