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