fad2ed8b9a806b21371342d105d0d1191915a39b
[polyglot.git] / main.c
1 \r
2 // main.c\r
3 \r
4 // includes\r
5 \r
6 #include <errno.h>\r
7 #include <stdio.h>\r
8 #include <stdlib.h>\r
9 #include <string.h>\r
10 \r
11 #include "attack.h"\r
12 #include "board.h"\r
13 #include "book.h"\r
14 #include "book_make.h"\r
15 #include "book_merge.h"\r
16 #include "engine.h"\r
17 #include "epd.h"\r
18 #include "fen.h"\r
19 #include "gui.h"\r
20 #include "hash.h"\r
21 #include "list.h"\r
22 #include "main.h"\r
23 #include "mainloop.h"\r
24 #include "move.h"\r
25 #include "move_gen.h"\r
26 #include "option.h"\r
27 #include "piece.h"\r
28 #include "search.h"\r
29 #include "square.h"\r
30 #include "uci.h"\r
31 #include "util.h"\r
32 #include "xboard2uci.h"\r
33 #include "uci2uci.h"\r
34 #include "ini.h"\r
35 \r
36 // constants\r
37 \r
38 \r
39 static const char * const Version = "1.4.42b";\r
40 static const char * const HelpMessage = "\\r
41 SYNTAX\n\\r
42 * polyglot [configfile] [-noini] [-ec engine] [-ed enginedirectory] [-en enginename] [-log] [-lf logfile] [-hash value] [-bk book] [-pg <name>=<value>]* [-uci <name>=<value>]*\n\\r
43 * polyglot make-book [-pgn inputfile] [-bin outputfile] [-max-ply ply] [-min-game games] [-min-score score] [-only-white] [-only-black] [-uniform]\n\\r
44 * polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\\r
45 * polyglot info-book [-bin inputfile] [-exact]\n\\r
46 * polyglot dump-book [-bin inputfile] -color color [-out outputfile]\n\\r
47 * polyglot [configfile] epd-test [engineoptions] [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\\r
48 * polyglot perft [-fen fen] [-max-depth depth]\\r
49 ";\r
50 \r
51 static const int SearchDepth = 63;\r
52 static const double SearchTime = 3600.0;\r
53 static const int StringSize = 4096;\r
54 \r
55 // variables\r
56 \r
57 static bool Init;\r
58 \r
59 // prototypes\r
60 \r
61 static void init_book ();\r
62 static void stop_search  ();\r
63 \r
64 // functions\r
65 \r
66 // arg_shift_left()\r
67 \r
68 static void arg_shift_left(char **argv, int index){\r
69     int i;\r
70     for(i=index; argv[i]!=NULL; i++){\r
71         argv[i]=argv[i+1];\r
72     }\r
73 }\r
74 \r
75 // write_ini()\r
76 \r
77 static void write_ini(const char *filename,\r
78                       option_list_t *pg_options,\r
79                       option_list_t *uci_options){\r
80     option_t *opt;\r
81     char tmp[StringSize];\r
82     FILE *f;\r
83     f=fopen(filename,"w");\r
84     if(!f){\r
85         my_fatal("ini_create_pg(): Cannot open %s for writing.\n",filename);\r
86     }\r
87     fprintf(f,"; You may edit this file to set options for the\n"\r
88               "; UCI engine whose PolyGlot name is %s.\n"\r
89               "; You may also safely delete this file\n"\r
90               "; to restore the default options.\n",\r
91             option_get_string(Option,"EngineName"));\r
92     fprintf(f,"[PolyGlot]\n");\r
93     option_start_iter(pg_options);\r
94     while((opt=option_next(pg_options))){\r
95         if(!my_string_equal(opt->value,opt->default_)&&\r
96            !my_string_case_equal(opt->type,"button") &&\r
97            (opt->mode & XBOARD)){\r
98             snprintf(tmp,sizeof(tmp),"%s=%s\n",opt->name,opt->value);\r
99             tmp[sizeof(tmp)-1]='\0';\r
100             fprintf(f,"%s",tmp);\r
101         }\r
102     }\r
103     fprintf(f,"[Engine]\n");\r
104     option_start_iter(uci_options);\r
105     while((opt=option_next(uci_options))){\r
106         if(!my_string_equal(opt->value,opt->default_)&&\r
107            !my_string_case_equal(opt->type,"button")){\r
108             snprintf(tmp,sizeof(tmp),"%s=%s\n",opt->name,opt->value);\r
109             tmp[sizeof(tmp)-1]='\0';\r
110             fprintf(f,"%s",tmp);\r
111         }\r
112     }\r
113     fclose(f);\r
114 }\r
115 \r
116 \r
117 // main()\r
118 \r
119 int main(int argc, char * argv[]) {\r
120     ini_t ini[1],ini_save[1];\r
121     ini_entry_t *entry;\r
122     char *arg;\r
123     int arg_index;\r
124     bool NoIni;\r
125  \r
126     if(!DEBUG){\r
127         printf("PolyGlot %s by Fabien Letouzey.\n",Version);\r
128     }else{\r
129         printf("PolyGlot %s by Fabien Letouzey (debug build).\n",Version);\r
130     }\r
131 \r
132     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
133         printf("%s\n",HelpMessage);\r
134         return EXIT_SUCCESS;\r
135     }\r
136 \r
137    // init\r
138 \r
139     Init = FALSE;\r
140 \r
141     util_init();\r
142     option_init_pg();\r
143     \r
144     square_init();\r
145     piece_init();\r
146     attack_init();\r
147     \r
148     hash_init();\r
149 \r
150     my_random_init();\r
151 \r
152     ini_init(ini);\r
153     ini_init(ini_save);\r
154 \r
155         // book utilities\r
156     \r
157     if (argc >= 2 && my_string_equal(argv[1],"make-book")) {\r
158         book_make(argc,argv);\r
159         return EXIT_SUCCESS;\r
160     }\r
161     \r
162     if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {\r
163         book_merge(argc,argv);\r
164         return EXIT_SUCCESS;\r
165     }\r
166 \r
167     if (argc >= 2 && my_string_equal(argv[1],"dump-book")) {\r
168         book_dump(argc,argv);\r
169         return EXIT_SUCCESS;\r
170     }\r
171     \r
172     if (argc >= 2 && my_string_equal(argv[1],"info-book")) {\r
173         book_info(argc,argv);\r
174         return EXIT_SUCCESS;\r
175     }\r
176 \r
177         // perft\r
178     \r
179     if (argc >= 2 && my_string_equal(argv[1],"perft")) {\r
180         do_perft(argc,argv);\r
181         return EXIT_SUCCESS;\r
182     }\r
183 \r
184         // TODO: If logging is enabled on the command line turn it on NOW\r
185         // and do not allow it to be overridden later. \r
186     \r
187         // What is the config file? This is very hacky right now.\r
188 \r
189         // Do we want a config file at all?\r
190 \r
191     arg_index=0;\r
192     NoIni=FALSE;\r
193     while((arg=argv[arg_index++])){\r
194         if(my_string_equal(arg,"-noini")){\r
195             NoIni=TRUE;\r
196             break;\r
197         }\r
198     }\r
199     arg_shift_left(argv,arg_index-1);\r
200     if(NoIni){\r
201         option_set(Option,"OptionFile","<empty>");\r
202     }\r
203 \r
204         // Ok see if first argument looks like config file\r
205     \r
206     if(argv[1] && !my_string_equal(argv[1],"epd-test") && !(argv[1][0]=='-')){\r
207                 // first argument must be  config file\r
208         if(!NoIni){\r
209             option_set(Option,"OptionFile",argv[1]);\r
210         }else{\r
211                 // ignore\r
212         }\r
213         arg_shift_left(argv,1);\r
214     }else{\r
215             // Config file is the default.\r
216             // This has already been set above or in "option_init_pg()"\r
217     }\r
218     \r
219 \r
220         // if we use a config file: load it!\r
221     \r
222     if(!my_string_equal(option_get_string(Option,"OptionFile"),"<empty>")){\r
223         if(ini_parse(ini,option_get_string(Option,"OptionFile"))){\r
224             my_fatal("main(): Can't open file \"%s\": %s\n",\r
225                    option_get_string(Option,"OptionFile"),\r
226                    strerror(errno));\r
227         }\r
228     }\r
229         // remind the reader of what options are in effect\r
230 \r
231     my_log("POLYGLOG Options from ini file\n");\r
232     ini_disp(ini);\r
233 \r
234         // extract PG options\r
235     \r
236     ini_start_iter(ini);\r
237     while((entry=ini_next(ini))){\r
238         if(my_string_case_equal(entry->section,"polyglot")){\r
239             option_set(Option,entry->name,entry->value);\r
240             option_set_default(Option,entry->name,entry->value);\r
241         }\r
242     }\r
243 \r
244         // start logging if required\r
245     \r
246     if (option_get_bool(Option,"Log")) {\r
247         my_log_open(option_get_string(Option,"LogFile"));\r
248     }\r
249 \r
250         // log welcome stuff\r
251     \r
252     if(!DEBUG){\r
253         my_log("PolyGlot %s by Fabien Letouzey\n",Version);\r
254     }else{\r
255         my_log("PolyGlot %s by Fabien Letouzey (debug build)\n",Version);\r
256     }    \r
257     my_log("POLYGLOT *** START ***\n");\r
258     my_log("POLYGLOT INI file \"%s\"\n",option_get_string(Option,"OptionFile"));\r
259 \r
260         // open book (presumably this should go else where)\r
261     \r
262     init_book();\r
263 \r
264         // scavenge command line for options necessary to start the engine\r
265     \r
266     arg_index=1;\r
267     while((arg=argv[arg_index])){\r
268         if(my_string_equal(arg,"-ec") && argv[arg_index+1]){\r
269             option_set(Option,"EngineCommand",argv[arg_index+1]);\r
270             arg_shift_left(argv,arg_index);\r
271             arg_shift_left(argv,arg_index);\r
272             continue;\r
273         }\r
274         if(my_string_equal(arg,"-ed") && argv[arg_index+1]){\r
275             option_set(Option,"EngineDir",argv[arg_index+1]);\r
276             arg_shift_left(argv,arg_index);\r
277             arg_shift_left(argv,arg_index);\r
278             continue;\r
279         }\r
280         if(my_string_equal(arg,"-en") && argv[arg_index+1]){\r
281             option_set(Option,"EngineName",argv[arg_index+1]);\r
282             arg_shift_left(argv,arg_index);\r
283             arg_shift_left(argv,arg_index);\r
284             continue;\r
285         }\r
286         arg_index++;\r
287     }\r
288 \r
289         // start engine\r
290     \r
291     engine_open(Engine);\r
292     if(!engine_active(Engine)){\r
293         my_fatal("Could not start \"%s\"\n",option_get(Option,"EngineCommand"));\r
294     }\r
295 \r
296         // switch to UCI mode if necessary\r
297     \r
298     if (option_get_bool(Option,"UCI")) {\r
299         my_log("POLYGLOT *** Switching to UCI mode ***\n");\r
300     }\r
301 \r
302         // initialize uci parsing and send uci command. Parse options and wait\r
303         // for uciok\r
304     \r
305     uci_open(Uci,Engine);\r
306 \r
307         // get engine name from engine if not supplied in config file\r
308     \r
309     if (my_string_equal(option_get_string(Option,"EngineName"),"<empty>")) {\r
310         option_set(Option,"EngineName",Uci->name);\r
311     }\r
312 \r
313         // what is the name of the persist file?\r
314 \r
315     if(my_string_equal(option_get_string(Option,"PersistFile"),"<empty>")){\r
316         char tmp[StringSize];\r
317         snprintf(tmp,sizeof(tmp),"PG_%s.ini",\r
318                  option_get_string(Option,"EngineName"));\r
319         tmp[sizeof(tmp)-1]='\0';\r
320         option_set(Option,"PersistFile",tmp);\r
321     }\r
322 \r
323         // if "Persist" is true, load the persist file!\r
324     \r
325     if(option_get_bool(Option,"Persist")){\r
326         my_log("POLYGLOT PersistFile=%s\n",option_get_string(Option,"PersistFile"));\r
327         if(ini_parse(ini_save,option_get_string(Option,"PersistFile"))){\r
328             my_log("POLYGLOT Unable to open PersistFile\n"); \r
329         }\r
330     }\r
331     \r
332         // parse the command line and merge remaining options\r
333 \r
334     arg_index=1;\r
335     while((arg=argv[arg_index])){\r
336         if(my_string_equal(arg,"-log")){\r
337             ini_insert_ex(ini_save,"PolyGlot","Log","true");\r
338             arg_shift_left(argv,arg_index);\r
339             continue;\r
340         }\r
341         if(my_string_equal(arg,"-lf") && argv[arg_index+1]){\r
342             ini_insert_ex(ini_save,"PolyGlot","LogFile",argv[arg_index+1]);\r
343             arg_shift_left(argv,arg_index);\r
344             arg_shift_left(argv,arg_index);\r
345             continue;\r
346         }\r
347         if(my_string_equal(arg,"-hash") && argv[arg_index+1]){\r
348             ini_insert_ex(ini_save,"Engine","Hash",argv[arg_index+1]);\r
349             arg_shift_left(argv,arg_index);\r
350             arg_shift_left(argv,arg_index);\r
351             continue;\r
352         }\r
353         if(my_string_equal(arg,"-bk") && argv[arg_index+1]){\r
354             ini_insert_ex(ini_save,"PolyGlot","Book","true");\r
355             ini_insert_ex(ini_save,"PolyGlot","BookFile",argv[arg_index+1]);\r
356             arg_shift_left(argv,arg_index);\r
357             arg_shift_left(argv,arg_index);\r
358             continue;\r
359         }\r
360         if((my_string_equal(arg,"-pg")||my_string_equal(arg,"-uci")) &&\r
361            argv[arg_index]){\r
362             int ret;\r
363             char section[StringSize];\r
364             char name[StringSize];\r
365             char value[StringSize];\r
366             ret=ini_line_parse(argv[arg_index++],section,name,value);\r
367             if(ret==NAME_VALUE){\r
368                 if(my_string_equal(arg,"-pg")){\r
369                     ini_insert_ex(ini_save,"PolyGlot",name,value);\r
370                 }else{\r
371                     ini_insert_ex(ini_save,"Engine",name,value);\r
372                 }\r
373             }\r
374             arg_shift_left(argv,arg_index);\r
375             arg_shift_left(argv,arg_index);\r
376             continue;\r
377         }\r
378         arg_index++;\r
379     }\r
380 \r
381         // remind the reader once again about options\r
382 \r
383     my_log("POLYGLOG Options from save file and command line\n");\r
384     ini_disp(ini_save);\r
385 \r
386         // extract PG options; this time do not set the default\r
387         // polyglot_set_option() performs the necessary actions such\r
388         // as opening the log file/opening book etcetera.\r
389     \r
390     ini_start_iter(ini_save);\r
391     while((entry=ini_next(ini_save))){\r
392         if(my_string_case_equal(entry->section,"polyglot")){\r
393             polyglot_set_option(entry->name,entry->value);\r
394         }\r
395     }\r
396 \r
397         // done initializing\r
398     \r
399     Init = TRUE;\r
400     \r
401         // collect engine options from config file(s) and send to engine\r
402     \r
403     ini_start_iter(ini);\r
404     while((entry=ini_next(ini))){\r
405         if(my_string_case_equal(entry->section,"engine")){\r
406                 // also updates value in Uci->option\r
407             uci_send_option(Uci,entry->name,"%s",entry->value);\r
408                 // since this comes from the ini file, also update default\r
409             option_set_default(Uci->option,entry->name,entry->value);\r
410                 // this is inherited, it probably does not work correctly\r
411            if(my_string_case_equal(entry->name,"MultiPV") &&\r
412               atoi(entry->value)>1){\r
413                Uci->multipv_mode=TRUE;\r
414            }\r
415         }\r
416     }\r
417     ini_start_iter(ini_save);\r
418     while((entry=ini_next(ini_save))){\r
419         if(my_string_case_equal(entry->section,"engine")){\r
420                 // also updates value in Uci->option\r
421             uci_send_option(Uci,entry->name,"%s",entry->value);\r
422                 // this is inherited, it probably does not work correctly\r
423             if(my_string_case_equal(entry->name,"MultiPV") &&\r
424                atoi(entry->value)>1){\r
425                 Uci->multipv_mode=TRUE;\r
426             }\r
427         }\r
428     }\r
429    \r
430     \r
431         // EPD test\r
432     \r
433     if (argv[1] && my_string_equal(argv[1],"epd-test")){\r
434         argc=0;\r
435         while((arg=argv[argc++]));\r
436         epd_test(argc-1,argv);\r
437         return EXIT_SUCCESS;\r
438     }\r
439     \r
440         // Anything that hasn't been parsed yet is a syntax error\r
441 \r
442     if(argv[1]){\r
443         my_fatal("main(): Unknown option: %s\n",argv[1]);\r
444     }\r
445 \r
446 \r
447     gui_init(GUI);\r
448     mainloop();\r
449     return EXIT_SUCCESS; \r
450 }\r
451 \r
452 // polyglot_set_option()\r
453 \r
454 void polyglot_set_option(const char *name, const char *value){ // this must be cleaned up!\r
455     my_log("POLYGLOT Setting PolyGlot option %s=\"%s\"\n",name,value);\r
456     option_set(Option,name,value);\r
457     if(option_get_bool(Option,"Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){\r
458         my_log("POLYGLOT *** SETTING BOOK ***\n");\r
459         my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile"));\r
460         book_close();\r
461         book_clear();\r
462         book_open(option_get_string(Option,"BookFile"));\r
463         if(!book_is_open()){\r
464             my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string(Option,"BookFile"));\r
465         }\r
466     }else if(option_get_bool(Option,"Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){\r
467         my_log("POLYGLOT *** SETTING LOGFILE ***\n");\r
468         my_log("POLYGLOT LOGFILE \"%s\"\n",option_get_string(Option,"LogFile"));\r
469         my_log_close();\r
470         my_log_open(option_get_string(Option,"LogFile"));\r
471     }else if(option_get_bool(Option,"UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){\r
472         my_log("POLYGLOT Adjust Engine Piority\n");\r
473         engine_set_nice_value(Engine,atoi(option_get_string(Option,"NiceValue")));\r
474     }else if(my_string_case_equal(name,"Book") && !option_get_bool(Option,"Book")){\r
475         book_close();\r
476         book_clear();\r
477     }else if(my_string_case_equal(name,"UseNice") && !option_get_bool(Option,"UseNice")){\r
478         my_log("POLYGLOT Adjust Engine Piority\n");\r
479         engine_set_nice_value(Engine,0);\r
480     }else if(my_string_case_equal(name,"Log") && !option_get_bool(Option,"Log")){\r
481         my_log("POLYGLOT QUIT LOGGING\n");\r
482         my_log_close();\r
483     }\r
484 }\r
485 \r
486 \r
487 // init_book()\r
488 \r
489 static void init_book(){\r
490     book_clear();\r
491     if (option_get_bool(Option,"Book")){\r
492         my_log("POLYGLOT *** SETTING BOOK ***\n");\r
493         my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile"));\r
494         book_open(option_get_string(Option,"BookFile"));\r
495         if(!book_is_open()){\r
496             my_log("POLYGLOT Unable to open book \"%s\"\n",\r
497                    option_get_string(Option,"BookFile"));\r
498         }\r
499     }\r
500 }\r
501 \r
502 \r
503 // quit()\r
504 \r
505 void quit() {\r
506 \r
507     my_log("POLYGLOT *** QUIT ***\n");\r
508     \r
509     if (Init) {\r
510         \r
511         stop_search();\r
512         engine_send(Engine,"quit");\r
513         my_log("POLYGLOT Closing engine\n");\r
514         engine_close(Engine);\r
515         \r
516     }\r
517     if(option_get_bool(Option,"Persist")){\r
518         write_ini(option_get_string(Option,"PersistFile"),\r
519                   Option,Uci->option);\r
520     }\r
521     my_log("POLYGLOT Calling exit\n");\r
522     exit(EXIT_SUCCESS);\r
523 }\r
524 \r
525 // stop_search()\r
526 \r
527 static void stop_search() {\r
528     \r
529     if (Init && Uci->searching) {\r
530         \r
531         ASSERT(Uci->searching);\r
532         ASSERT(Uci->pending_nb>=1);\r
533         \r
534         my_log("POLYGLOT STOP SEARCH\n");\r
535         \r
536         if (option_get_bool(Option,"SyncStop")) {\r
537             uci_send_stop_sync(Uci);\r
538         } else {\r
539             uci_send_stop(Uci);\r
540         }\r
541     }\r
542 }\r
543 \r
544 \r
545 // end of main.cpp\r
546 \r