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