6ffac64a4c8935196772b7a9e922babb2aa4dac6
[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.41b";\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 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 \r
76 void write_ini(const char *filename,\r
77                option_list_t *pg_options,\r
78                option_list_t *uci_options){\r
79     option_t *opt;\r
80     char tmp[StringSize];\r
81     FILE *f;\r
82     f=fopen(filename,"w");\r
83     if(!f){\r
84         my_fatal("ini_create_pg(): Cannot open %s for writing.\n",filename);\r
85     }\r
86     fprintf(f,"; You may edit this file to set options for the\n"\r
87               "; UCI engine whose PolyGlot name is %s.\n"\r
88               "; You may also safely delete this file\n"\r
89               "; to restore the default options.\n",\r
90             option_get_string(Option,"EngineName"));\r
91     fprintf(f,"[PolyGlot]\n");\r
92     option_start_iter(pg_options);\r
93     while((opt=option_next(pg_options))){\r
94         if(!my_string_case_equal(opt->type,"button") && (opt->mode & XBOARD)){\r
95             snprintf(tmp,sizeof(tmp),"%s=%s\n",opt->name,opt->value);\r
96             tmp[sizeof(tmp)-1]='\0';\r
97             fprintf(f,"%s",tmp);\r
98         }\r
99     }\r
100     fprintf(f,"[Engine]\n");\r
101     option_start_iter(uci_options);\r
102     while((opt=option_next(uci_options))){\r
103         if(!my_string_case_equal(opt->type,"button")){\r
104             snprintf(tmp,sizeof(tmp),"%s=%s\n",opt->name,opt->value);\r
105             tmp[sizeof(tmp)-1]='\0';\r
106             fprintf(f,"%s",tmp);\r
107         }\r
108     }\r
109     fclose(f);\r
110 }\r
111 \r
112 \r
113 // main()\r
114 \r
115 int main(int argc, char * argv[]) {\r
116     ini_t ini[1];\r
117     ini_entry_t *entry;\r
118     char *arg;\r
119     int arg_index;\r
120     bool NoIni;\r
121  \r
122     if(!DEBUG){\r
123         printf("PolyGlot %s by Fabien Letouzey.\n",Version);\r
124     }else{\r
125         printf("PolyGlot %s by Fabien Letouzey (debug build).\n",Version);\r
126     }\r
127 \r
128     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
129         printf("%s\n",HelpMessage);\r
130         return EXIT_SUCCESS;\r
131     }\r
132 \r
133    // init\r
134 \r
135     Init = FALSE;\r
136 \r
137     util_init();\r
138     option_init_pg();\r
139     \r
140     square_init();\r
141     piece_init();\r
142     attack_init();\r
143     \r
144     hash_init();\r
145 \r
146     my_random_init();\r
147 \r
148         // book utilities\r
149     \r
150     if (argc >= 2 && my_string_equal(argv[1],"make-book")) {\r
151         book_make(argc,argv);\r
152         return EXIT_SUCCESS;\r
153     }\r
154     \r
155     if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {\r
156         book_merge(argc,argv);\r
157         return EXIT_SUCCESS;\r
158     }\r
159 \r
160     if (argc >= 2 && my_string_equal(argv[1],"dump-book")) {\r
161         book_dump(argc,argv);\r
162         return EXIT_SUCCESS;\r
163     }\r
164     \r
165     if (argc >= 2 && my_string_equal(argv[1],"info-book")) {\r
166         book_info(argc,argv);\r
167         return EXIT_SUCCESS;\r
168     }\r
169 \r
170         // perft\r
171     \r
172     if (argc >= 2 && my_string_equal(argv[1],"perft")) {\r
173         do_perft(argc,argv);\r
174         return EXIT_SUCCESS;\r
175     }\r
176 \r
177         // what is the config file? This is very hacky right now?\r
178 \r
179         // Do we want a config file at all?\r
180 \r
181     arg_index=0;\r
182     NoIni=FALSE;\r
183     while((arg=argv[arg_index++])){\r
184         if(my_string_equal(arg,"-noini")){\r
185             NoIni=TRUE;\r
186             break;\r
187         }\r
188     }\r
189     arg_shift_left(argv,arg_index-1);\r
190     if(NoIni){\r
191         option_set(Option,"OptionFile","<empty>");\r
192     }\r
193 \r
194         // Ok see if first argument looks like config file\r
195     \r
196     if(argv[1] && !my_string_equal(argv[1],"epd-test") && !(argv[1][0]=='-')){\r
197                 // first argument must be  config file\r
198         if(!NoIni){\r
199             option_set(Option,"OptionFile",argv[1]);\r
200         }else{\r
201                 // ignore\r
202         }\r
203         arg_shift_left(argv,1);\r
204     }else{\r
205             // Config file is the default.\r
206             // This has already been set above or in "option_init_pg"\r
207     }\r
208     \r
209     ini_init(ini);\r
210 \r
211         // if we use a config file: load it!\r
212     \r
213     if(!my_string_equal(option_get_string(Option,"OptionFile"),"<empty>")){\r
214         if(ini_parse(ini,option_get_string(Option,"OptionFile"))){\r
215             my_fatal("main(): Can't open file \"%s\": %s\n",\r
216                    option_get_string(Option,"OptionFile"),\r
217                    strerror(errno));\r
218         }\r
219     }\r
220 \r
221         // parse the command line and merge options\r
222 \r
223     arg_index=1;\r
224     while((arg=argv[arg_index])){\r
225 //        int i=1;\r
226 //        char *arg1;\r
227 //        printf("arg_index=%d\n",arg_index);\r
228 //        while((arg1=argv[i++])){\r
229 //            printf("arg=%s ",arg1);\r
230 //        }\r
231 //        printf("\n");\r
232         if(my_string_equal(arg,"-ec") && argv[arg_index+1]){\r
233             ini_insert_ex(ini,"PolyGlot","EngineCommand",argv[arg_index+1]);\r
234             arg_shift_left(argv,arg_index);\r
235             arg_shift_left(argv,arg_index);\r
236             continue;\r
237         }\r
238         if(my_string_equal(arg,"-ed") && argv[arg_index+1]){\r
239             ini_insert_ex(ini,"PolyGlot","EngineDir",argv[arg_index+1]);\r
240             arg_shift_left(argv,arg_index);\r
241             arg_shift_left(argv,arg_index);\r
242             continue;\r
243         }\r
244         if(my_string_equal(arg,"-en") && argv[arg_index+1]){\r
245             ini_insert_ex(ini,"PolyGlot","EngineName",argv[arg_index+1]);\r
246             arg_shift_left(argv,arg_index);\r
247             arg_shift_left(argv,arg_index);\r
248             continue;\r
249         }\r
250         if(my_string_equal(arg,"-log")){\r
251             ini_insert_ex(ini,"PolyGlot","Log","true");\r
252             arg_shift_left(argv,arg_index);\r
253             continue;\r
254         }\r
255         if(my_string_equal(arg,"-lf") && argv[arg_index+1]){\r
256             ini_insert_ex(ini,"PolyGlot","LogFile",argv[arg_index+1]);\r
257             arg_shift_left(argv,arg_index);\r
258             arg_shift_left(argv,arg_index);\r
259             continue;\r
260         }\r
261         if(my_string_equal(arg,"-hash") && argv[arg_index+1]){\r
262             ini_insert_ex(ini,"Engine","Hash",argv[arg_index+1]);\r
263             arg_shift_left(argv,arg_index);\r
264             arg_shift_left(argv,arg_index);\r
265             continue;\r
266         }\r
267         if(my_string_equal(arg,"-bk") && argv[arg_index+1]){\r
268             ini_insert_ex(ini,"PolyGlot","Book","true");\r
269             ini_insert_ex(ini,"PolyGlot","BookFile",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,"-pg")||my_string_equal(arg,"-uci")) &&\r
275            argv[arg_index]){\r
276             int ret;\r
277             char section[StringSize];\r
278             char name[StringSize];\r
279             char value[StringSize];\r
280             ret=ini_line_parse(argv[arg_index++],section,name,value);\r
281             if(ret==NAME_VALUE){\r
282                 if(my_string_equal(arg,"-pg")){\r
283                     ini_insert_ex(ini,"PolyGlot",name,value);\r
284                 }else{\r
285                     ini_insert_ex(ini,"Engine",name,value);\r
286                 }\r
287             }\r
288             arg_shift_left(argv,arg_index);\r
289             arg_shift_left(argv,arg_index);\r
290             continue;\r
291         }\r
292         arg_index++;\r
293     }\r
294 \r
295         // extract PG options\r
296         // this sets both the default and the value\r
297     \r
298     option_from_ini(Option,ini,"polyglot");\r
299     \r
300         // start logging if required\r
301     \r
302     if (option_get_bool(Option,"Log")) {\r
303         my_log_open(option_get_string(Option,"LogFile"));\r
304     }\r
305 \r
306         // log welcome stuff\r
307     \r
308     if(!DEBUG){\r
309         my_log("PolyGlot %s by Fabien Letouzey\n",Version);\r
310     }else{\r
311         my_log("PolyGlot %s by Fabien Letouzey (debug build)\n",Version);\r
312     }    \r
313     my_log("POLYGLOT *** START ***\n");\r
314     my_log("POLYGLOT INI file \"%s\"\n",option_get_string(Option,"OptionFile"));\r
315 \r
316         // start engine\r
317     \r
318     engine_open(Engine);\r
319     if(!engine_active(Engine)){\r
320         my_fatal("Could not start \"%s\"\n",option_get(Option,"EngineCommand"));\r
321     }\r
322 \r
323         // switch to UCI mode if necessary\r
324     \r
325     if (option_get_bool(Option,"UCI")) {\r
326         my_log("POLYGLOT *** Switching to UCI mode ***\n");\r
327     }\r
328 \r
329         // initialize uci parsing and send uci command. Parse options and wait\r
330         // for uciok\r
331     \r
332     uci_open(Uci,Engine);\r
333 \r
334         // get engine name from engine if not supplied in config file\r
335     \r
336     if (my_string_equal(option_get_string(Option,"EngineName"),"<empty>")) {\r
337         option_set(Option,"EngineName",Uci->name);\r
338     }\r
339 \r
340         // if there is a save file: load it!\r
341 \r
342     if(my_string_equal(option_get_string(Option,"SaveFile"),"<empty>")){\r
343         char tmp[StringSize];\r
344         snprintf(tmp,sizeof(tmp),"PG_%s.ini",\r
345                  option_get_string(Option,"EngineName"));\r
346         tmp[sizeof(tmp)-1]='\0';\r
347         option_set(Option,"SaveFile",tmp);\r
348     }\r
349     if(option_get_bool(Option,"SaveSettingsOnExit")){\r
350         my_log("POLYGLOT SaveFile=%s\n",option_get_string(Option,"SaveFile"));\r
351         if(ini_parse(ini,option_get_string(Option,"SaveFile"))){\r
352             my_log("POLYGLOT Unable to open SaveFile\n"); \r
353         }\r
354     }\r
355         // start if it was enabled in the SaveFile\r
356     \r
357     my_log_close();\r
358     if (option_get_bool(Option,"Log")) {\r
359         my_log_open(option_get_string(Option,"LogFile"));\r
360     }\r
361         // remind the user of the options that are now in effect\r
362     \r
363     ini_disp(ini);\r
364 \r
365 \r
366 \r
367         // done initializing\r
368     \r
369     Init = TRUE;\r
370     \r
371         // collect engine options from config file(s) and send to engine\r
372     \r
373     ini_start_iter(ini);\r
374     while((entry=ini_next(ini))){\r
375         if(my_string_case_equal(entry->section,"engine")){\r
376                 // also updates value in Uci->option\r
377             uci_send_option(Uci,entry->name,"%s",entry->value);\r
378                 // since this comes from the ini file, also update default\r
379             option_set_default(Uci->option,entry->name,entry->value);\r
380                 //to get a decent display in winboard_x we need to now if an engine really is doing multipv analysis\r
381                // "multipv 1" in the pv is meaningless,f.i. toga sends that all the time\r
382                //therefore check if MultiPV is set to a decent value in the polyglot ini file\r
383            if(my_string_case_equal(entry->name,"MultiPV") &&\r
384               atoi(entry->value)>1){\r
385                Uci->multipv_mode=TRUE;\r
386            }\r
387         }\r
388     }\r
389    \r
390     \r
391         // EPD test\r
392     \r
393     if (argv[1] && my_string_equal(argv[1],"epd-test")){\r
394         argc=0;\r
395         while((arg=argv[argc++]));\r
396         epd_test(argc-1,argv);\r
397         return EXIT_SUCCESS;\r
398     }\r
399     \r
400         // Anything that hasn't been parsed yet is a syntax error\r
401 \r
402     if(argv[1]){\r
403         my_fatal("main(): Unknown option: %s\n",argv[1]);\r
404     }\r
405 \r
406 \r
407     init_book();\r
408     gui_init(GUI);\r
409     mainloop();\r
410     return EXIT_SUCCESS; \r
411 }\r
412 \r
413 // polyglot_set_option\r
414 \r
415 void polyglot_set_option(char *name, char *value){ // this must be cleaned up!\r
416     option_set(Option,name,value);\r
417     if(option_get_bool(Option,"Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){\r
418         my_log("POLYGLOT *** SETTING BOOK ***\n");\r
419         my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile"));\r
420         book_close();\r
421         book_clear();\r
422         book_open(option_get_string(Option,"BookFile"));\r
423         if(!book_is_open()){\r
424             my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string(Option,"BookFile"));\r
425         }\r
426     }else if(option_get_bool(Option,"Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){\r
427         my_log("POLYGLOT *** SETTING LOGFILE ***\n");\r
428         my_log("POLYGLOT LOGFILE \"%s\"\n",option_get_string(Option,"LogFile"));\r
429         my_log_close();\r
430         my_log_open(option_get_string(Option,"LogFile"));\r
431     }else if(option_get_bool(Option,"UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){\r
432         my_log("POLYGLOT Adjust Engine Piority\n");\r
433         engine_set_nice_value(Engine,atoi(option_get_string(Option,"NiceValue")));\r
434     }else if(my_string_case_equal(name,"Book") && !option_get_bool(Option,"Book")){\r
435         book_close();\r
436         book_clear();\r
437     }else if(my_string_case_equal(name,"UseNice") && !option_get_bool(Option,"UseNice")){\r
438         my_log("POLYGLOT Adjust Engine Piority\n");\r
439         engine_set_nice_value(Engine,0);\r
440     }else if(my_string_case_equal(name,"Log") && !option_get_bool(Option,"Log")){\r
441         my_log("POLYGLOT QUIT LOGGING\n");\r
442         my_log_close();\r
443     }\r
444 }\r
445 \r
446 \r
447 // init_book()\r
448 \r
449 static void init_book(){\r
450     book_clear();\r
451     if (option_get_bool(Option,"Book")){\r
452         my_log("POLYGLOT *** SETTING BOOK ***\n");\r
453         my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile"));\r
454         book_open(option_get_string(Option,"BookFile"));\r
455         if(!book_is_open()){\r
456             my_log("POLYGLOT Unable to open book \"%s\"\n",\r
457                    option_get_string(Option,"BookFile"));\r
458         }\r
459     }\r
460 }\r
461 \r
462 \r
463 // quit()\r
464 \r
465 void quit() {\r
466 \r
467     my_log("POLYGLOT *** QUIT ***\n");\r
468     \r
469     if (Init) {\r
470         \r
471         stop_search();\r
472         engine_send(Engine,"quit");\r
473         my_log("POLYGLOT Closing engine\n");\r
474         engine_close(Engine);\r
475         \r
476     }\r
477     if(option_get_bool(Option,"SaveSettingsOnExit")){\r
478         write_ini(option_get_string(Option,"SaveFile"),Option,Uci->option);\r
479     }\r
480     my_log("POLYGLOT Calling exit\n");\r
481     exit(EXIT_SUCCESS);\r
482 }\r
483 \r
484 // stop_search()\r
485 \r
486 static void stop_search() {\r
487     \r
488     if (Init && Uci->searching) {\r
489         \r
490         ASSERT(Uci->searching);\r
491         ASSERT(Uci->pending_nb>=1);\r
492         \r
493         my_log("POLYGLOT STOP SEARCH\n");\r
494         \r
495         if (option_get_bool(Option,"SyncStop")) {\r
496             uci_send_stop_sync(Uci);\r
497         } else {\r
498             uci_send_stop(Uci);\r
499         }\r
500     }\r
501 }\r
502 \r
503 \r
504 // end of main.cpp\r
505 \r