version 1.4.56b
[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 an 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    if (!parse_get_string(parse,argument,StringSize)) {\r
439        return EVENT_ILLEGAL_MOVE;\r
440 //      my_fatal("parse_bestmove(): missing argument\n");\r
441    }\r
442 \r
443    uci->best_move = move_from_can(argument,uci->board);\r
444    if (uci->best_move == MoveNone) {\r
445        return EVENT_ILLEGAL_MOVE;\r
446 //       my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
447    }\r
448 \r
449    if(!move_is_legal(uci->best_move,uci->board)){\r
450        return EVENT_ILLEGAL_MOVE;\r
451    }\r
452    ASSERT(uci->best_move!=MoveNone);\r
453    ASSERT(move_is_legal(uci->best_move,uci->board));\r
454 \r
455    // loop\r
456 \r
457    while (parse_get_word(parse,option,StringSize)) {\r
458 \r
459       parse_get_string(parse,argument,StringSize);\r
460 \r
461       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
462 \r
463       if (FALSE) {\r
464 \r
465       } else if (my_string_equal(option,"ponder")) {\r
466 \r
467          ASSERT(!my_string_empty(argument));\r
468 \r
469          board_copy(board,uci->board);\r
470          move_do(board,uci->best_move);\r
471 \r
472          uci->ponder_move = move_from_can(argument,board);\r
473          // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
474 \r
475          ASSERT(uci->ponder_move!=MoveNone);\r
476          ASSERT(move_is_legal(uci->ponder_move,board));\r
477 \r
478       } else {\r
479 \r
480          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
481       }\r
482    }\r
483 \r
484    parse_close(parse);\r
485 \r
486    return EVENT_MOVE;\r
487 }\r
488 \r
489 // parse_id()\r
490 \r
491 static void parse_id(uci_t * uci, const char string[]) {\r
492 \r
493    parse_t parse[1];\r
494    char command[StringSize];\r
495    char option[StringSize];\r
496    char argument[StringSize];\r
497 \r
498    ASSERT(uci!=NULL);\r
499    ASSERT(string!=NULL);\r
500 \r
501    // init\r
502 \r
503    strcpy(command,"id");\r
504 \r
505    parse_open(parse,string);\r
506    parse_add_keyword(parse,"author");\r
507    parse_add_keyword(parse,"name");\r
508 \r
509    // loop\r
510 \r
511    while (parse_get_word(parse,option,StringSize)) {\r
512 \r
513       parse_get_string(parse,argument,StringSize);\r
514       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
515 \r
516       if (FALSE) {\r
517       } else if (my_string_equal(option,"author")) {\r
518          ASSERT(!my_string_empty(argument));\r
519          my_string_set(&uci->author,argument);\r
520       } else if (my_string_equal(option,"name")) {\r
521          ASSERT(!my_string_empty(argument));\r
522          my_string_set(&uci->name,argument);\r
523       } else {\r
524          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
525       }\r
526    }\r
527 \r
528    parse_close(parse);\r
529 \r
530    if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author);\r
531 }\r
532 \r
533 // parse_info()\r
534 \r
535 static int parse_info(uci_t * uci, const char string[]) {\r
536 \r
537    int event;\r
538    parse_t parse[1];\r
539    char command[StringSize];\r
540    char option[StringSize];\r
541    char argument[StringSize];\r
542    int n;\r
543    int multipvline=0;\r
544    sint64 ln;\r
545 \r
546 \r
547    \r
548    ASSERT(uci_is_ok(uci));\r
549    ASSERT(string!=NULL);\r
550 \r
551    // init\r
552 \r
553    event = EVENT_NONE;\r
554 \r
555    strcpy(command,"info");\r
556 \r
557    parse_open(parse,string);\r
558    parse_add_keyword(parse,"cpuload");\r
559    parse_add_keyword(parse,"currline");\r
560    parse_add_keyword(parse,"currmove");\r
561    parse_add_keyword(parse,"currmovenumber");\r
562    parse_add_keyword(parse,"depth");\r
563    parse_add_keyword(parse,"hashfull");\r
564    parse_add_keyword(parse,"multipv");\r
565    parse_add_keyword(parse,"nodes");\r
566    parse_add_keyword(parse,"nps");\r
567    parse_add_keyword(parse,"pv");\r
568    parse_add_keyword(parse,"refutation");\r
569    parse_add_keyword(parse,"score");\r
570    parse_add_keyword(parse,"seldepth");\r
571    parse_add_keyword(parse,"string");\r
572    parse_add_keyword(parse,"tbhits");\r
573    parse_add_keyword(parse,"time");\r
574 \r
575    // loop\r
576 \r
577    while (parse_get_word(parse,option,StringSize)) {\r
578 \r
579       parse_get_string(parse,argument,StringSize);\r
580 \r
581       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
582 \r
583       if (FALSE) {\r
584 \r
585       } else if (my_string_equal(option,"cpuload")) {\r
586 \r
587          ASSERT(!my_string_empty(argument));\r
588 \r
589          n = atoi(argument);\r
590          ASSERT(n>=0);\r
591 \r
592          if (n >= 0) uci->cpu = ((double)n) / 1000.0;\r
593 \r
594       } else if (my_string_equal(option,"currline")) {\r
595 \r
596          ASSERT(!my_string_empty(argument));\r
597 \r
598          line_from_can(uci->current_line,uci->board,argument,LineSize);\r
599 \r
600       } else if (my_string_equal(option,"currmove")) {\r
601 \r
602          ASSERT(!my_string_empty(argument));\r
603 \r
604          uci->root_move = move_from_can(argument,uci->board);\r
605          ASSERT(uci->root_move!=MoveNone);\r
606 \r
607       } else if (my_string_equal(option,"currmovenumber")) {\r
608 \r
609          ASSERT(!my_string_empty(argument));\r
610 \r
611          n = atoi(argument);\r
612          ASSERT(n>=1&&n<=uci->root_move_nb);\r
613 \r
614          if (n >= 1 && n <= uci->root_move_nb) {\r
615             uci->root_move_pos = n - 1;\r
616             ASSERT(uci->root_move_pos>=0&&uci->root_move_pos<uci->root_move_nb);\r
617          }\r
618 \r
619       } else if (my_string_equal(option,"depth")) {\r
620 \r
621          ASSERT(!my_string_empty(argument));\r
622 \r
623          n = atoi(argument);\r
624          ASSERT(n>=1);\r
625 \r
626          if (n >= 0) {\r
627             if (n > uci->depth) event |= EVENT_DEPTH;\r
628             uci->depth = n;\r
629          }\r
630 \r
631       } else if (my_string_equal(option,"hashfull")) {\r
632 \r
633          ASSERT(!my_string_empty(argument));\r
634 \r
635          n = atoi(argument);\r
636          ASSERT(n>=0);\r
637 \r
638          if (n >= 0) uci->hash = ((double)n) / 1000.0;\r
639 \r
640       } else if (my_string_equal(option,"multipv")) {\r
641 \r
642          ASSERT(!my_string_empty(argument));\r
643 \r
644          n = atoi(argument);\r
645          multipvline=n;\r
646         \r
647          ASSERT(n>=1);\r
648 \r
649       } else if (my_string_equal(option,"nodes")) {\r
650 \r
651          ASSERT(!my_string_empty(argument));\r
652 \r
653          ln = my_atoll(argument);\r
654          ASSERT(ln>=0);\r
655 \r
656          if (ln >= 0) uci->node_nb = ln;\r
657 \r
658       } else if (my_string_equal(option,"nps")) {\r
659 \r
660          ASSERT(!my_string_empty(argument));\r
661 \r
662          n = atoi(argument);\r
663          ASSERT(n>=0);\r
664 \r
665          if (n >= 0) uci->speed = ((double)n);\r
666 \r
667       } else if (my_string_equal(option,"pv")) {\r
668 \r
669          ASSERT(!my_string_empty(argument));\r
670 \r
671          line_from_can(uci->pv,uci->board,argument,LineSize);\r
672          event |= EVENT_PV;\r
673 \r
674       } else if (my_string_equal(option,"refutation")) {\r
675 \r
676          ASSERT(!my_string_empty(argument));\r
677 \r
678          line_from_can(uci->pv,uci->board,argument,LineSize);\r
679 \r
680       } else if (my_string_equal(option,"score")) {\r
681 \r
682          ASSERT(!my_string_empty(argument));\r
683 \r
684          parse_score(uci,argument);\r
685 \r
686       } else if (my_string_equal(option,"seldepth")) {\r
687 \r
688          ASSERT(!my_string_empty(argument));\r
689 \r
690          n = atoi(argument);\r
691          ASSERT(n>=0);\r
692 \r
693          if (n >= 0) uci->sel_depth = n;\r
694 \r
695       } else  if (my_string_equal(option,"string")) {\r
696                   if(my_string_case_equal(argument,"DrawOffer")){\r
697                           event |= EVENT_DRAW;\r
698           }else if(my_string_case_equal(argument,"Resign")){\r
699                           event |= EVENT_RESIGN;\r
700           }else{\r
701               snprintf(uci->info,sizeof(uci->info),"%s",argument);\r
702               uci->info[sizeof(uci->info)-1]='\0';\r
703               event|=EVENT_INFO;\r
704           }\r
705          // TODO: argument to EOS\r
706 \r
707          ASSERT(!my_string_empty(argument));\r
708 \r
709       } else if (my_string_equal(option,"tbhits")) {\r
710 \r
711          ASSERT(!my_string_empty(argument));\r
712 \r
713          ln = my_atoll(argument);\r
714          ASSERT(ln>=0);\r
715 \r
716       } else if (my_string_equal(option,"time")) {\r
717 \r
718          ASSERT(!my_string_empty(argument));\r
719 \r
720          n = atoi(argument);\r
721          ASSERT(n>=0);\r
722 \r
723          if (n >= 0) uci->time = ((double)n) / 1000.0;\r
724 \r
725       } else {\r
726 \r
727          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
728              // This should probably be protected\r
729              // by a "WorkAround" option.\r
730          snprintf(uci->info,sizeof(uci->info),"%s %s",option,argument);\r
731          uci->info[sizeof(uci->info)-1]='\0';\r
732          event|=EVENT_INFO;\r
733       }\r
734    }\r
735 \r
736    parse_close(parse);\r
737 \r
738 \r
739    // code by HGM\r
740    if ((event & EVENT_PV) != 0) {\r
741       uci->best_score = uci->score; \r
742       uci->best_sel_depth = uci->sel_depth;\r
743       line_copy(uci->best_pv,uci->pv);\r
744    }\r
745    if(uci->depth < uci->best_depth){\r
746      // ignore lines of lower depth\r
747      event &= ~EVENT_PV;\r
748    } else {\r
749      if(uci->depth > uci->best_depth) {\r
750        // clear stack when we start new depth\r
751        uci->multipvSP = 0; \r
752      }\r
753      uci->best_depth = uci->depth;\r
754      if(multipvline >= 1) {\r
755        int i;\r
756        for(i=0; i<uci->multipvSP; i++) {\r
757          if(uci->score == uci->multipvScore[i] && uci->pv[0] == uci->multipvMove[i]) {\r
758            event &= ~EVENT_PV; // ignore duplicates\r
759          }\r
760        }\r
761        if(event & EVENT_PV){\r
762          // line is new, try to add to stack\r
763          if(uci->multipvSP<MultiPVStackSize){\r
764            uci->multipvMove[uci->multipvSP] = uci->pv[0];\r
765            uci->multipvScore[uci->multipvSP] = uci->score;\r
766            uci->multipvSP++;\r
767          }else{\r
768            my_fatal("parse_info(): multipv stack overflow.");\r
769          }\r
770        }\r
771      }\r
772    }\r
773 \r
774 \r
775    return event;\r
776 }\r
777 \r
778 // parse_option()\r
779 \r
780 static void parse_option(uci_t * uci, const char string[]) {\r
781 \r
782    option_t opt[1];\r
783    parse_t parse[1];\r
784    char command[StringSize];\r
785    char option[StringSize];\r
786    char argument[StringSize];\r
787 \r
788    ASSERT(uci!=NULL);\r
789    ASSERT(string!=NULL);\r
790 \r
791    // init\r
792 \r
793    strcpy(command,"option");\r
794 \r
795    memset(opt,0,sizeof(option_t));\r
796    \r
797    my_string_set(&opt->value,"<empty>");\r
798    my_string_set(&opt->name,"<empty>");\r
799    my_string_set(&opt->default_,"<empty>");\r
800    my_string_set(&opt->max,"<empty>");\r
801    my_string_set(&opt->min,"<empty>");\r
802    my_string_set(&opt->type,"<empty>");\r
803    opt->var_nb=0;\r
804    opt->mode=0;\r
805    \r
806    parse_open(parse,string);\r
807    parse_add_keyword(parse,"default");\r
808    parse_add_keyword(parse,"max");\r
809    parse_add_keyword(parse,"min");\r
810    parse_add_keyword(parse,"name");\r
811    parse_add_keyword(parse,"type");\r
812    parse_add_keyword(parse,"var");\r
813 \r
814    // loop\r
815 \r
816    while (parse_get_word(parse,option,StringSize)) {\r
817       parse_get_string(parse,argument,StringSize);\r
818       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
819 \r
820       if (FALSE) {\r
821 \r
822       } else if (my_string_equal(option,"default")) {\r
823 \r
824          // ASSERT(!my_string_empty(argument)); // HACK for Pepito\r
825 \r
826          if (!my_string_empty(argument)) {\r
827             my_string_set(&opt->default_,argument);\r
828             my_string_set(&opt->value,argument);\r
829          }\r
830 \r
831       } else if (my_string_equal(option,"max")) {\r
832 \r
833          ASSERT(!my_string_empty(argument));\r
834          my_string_set(&opt->max,argument);\r
835 \r
836       } else if (my_string_equal(option,"min")) {\r
837 \r
838          ASSERT(!my_string_empty(argument));\r
839          my_string_set(&opt->min,argument);\r
840 \r
841       } else if (my_string_equal(option,"name")) {\r
842 \r
843          ASSERT(!my_string_empty(argument));\r
844 \r
845          if (!my_string_empty(argument)) {\r
846             my_string_set(&opt->name,argument);\r
847          }\r
848 \r
849       } else if (my_string_equal(option,"type")) {\r
850 \r
851          ASSERT(!my_string_empty(argument));\r
852          my_string_set(&opt->type,argument);\r
853 \r
854       } else if (my_string_equal(option,"var")) {\r
855 \r
856          ASSERT(!my_string_empty(argument));\r
857          my_string_set(&opt->var[opt->var_nb++],argument);\r
858          if(opt->var_nb==VarNb) break;\r
859 \r
860       } else {\r
861 \r
862          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
863       }\r
864    }\r
865 \r
866    parse_close(parse);\r
867 \r
868    apply_UCI3_heuristics(opt);\r
869    option_insert(uci->option,opt);\r
870    option_free(opt);\r
871 \r
872    if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_);\r
873 }\r
874 \r
875 // parse_score()\r
876 \r
877 static void parse_score(uci_t * uci, const char string[]) {\r
878 \r
879    parse_t parse[1];\r
880    char command[StringSize];\r
881    char option[StringSize];\r
882    char argument[StringSize];\r
883    int n;\r
884 \r
885    ASSERT(uci_is_ok(uci));\r
886    ASSERT(string!=NULL);\r
887 \r
888    // init\r
889 \r
890    strcpy(command,"score");\r
891 \r
892    parse_open(parse,string);\r
893    parse_add_keyword(parse,"cp");\r
894    parse_add_keyword(parse,"lowerbound");\r
895    parse_add_keyword(parse,"mate");\r
896    parse_add_keyword(parse,"upperbound");\r
897 \r
898    // loop\r
899 \r
900    while (parse_get_word(parse,option,StringSize)) {\r
901 \r
902       parse_get_string(parse,argument,StringSize);\r
903 \r
904       if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
905 \r
906       if (FALSE) {\r
907 \r
908       } else if (my_string_equal(option,"cp")) {\r
909 \r
910          ASSERT(!my_string_empty(argument));\r
911 \r
912          n = atoi(argument);\r
913 \r
914          uci->score = n;\r
915 \r
916       } else if (my_string_equal(option,"lowerbound")) {\r
917 \r
918          ASSERT(my_string_empty(argument));\r
919 \r
920       } else if (my_string_equal(option,"mate")) {\r
921 \r
922          ASSERT(!my_string_empty(argument));\r
923 \r
924          n = atoi(argument);\r
925          ASSERT(n!=0);\r
926 \r
927          uci->score = mate_score(n);\r
928 \r
929       } else if (my_string_equal(option,"upperbound")) {\r
930 \r
931          ASSERT(my_string_empty(argument));\r
932 \r
933       } else {\r
934 \r
935          my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
936       }\r
937    }\r
938 \r
939    parse_close(parse);\r
940 }\r
941 \r
942 // mate_score()\r
943 \r
944 static int mate_score(int dist) {\r
945 \r
946    ASSERT(dist!=0);\r
947 \r
948    if (FALSE) {\r
949    } else if (dist > 0) {\r
950        return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1;\r
951    } else if (dist < 0) {\r
952        return -option_get_int(Option,"MateScore") + (-dist) * 2;\r
953    }\r
954 \r
955    return 0;\r
956 }\r
957 \r
958 // end of uci.cpp\r
959 \r