05d60b35cd702fee3312f738f6420dd5a9d1604d
[polyglot.git] / uci.c
1 \r
2 // uci.c\r
3 \r
4 // includes\r
5 \r
6 #include <stdarg.h>\r
7 #include <stdio.h>\r
8 #include <stdlib.h>\r
9 #include <string.h>\r
10 \r
11 #include "board.h"\r
12 #include "engine.h"\r
13 #include "gui.h"\r
14 #include "move.h"\r
15 #include "move_do.h"\r
16 #include "move_legal.h"\r
17 #include "option.h"\r
18 #include "parse.h"\r
19 #include "line.h"\r
20 #include "uci.h"\r
21 \r
22 \r
23 // constants\r
24 \r
25 static const bool UseDebug = FALSE;\r
26 \r
27 #define StringSize ((int)4096)\r
28 \r
29 // variables\r
30 \r
31 uci_t Uci[1];\r
32 \r
33 // Hopefully the following confusion is temporary\r
34 // Normally we should check for the engine name but this is a hack anyway\r
35 // Some of there where provided by Marc Lacrosse\r
36 \r
37 const char * thread_options[]={\r
38   "number of threads",        // toga\r
39   "number threads",           // Deep Learning Toga\r
40   "threads",                  // glaurung, zappa, cyclone, grapefruit,\r
41                               // Deep Shredder, Deep Junior, bright\r
42   "core threads",             // HIARCS\r
43   "max cpus",                 // rybka\r
44   "cpus",                     // Deep Sjeng, Fruit2.3.5\r
45   "maxthreads",               // Naum \r
46   NULL\r
47 };\r
48 \r
49 // prototypes\r
50 \r
51 static bool uci_is_ok      (const uci_t * uci);\r
52 \r
53 static int  parse_bestmove (uci_t * uci, const char string[]);\r
54 static void parse_id       (uci_t * uci, const char string[]);\r
55 static int  parse_info     (uci_t * uci, const char string[]);\r
56 static void parse_option   (uci_t * uci, const char string[]);\r
57 static void parse_score    (uci_t * uci, const char string[]);\r
58 \r
59 static int  mate_score     (int dist);\r
60 \r
61 // functions\r
62 \r
63 \r
64 // uci_adapt_UCI3()\r
65 \r
66 static void apply_UCI3_heuristics(option_t *opt){\r
67   if(option_get_int(Option,"UCIVersion")>2){\r
68     return;\r
69   }\r
70   if(!my_string_equal(opt->type,"string")){\r
71     return;\r
72   }\r
73   if(!strncmp(opt->name,"UCI_",4)){\r
74     return;\r
75   }\r
76   if(my_string_case_contains(opt->name,"file")){\r
77     my_string_set(&opt->type,"file");\r
78     return;\r
79   }\r
80   if(my_string_case_contains(opt->name,"path")){\r
81     my_string_set(&opt->type,"path");\r
82     return;\r
83   }\r
84 }\r
85 \r
86 // uci_set_threads()\r
87 \r
88 void uci_set_threads(uci_t * uci, int n) {\r
89     const char *thread_option=uci_thread_option(uci);\r
90     ASSERT(n>=1);\r
91     if(thread_option){\r
92         uci_send_option(uci,thread_option,"%d",n);\r
93     }\r
94 }\r
95 \r
96 \r
97 const char * uci_thread_option(uci_t * uci){\r
98     const char **p = thread_options;\r
99     const char *thread_option;\r
100     option_t *opt;\r
101     while((thread_option = *(p++))){\r
102         if((opt=option_find(uci->option,thread_option))){\r
103             return opt->name;\r
104             break;\r
105         }\r
106     }\r
107     return NULL;\r
108 }\r
109 \r
110 // uci_is_ok()\r
111 \r
112 static bool uci_is_ok(const uci_t * uci) {\r
113 \r
114    if (uci == NULL) return FALSE;\r
115    if (uci->engine == NULL) return FALSE;\r
116    if (!option_is_ok(uci->option)) return FALSE;\r
117    return TRUE;\r
118 }\r
119 \r
120 // uci_open()\r
121 \r
122 void uci_open(uci_t * uci, engine_t * engine) {\r
123 \r
124    char string[StringSize];\r
125    int event;\r
126 \r
127    ASSERT(uci!=NULL);\r
128    ASSERT(engine!=NULL);\r
129 \r
130    // init\r
131 \r
132    uci->engine = engine;\r
133 \r
134    uci->name = NULL;\r
135    my_string_set(&uci->name,"<empty>");\r
136    uci->author = NULL;\r
137    my_string_set(&uci->author,"<empty>");\r
138    option_init(uci->option);\r
139 \r
140    uci->ready_nb = 0;\r
141    uci->searching = 0;\r
142    uci->pending_nb = 0;\r
143    uci->multipv_mode = FALSE;\r
144    board_start(uci->board);\r
145    uci_clear(uci);\r
146 \r
147    // send "uci" and wait for "uciok"\r
148 \r
149    engine_send(uci->engine,"uci");\r
150 \r
151    do {\r
152       engine_get(uci->engine,string);\r
153       // Handle the case that the engine is really a WB engine somewhat gracefully.\r
154       if((strstr(string,"Illegal") || strstr(string,"Error"))\r
155          &&strstr(string,"uci")){\r
156           my_fatal("uci_open(): Not a UCI engine.\n");\r
157       }\r
158       event = uci_parse(uci,string);\r
159    } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0);\r
160 }\r
161 \r
162 // uci_close()\r
163 \r
164 void uci_close(uci_t * uci) {\r
165 \r
166    ASSERT(uci_is_ok(uci));\r
167    engine_close(uci->engine);\r
168    uci->engine = NULL;\r
169    my_string_clear(&uci->name);\r
170    my_string_clear(&uci->author);\r
171 \r
172    option_clear(uci->option);\r
173 }\r
174 \r
175 // uci_clear()\r
176 \r
177 void uci_clear(uci_t * uci) {\r
178 \r
179    ASSERT(uci_is_ok(uci));\r
180 \r
181    ASSERT(!uci->searching);\r
182 \r
183    uci->best_move = MoveNone;\r
184    uci->ponder_move = MoveNone;\r
185 \r
186    uci->score = 0;\r
187    uci->depth = 0;\r
188    uci->sel_depth = 0;\r
189    line_clear(uci->pv);\r
190 \r
191    uci->best_score = 0;\r
192    uci->best_depth = 0;\r
193    uci->best_sel_depth = 0;\r
194    line_clear(uci->best_pv);\r
195 // make the default 1 instead of 0 so that info lines can be recognized by their node number 0\r
196    uci->node_nb = 1;\r
197    uci->time = 0.0;\r
198    uci->speed = 0.0;\r
199    uci->cpu = 0.0;\r
200    uci->hash = 0.0;\r
201    line_clear(uci->current_line);\r
202 \r
203    uci->root_move = MoveNone;\r
204    uci->root_move_pos = 0;\r
205    uci->root_move_nb = board_mobility(uci->board);\r
206 \r
207    uci->multipvSP=0;\r
208 }\r
209 \r
210 // uci_send_isready()\r
211 \r
212 void uci_send_isready(uci_t * uci) {\r
213 \r
214    ASSERT(uci!=NULL);\r
215 \r
216    engine_send(uci->engine,"isready");\r
217    uci->ready_nb++;\r
218 }\r
219 \r
220 // uci_send_isready_sync()\r
221 \r
222 void uci_send_isready_sync(uci_t * uci) {\r
223 \r
224    char string[StringSize];\r
225    int event;\r
226 \r
227    ASSERT(uci_is_ok(uci));\r
228 \r
229    // send "isready" and wait for "readyok"\r
230 \r
231    uci_send_isready(uci);\r
232 \r
233    do {\r
234       engine_get(uci->engine,string);\r
235       event = uci_parse(uci,string);\r
236    } while (!engine_eof(Engine) && (event & EVENT_READY) == 0);\r
237 }\r
238 \r
239 // uci_send_stop()\r
240 \r
241 void uci_send_stop(uci_t * uci) {\r
242 \r
243    ASSERT(uci_is_ok(uci));\r
244 \r
245    ASSERT(uci->searching);\r
246    ASSERT(uci->pending_nb>=1);\r
247 \r
248    engine_send(Engine,"stop");\r
249    uci->searching = FALSE;\r
250 }\r
251 \r
252 // uci_send_stop_sync()\r
253 \r
254 void uci_send_stop_sync(uci_t * uci) {\r
255 \r
256    char string[StringSize];\r
257    int event;\r
258 \r
259    ASSERT(uci_is_ok(uci));\r
260 \r
261    ASSERT(uci->searching);\r
262    ASSERT(uci->pending_nb>=1);\r
263 \r
264    // send "stop" and wait for "bestmove"\r
265 \r
266    uci_send_stop(uci);\r
267 \r
268    do {\r
269       engine_get(uci->engine,string);\r
270       event = uci_parse(uci,string);\r
271    } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0);\r
272 }\r
273 \r
274 // uci_send_ucinewgame()\r
275 \r
276 void uci_send_ucinewgame(uci_t * uci) {\r
277 \r
278    ASSERT(uci!=NULL);\r
279 \r
280    if (option_get_int(Option,"UCIVersion") >= 2) {\r
281       engine_send(uci->engine,"ucinewgame");\r
282    }\r
283 }\r
284 \r
285 // uci_send_option()\r
286 \r
287 bool uci_send_option(uci_t * uci, const char option[], const char format[], ...) {\r
288 \r
289    char value[FormatBufferSize];\r
290    option_t * opt;\r
291    bool found=FALSE;\r
292 \r
293    ASSERT(uci_is_ok(uci));\r
294    ASSERT(option!=NULL);\r
295    ASSERT(format!=NULL);\r
296 \r
297    // format\r
298 \r
299    CONSTRUCT_ARG_STRING(format,value);\r
300 \r
301    if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value);\r
302 \r
303    opt=option_find(uci->option,option);\r
304    if(opt){\r
305        found=TRUE;\r
306        if(!IS_BUTTON(opt->type)){\r
307            if(!my_string_equal(opt->value,value)){\r
308                engine_send(uci->engine,"setoption name %s value %s",\r
309                            opt->name,value);\r
310                my_string_set(&opt->value,value);\r
311            }else{\r
312                my_log("POLYGLOT Not sending option \"%s\" since it "\r
313                       "already has the correct value.\n",opt->name);\r
314            }\r
315        }else{\r
316            engine_send(uci->engine,"setoption name %s",opt->name);\r
317        }\r
318    }\r
319    return found;\r
320 }\r
321 \r
322 // uci_parse()\r
323 \r
324 int uci_parse(uci_t * uci, const char string[]) {\r
325 \r
326    int event;\r
327    parse_t parse[1];\r
328    char command[StringSize];\r
329    char argument[StringSize];\r
330 \r
331    ASSERT(uci_is_ok(uci));\r
332    ASSERT(string!=NULL);\r
333 \r
334    // init\r
335 \r
336    event = EVENT_NONE;\r
337 \r
338    // parse\r
339 \r
340    parse_open(parse,string);\r
341 \r
342    if (parse_get_word(parse,command,StringSize)) {\r
343        \r
344       parse_get_string(parse,argument,StringSize);\r
345       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument);\r
346 \r
347       if (FALSE) {\r
348 \r
349       } else if (my_string_equal(command,"bestmove")) {\r
350 \r
351          // search end\r
352 \r
353          ASSERT(uci->pending_nb>0);\r
354 \r
355          if (uci->searching && uci->pending_nb == 1) {\r
356 \r
357             // current search\r
358 \r
359             uci->searching = FALSE;\r
360             uci->pending_nb--;\r
361 \r
362             event = parse_bestmove(uci,argument); // updates uci->best_move and uci->ponder_move\r
363 \r
364          } else {\r
365 \r
366             // obsolete search\r
367 \r
368             if (uci->pending_nb > 0) {\r
369                uci->pending_nb--;\r
370                if (uci->pending_nb == 0) event = EVENT_STOP;\r
371             }\r
372          }\r
373 \r
374       } else if (my_string_equal(command,"id")) {\r
375 \r
376          parse_id(uci,argument);\r
377 \r
378       } else if (my_string_equal(command,"info")) {\r
379 \r
380          // search information\r
381 \r
382               if (uci->searching && uci->pending_nb == 1) { // current search\r
383                   event = parse_info(uci,argument);\r
384                }\r
385 \r
386       } else if (my_string_equal(command,"option")) {\r
387 \r
388          parse_option(uci,argument);\r
389 \r
390       } else if (my_string_equal(command,"readyok")) {\r
391 \r
392          // engine is ready\r
393 \r
394          ASSERT(uci->ready_nb>0);\r
395 \r
396          if (uci->ready_nb > 0) {\r
397             uci->ready_nb--;\r
398             if (uci->ready_nb == 0) event = EVENT_READY;\r
399          }\r
400 \r
401       } else if (my_string_equal(command,"uciok")) {\r
402 \r
403          event = EVENT_UCI;\r
404 \r
405       } else {\r
406 \r
407          if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command);\r
408       }\r
409    }\r
410 \r
411    parse_close(parse);\r
412 \r
413    return event;\r
414 }\r
415 \r
416 // parse_bestmove()\r
417 \r
418 static int parse_bestmove(uci_t * uci, const char string[]) {\r
419 \r
420    parse_t parse[1];\r
421    char command[StringSize];\r
422    char option[StringSize];\r
423    char argument[StringSize];\r
424    board_t board[1];\r
425 \r
426    ASSERT(uci_is_ok(uci));\r
427    ASSERT(string!=NULL);\r
428 \r
429    // init\r
430 \r
431    strcpy(command,"bestmove");\r
432 \r
433    parse_open(parse,string);\r
434    parse_add_keyword(parse,"ponder");\r
435 \r
436    // bestmove\r
437 \r
438    uci->bestmove[0]='\0';\r
439    if (!parse_get_string(parse,argument,StringSize)) {\r
440        strcpy(uci->bestmove,"nomove");\r
441        return EVENT_ILLEGAL_MOVE;\r
442 //      my_fatal("parse_bestmove(): missing argument\n");\r
443    }\r
444    strncpy(uci->bestmove,argument,UciStringSize);\r
445    uci->bestmove[UciStringSize-1]='\0';\r
446 \r
447    uci->best_move = move_from_can(argument,uci->board);\r
448    if (uci->best_move == MoveNone) {\r
449        return EVENT_ILLEGAL_MOVE;\r
450 //       my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
451    }\r
452 \r
453    if(!move_is_legal(uci->best_move,uci->board)){\r
454        return EVENT_ILLEGAL_MOVE;\r
455    }\r
456    ASSERT(uci->best_move!=MoveNone);\r
457    ASSERT(move_is_legal(uci->best_move,uci->board));\r
458 \r
459    // loop\r
460 \r
461    while (parse_get_word(parse,option,StringSize)) {\r
462 \r
463       parse_get_string(parse,argument,StringSize);\r
464 \r
465       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
466 \r
467       if (FALSE) {\r
468 \r
469       } else if (my_string_equal(option,"ponder")) {\r
470 \r
471          ASSERT(!my_string_empty(argument));\r
472 \r
473          board_copy(board,uci->board);\r
474          move_do(board,uci->best_move);\r
475 \r
476          uci->ponder_move = move_from_can(argument,board);\r
477          // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
478 \r
479          ASSERT(uci->ponder_move!=MoveNone);\r
480          ASSERT(move_is_legal(uci->ponder_move,board));\r
481 \r
482       } else {\r
483 \r
484          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
485       }\r
486    }\r
487 \r
488    parse_close(parse);\r
489 \r
490    return EVENT_MOVE;\r
491 }\r
492 \r
493 // parse_id()\r
494 \r
495 static void parse_id(uci_t * uci, const char string[]) {\r
496 \r
497    parse_t parse[1];\r
498    char command[StringSize];\r
499    char option[StringSize];\r
500    char argument[StringSize];\r
501 \r
502    ASSERT(uci!=NULL);\r
503    ASSERT(string!=NULL);\r
504 \r
505    // init\r
506 \r
507    strcpy(command,"id");\r
508 \r
509    parse_open(parse,string);\r
510    parse_add_keyword(parse,"author");\r
511    parse_add_keyword(parse,"name");\r
512 \r
513    // loop\r
514 \r
515    while (parse_get_word(parse,option,StringSize)) {\r
516 \r
517       parse_get_string(parse,argument,StringSize);\r
518       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
519 \r
520       if (FALSE) {\r
521       } else if (my_string_equal(option,"author")) {\r
522          ASSERT(!my_string_empty(argument));\r
523          my_string_set(&uci->author,argument);\r
524       } else if (my_string_equal(option,"name")) {\r
525          ASSERT(!my_string_empty(argument));\r
526          my_string_set(&uci->name,argument);\r
527       } else {\r
528          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
529       }\r
530    }\r
531 \r
532    parse_close(parse);\r
533 \r
534    if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author);\r
535 }\r
536 \r
537 // parse_info()\r
538 \r
539 static int parse_info(uci_t * uci, const char string[]) {\r
540 \r
541    int event;\r
542    parse_t parse[1];\r
543    char command[StringSize];\r
544    char option[StringSize];\r
545    char argument[StringSize];\r
546    int n;\r
547    int multipvline=0;\r
548    sint64 ln;\r
549 \r
550 \r
551    \r
552    ASSERT(uci_is_ok(uci));\r
553    ASSERT(string!=NULL);\r
554 \r
555    // init\r
556 \r
557    event = EVENT_NONE;\r
558 \r
559    strcpy(command,"info");\r
560 \r
561    parse_open(parse,string);\r
562    parse_add_keyword(parse,"cpuload");\r
563    parse_add_keyword(parse,"currline");\r
564    parse_add_keyword(parse,"currmove");\r
565    parse_add_keyword(parse,"currmovenumber");\r
566    parse_add_keyword(parse,"depth");\r
567    parse_add_keyword(parse,"hashfull");\r
568    parse_add_keyword(parse,"multipv");\r
569    parse_add_keyword(parse,"nodes");\r
570    parse_add_keyword(parse,"nps");\r
571    parse_add_keyword(parse,"pv");\r
572    parse_add_keyword(parse,"refutation");\r
573    parse_add_keyword(parse,"score");\r
574    parse_add_keyword(parse,"seldepth");\r
575    parse_add_keyword(parse,"string");\r
576    parse_add_keyword(parse,"tbhits");\r
577    parse_add_keyword(parse,"time");\r
578 \r
579    // loop\r
580 \r
581    while (parse_get_word(parse,option,StringSize)) {\r
582 \r
583       parse_get_string(parse,argument,StringSize);\r
584 \r
585       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
586 \r
587       if (FALSE) {\r
588 \r
589       } else if (my_string_equal(option,"cpuload")) {\r
590 \r
591          ASSERT(!my_string_empty(argument));\r
592 \r
593          n = atoi(argument);\r
594          ASSERT(n>=0);\r
595 \r
596          if (n >= 0) uci->cpu = ((double)n) / 1000.0;\r
597 \r
598       } else if (my_string_equal(option,"currline")) {\r
599 \r
600          ASSERT(!my_string_empty(argument));\r
601 \r
602          line_from_can(uci->current_line,uci->board,argument,LineSize);\r
603 \r
604       } else if (my_string_equal(option,"currmove")) {\r
605 \r
606          ASSERT(!my_string_empty(argument));\r
607 \r
608          uci->root_move = move_from_can(argument,uci->board);\r
609          ASSERT(uci->root_move!=MoveNone);\r
610 \r
611       } else if (my_string_equal(option,"currmovenumber")) {\r
612 \r
613          ASSERT(!my_string_empty(argument));\r
614 \r
615          n = atoi(argument);\r
616          ASSERT(n>=1&&n<=uci->root_move_nb);\r
617 \r
618          if (n >= 1 && n <= uci->root_move_nb) {\r
619             uci->root_move_pos = n - 1;\r
620             ASSERT(uci->root_move_pos>=0&&uci->root_move_pos<uci->root_move_nb);\r
621          }\r
622 \r
623       } else if (my_string_equal(option,"depth")) {\r
624 \r
625          ASSERT(!my_string_empty(argument));\r
626 \r
627          n = atoi(argument);\r
628          ASSERT(n>=1);\r
629 \r
630          if (n >= 0) {\r
631             if (n > uci->depth) event |= EVENT_DEPTH;\r
632             uci->depth = n;\r
633          }\r
634 \r
635       } else if (my_string_equal(option,"hashfull")) {\r
636 \r
637          ASSERT(!my_string_empty(argument));\r
638 \r
639          n = atoi(argument);\r
640          ASSERT(n>=0);\r
641 \r
642          if (n >= 0) uci->hash = ((double)n) / 1000.0;\r
643 \r
644       } else if (my_string_equal(option,"multipv")) {\r
645 \r
646          ASSERT(!my_string_empty(argument));\r
647 \r
648          n = atoi(argument);\r
649          multipvline=n;\r
650         \r
651          ASSERT(n>=1);\r
652 \r
653       } else if (my_string_equal(option,"nodes")) {\r
654 \r
655          ASSERT(!my_string_empty(argument));\r
656 \r
657          ln = my_atoll(argument);\r
658          ASSERT(ln>=0);\r
659 \r
660          if (ln >= 0) uci->node_nb = ln;\r
661 \r
662       } else if (my_string_equal(option,"nps")) {\r
663 \r
664          ASSERT(!my_string_empty(argument));\r
665 \r
666          n = atoi(argument);\r
667          ASSERT(n>=0);\r
668 \r
669          if (n >= 0) uci->speed = ((double)n);\r
670 \r
671       } else if (my_string_equal(option,"pv")) {\r
672 \r
673          ASSERT(!my_string_empty(argument));\r
674 \r
675          line_from_can(uci->pv,uci->board,argument,LineSize);\r
676          event |= EVENT_PV;\r
677 \r
678       } else if (my_string_equal(option,"refutation")) {\r
679 \r
680          ASSERT(!my_string_empty(argument));\r
681 \r
682          line_from_can(uci->pv,uci->board,argument,LineSize);\r
683 \r
684       } else if (my_string_equal(option,"score")) {\r
685 \r
686          ASSERT(!my_string_empty(argument));\r
687 \r
688          parse_score(uci,argument);\r
689 \r
690       } else if (my_string_equal(option,"seldepth")) {\r
691 \r
692          ASSERT(!my_string_empty(argument));\r
693 \r
694          n = atoi(argument);\r
695          ASSERT(n>=0);\r
696 \r
697          if (n >= 0) uci->sel_depth = n;\r
698 \r
699       } else  if (my_string_equal(option,"string")) {\r
700                   if(my_string_case_equal(argument,"DrawOffer")){\r
701                           event |= EVENT_DRAW;\r
702           }else if(my_string_case_equal(argument,"Resign")){\r
703                           event |= EVENT_RESIGN;\r
704           }else{\r
705               snprintf(uci->info,sizeof(uci->info),"%s",argument);\r
706               uci->info[sizeof(uci->info)-1]='\0';\r
707               event|=EVENT_INFO;\r
708           }\r
709          // TODO: argument to EOS\r
710 \r
711          ASSERT(!my_string_empty(argument));\r
712 \r
713       } else if (my_string_equal(option,"tbhits")) {\r
714 \r
715          ASSERT(!my_string_empty(argument));\r
716 \r
717          ln = my_atoll(argument);\r
718          ASSERT(ln>=0);\r
719 \r
720       } else if (my_string_equal(option,"time")) {\r
721 \r
722          ASSERT(!my_string_empty(argument));\r
723 \r
724          n = atoi(argument);\r
725          ASSERT(n>=0);\r
726 \r
727          if (n >= 0) uci->time = ((double)n) / 1000.0;\r
728 \r
729       } else {\r
730 \r
731          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
732              // This should probably be protected\r
733              // by a "WorkAround" option.\r
734          snprintf(uci->info,sizeof(uci->info),"%s %s",option,argument);\r
735          uci->info[sizeof(uci->info)-1]='\0';\r
736          event|=EVENT_INFO;\r
737       }\r
738    }\r
739 \r
740    parse_close(parse);\r
741 \r
742 \r
743    // code by HGM\r
744    if ((event & EVENT_PV) != 0) {\r
745       uci->best_score = uci->score; \r
746       uci->best_sel_depth = uci->sel_depth;\r
747       line_copy(uci->best_pv,uci->pv);\r
748    }\r
749    if(uci->depth < uci->best_depth){\r
750      // ignore lines of lower depth\r
751      event &= ~EVENT_PV;\r
752    } else {\r
753      if(uci->depth > uci->best_depth) {\r
754        // clear stack when we start new depth\r
755        uci->multipvSP = 0; \r
756      }\r
757      uci->best_depth = uci->depth;\r
758      if(multipvline >= 1) {\r
759        int i;\r
760        for(i=0; i<uci->multipvSP; i++) {\r
761          if(uci->score == uci->multipvScore[i] && uci->pv[0] == uci->multipvMove[i]) {\r
762            event &= ~EVENT_PV; // ignore duplicates\r
763          }\r
764        }\r
765        if(event & EVENT_PV){\r
766          // line is new, try to add to stack\r
767          if(uci->multipvSP<MultiPVStackSize){\r
768            uci->multipvMove[uci->multipvSP] = uci->pv[0];\r
769            uci->multipvScore[uci->multipvSP] = uci->score;\r
770            uci->multipvSP++;\r
771          }else{\r
772            my_fatal("parse_info(): multipv stack overflow.");\r
773          }\r
774        }\r
775      }\r
776    }\r
777 \r
778 \r
779    return event;\r
780 }\r
781 \r
782 // parse_option()\r
783 \r
784 static void parse_option(uci_t * uci, const char string[]) {\r
785 \r
786    option_t opt[1];\r
787    parse_t parse[1];\r
788    char command[StringSize];\r
789    char option[StringSize];\r
790    char argument[StringSize];\r
791 \r
792    ASSERT(uci!=NULL);\r
793    ASSERT(string!=NULL);\r
794 \r
795    // init\r
796 \r
797    strcpy(command,"option");\r
798 \r
799    memset(opt,0,sizeof(option_t));\r
800    \r
801    my_string_set(&opt->value,"<empty>");\r
802    my_string_set(&opt->name,"<empty>");\r
803    my_string_set(&opt->default_,"<empty>");\r
804    my_string_set(&opt->max,"<empty>");\r
805    my_string_set(&opt->min,"<empty>");\r
806    my_string_set(&opt->type,"<empty>");\r
807    opt->var_nb=0;\r
808    opt->mode=0;\r
809    \r
810    parse_open(parse,string);\r
811    parse_add_keyword(parse,"default");\r
812    parse_add_keyword(parse,"max");\r
813    parse_add_keyword(parse,"min");\r
814    parse_add_keyword(parse,"name");\r
815    parse_add_keyword(parse,"type");\r
816    parse_add_keyword(parse,"var");\r
817 \r
818    // loop\r
819 \r
820    while (parse_get_word(parse,option,StringSize)) {\r
821       parse_get_string(parse,argument,StringSize);\r
822       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
823 \r
824       if (FALSE) {\r
825 \r
826       } else if (my_string_equal(option,"default")) {\r
827 \r
828          // ASSERT(!my_string_empty(argument)); // HACK for Pepito\r
829 \r
830          if (!my_string_empty(argument)) {\r
831             my_string_set(&opt->default_,argument);\r
832             my_string_set(&opt->value,argument);\r
833          }\r
834 \r
835       } else if (my_string_equal(option,"max")) {\r
836 \r
837          ASSERT(!my_string_empty(argument));\r
838          my_string_set(&opt->max,argument);\r
839 \r
840       } else if (my_string_equal(option,"min")) {\r
841 \r
842          ASSERT(!my_string_empty(argument));\r
843          my_string_set(&opt->min,argument);\r
844 \r
845       } else if (my_string_equal(option,"name")) {\r
846 \r
847          ASSERT(!my_string_empty(argument));\r
848 \r
849          if (!my_string_empty(argument)) {\r
850             my_string_set(&opt->name,argument);\r
851          }\r
852 \r
853       } else if (my_string_equal(option,"type")) {\r
854 \r
855          ASSERT(!my_string_empty(argument));\r
856          my_string_set(&opt->type,argument);\r
857 \r
858       } else if (my_string_equal(option,"var")) {\r
859 \r
860          ASSERT(!my_string_empty(argument));\r
861          my_string_set(&opt->var[opt->var_nb++],argument);\r
862          if(opt->var_nb==VarNb) break;\r
863 \r
864       } else {\r
865 \r
866          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
867       }\r
868    }\r
869 \r
870    parse_close(parse);\r
871 \r
872    apply_UCI3_heuristics(opt);\r
873    option_insert(uci->option,opt);\r
874    option_free(opt);\r
875 \r
876    if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_);\r
877 }\r
878 \r
879 // parse_score()\r
880 \r
881 static void parse_score(uci_t * uci, const char string[]) {\r
882 \r
883    parse_t parse[1];\r
884    char command[StringSize];\r
885    char option[StringSize];\r
886    char argument[StringSize];\r
887    int n;\r
888 \r
889    ASSERT(uci_is_ok(uci));\r
890    ASSERT(string!=NULL);\r
891 \r
892    // init\r
893 \r
894    strcpy(command,"score");\r
895 \r
896    parse_open(parse,string);\r
897    parse_add_keyword(parse,"cp");\r
898    parse_add_keyword(parse,"lowerbound");\r
899    parse_add_keyword(parse,"mate");\r
900    parse_add_keyword(parse,"upperbound");\r
901 \r
902    // loop\r
903 \r
904    while (parse_get_word(parse,option,StringSize)) {\r
905 \r
906       parse_get_string(parse,argument,StringSize);\r
907 \r
908       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
909 \r
910       if (FALSE) {\r
911 \r
912       } else if (my_string_equal(option,"cp")) {\r
913 \r
914          ASSERT(!my_string_empty(argument));\r
915 \r
916          n = atoi(argument);\r
917 \r
918          uci->score = n;\r
919 \r
920       } else if (my_string_equal(option,"lowerbound")) {\r
921 \r
922          ASSERT(my_string_empty(argument));\r
923 \r
924       } else if (my_string_equal(option,"mate")) {\r
925 \r
926          ASSERT(!my_string_empty(argument));\r
927 \r
928          n = atoi(argument);\r
929          ASSERT(n!=0);\r
930 \r
931          uci->score = mate_score(n);\r
932 \r
933       } else if (my_string_equal(option,"upperbound")) {\r
934 \r
935          ASSERT(my_string_empty(argument));\r
936 \r
937       } else {\r
938 \r
939          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
940       }\r
941    }\r
942 \r
943    parse_close(parse);\r
944 }\r
945 \r
946 // mate_score()\r
947 \r
948 static int mate_score(int dist) {\r
949 \r
950    ASSERT(dist!=0);\r
951 \r
952    if (FALSE) {\r
953    } else if (dist > 0) {\r
954        return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1;\r
955    } else if (dist < 0) {\r
956        return -option_get_int(Option,"MateScore") + (-dist) * 2;\r
957    }\r
958 \r
959    return 0;\r
960 }\r
961 \r
962 // end of uci.cpp\r
963 \r