16 #include "move_legal.h"
25 static const bool UseDebug = FALSE;
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
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
42 "cpus", // Deep Sjeng, Fruit2.3.5
49 static bool uci_is_ok (const uci_t * uci);
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[]);
57 static int mate_score (int dist);
64 static void apply_UCI3_heuristics(option_t *opt){
65 if(option_get_int(Option,"UCIVersion")>2){
68 if(!my_string_equal(opt->type,"string")){
71 if(!strncmp(opt->name,"UCI_",4)){
74 if(my_string_case_contains(opt->name,"file")){
75 my_string_set(&opt->type,"file");
78 if(my_string_case_contains(opt->name,"path")){
79 my_string_set(&opt->type,"path");
86 void uci_set_threads(uci_t * uci, int n) {
87 const char *thread_option=uci_thread_option(uci);
90 uci_send_option(uci,thread_option,"%d",n);
95 const char * uci_thread_option(uci_t * uci){
96 const char **p = thread_options;
97 const char *thread_option;
99 while((thread_option = *(p++))){
100 if((opt=option_find(uci->option,thread_option))){
110 static bool uci_is_ok(const uci_t * uci) {
112 if (uci == NULL) return FALSE;
113 if (uci->engine == NULL) return FALSE;
114 if (!option_is_ok(uci->option)) return FALSE;
120 void uci_open(uci_t * uci, engine_t * engine) {
122 char string[StringSize];
126 ASSERT(engine!=NULL);
130 uci->engine = engine;
133 my_string_set(&uci->name,"unknown");
135 my_string_set(&uci->author,"<empty>");
136 option_init(uci->option);
141 uci->multipv_mode = FALSE;
142 board_start(uci->board);
145 // send "uci" and wait for "uciok"
147 engine_send(uci->engine,"uci");
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");
156 event = uci_parse(uci,string);
157 } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0);
162 void uci_close(uci_t * uci) {
164 ASSERT(uci_is_ok(uci));
165 engine_close(uci->engine);
167 my_string_clear(&uci->name);
168 my_string_clear(&uci->author);
170 option_clear(uci->option);
175 void uci_clear(uci_t * uci) {
177 ASSERT(uci_is_ok(uci));
179 ASSERT(!uci->searching);
181 uci->best_move = MoveNone;
182 uci->ponder_move = MoveNone;
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
199 line_clear(uci->current_line);
201 uci->root_move = MoveNone;
202 uci->root_move_pos = 0;
203 uci->root_move_nb = board_mobility(uci->board);
208 // uci_send_isready()
210 void uci_send_isready(uci_t * uci) {
214 engine_send(uci->engine,"isready");
218 // uci_send_isready_sync()
220 void uci_send_isready_sync(uci_t * uci) {
222 char string[StringSize];
225 ASSERT(uci_is_ok(uci));
227 // send "isready" and wait for "readyok"
229 uci_send_isready(uci);
232 engine_get(uci->engine,string);
233 event = uci_parse(uci,string);
234 } while (!engine_eof(Engine) && (event & EVENT_READY) == 0);
239 void uci_send_stop(uci_t * uci) {
241 ASSERT(uci_is_ok(uci));
243 ASSERT(uci->searching);
244 ASSERT(uci->pending_nb>=1);
246 engine_send(Engine,"stop");
247 uci->searching = FALSE;
250 // uci_send_stop_sync()
252 void uci_send_stop_sync(uci_t * uci) {
254 char string[StringSize];
257 ASSERT(uci_is_ok(uci));
259 ASSERT(uci->searching);
260 ASSERT(uci->pending_nb>=1);
262 // send "stop" and wait for "bestmove"
267 engine_get(uci->engine,string);
268 event = uci_parse(uci,string);
269 } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0);
272 // uci_send_ucinewgame()
274 void uci_send_ucinewgame(uci_t * uci) {
278 if (option_get_int(Option,"UCIVersion") >= 2) {
279 engine_send(uci->engine,"ucinewgame");
285 bool uci_send_option(uci_t * uci, const char option[], const char format[], ...) {
287 char value[FormatBufferSize];
291 ASSERT(uci_is_ok(uci));
292 ASSERT(option!=NULL);
293 ASSERT(format!=NULL);
297 CONSTRUCT_ARG_STRING(format,value);
299 if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value);
301 opt=option_find(uci->option,option);
304 if(!IS_BUTTON(opt->type)){
305 if(!my_string_equal(opt->value,value)){
306 engine_send(uci->engine,"setoption name %s value %s",
308 my_string_set(&opt->value,value);
310 my_log("POLYGLOT Not sending option \"%s\" since it "
311 "already has the correct value.\n",opt->name);
314 engine_send(uci->engine,"setoption name %s",opt->name);
322 int uci_parse(uci_t * uci, const char string[]) {
326 char command[StringSize];
327 char argument[StringSize];
329 ASSERT(uci_is_ok(uci));
330 ASSERT(string!=NULL);
338 parse_open(parse,string);
340 if (parse_get_word(parse,command,StringSize)) {
342 parse_get_string(parse,argument,StringSize);
343 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument);
347 } else if (my_string_equal(command,"bestmove")) {
351 ASSERT(uci->pending_nb>0);
353 if (uci->searching && uci->pending_nb == 1) {
357 uci->searching = FALSE;
360 event = parse_bestmove(uci,argument); // updates uci->best_move, uci->ponder_move
366 if (uci->pending_nb > 0) {
368 if (uci->pending_nb == 0) event = EVENT_STOP;
372 } else if (my_string_equal(command,"id")) {
374 parse_id(uci,argument);
376 } else if (my_string_equal(command,"info")) {
378 // search information
380 if (uci->searching && uci->pending_nb == 1) { // current search
381 event = parse_info(uci,argument);
384 } else if (my_string_equal(command,"option")) {
386 parse_option(uci,argument);
388 } else if (my_string_equal(command,"readyok")) {
392 ASSERT(uci->ready_nb>0);
394 if (uci->ready_nb > 0) {
396 if (uci->ready_nb == 0) event = EVENT_READY;
399 } else if (my_string_equal(command,"uciok")) {
405 if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command);
416 static int parse_bestmove(uci_t * uci, const char string[]) {
419 char command[StringSize];
420 char option[StringSize];
421 char argument[StringSize];
424 ASSERT(uci_is_ok(uci));
425 ASSERT(string!=NULL);
429 strcpy(command,"bestmove");
431 parse_open(parse,string);
432 parse_add_keyword(parse,"ponder");
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");
442 strncpy(uci->bestmove,argument,UciStringSize);
443 uci->bestmove[UciStringSize-1]='\0';
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);
451 if(!move_is_legal(uci->best_move,uci->board)){
452 return EVENT_ILLEGAL_MOVE;
454 ASSERT(uci->best_move!=MoveNone);
455 ASSERT(move_is_legal(uci->best_move,uci->board));
459 while (parse_get_word(parse,option,StringSize)) {
461 parse_get_string(parse,argument,StringSize);
463 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
467 } else if (my_string_equal(option,"ponder")) {
469 ASSERT(!my_string_empty(argument));
471 board_copy(board,uci->board);
472 move_do(board,uci->best_move);
474 uci->ponder_move = move_from_can(argument,board);
476 // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);
478 ASSERT(uci->ponder_move!=MoveNone);
479 ASSERT(move_is_legal(uci->ponder_move,board));
483 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
494 static void parse_id(uci_t * uci, const char string[]) {
497 char command[StringSize];
498 char option[StringSize];
499 char argument[StringSize];
502 ASSERT(string!=NULL);
506 strcpy(command,"id");
508 parse_open(parse,string);
509 parse_add_keyword(parse,"author");
510 parse_add_keyword(parse,"name");
514 while (parse_get_word(parse,option,StringSize)) {
516 parse_get_string(parse,argument,StringSize);
517 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
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);
527 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
533 if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author);
538 static int parse_info(uci_t * uci, const char string[]) {
542 char command[StringSize];
543 char option[StringSize];
544 char argument[StringSize];
551 ASSERT(uci_is_ok(uci));
552 ASSERT(string!=NULL);
558 strcpy(command,"info");
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");
580 while (parse_get_word(parse,option,StringSize)) {
582 parse_get_string(parse,argument,StringSize);
584 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
588 } else if (my_string_equal(option,"cpuload")) {
590 ASSERT(!my_string_empty(argument));
595 if (n >= 0) uci->cpu = ((double)n) / 1000.0;
597 } else if (my_string_equal(option,"currline")) {
599 ASSERT(!my_string_empty(argument));
601 line_from_can(uci->current_line,uci->board,argument,LineSize);
603 } else if (my_string_equal(option,"currmove")) {
605 ASSERT(!my_string_empty(argument));
607 uci->root_move = move_from_can(argument,uci->board);
608 ASSERT(uci->root_move!=MoveNone);
610 } else if (my_string_equal(option,"currmovenumber")) {
612 ASSERT(!my_string_empty(argument));
615 ASSERT(n>=1&&n<=uci->root_move_nb);
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);
622 } else if (my_string_equal(option,"depth")) {
624 ASSERT(!my_string_empty(argument));
630 if (n > uci->depth) event |= EVENT_DEPTH;
634 } else if (my_string_equal(option,"hashfull")) {
636 ASSERT(!my_string_empty(argument));
641 if (n >= 0) uci->hash = ((double)n) / 1000.0;
643 } else if (my_string_equal(option,"multipv")) {
645 ASSERT(!my_string_empty(argument));
652 } else if (my_string_equal(option,"nodes")) {
654 ASSERT(!my_string_empty(argument));
656 ln = my_atoll(argument);
659 if (ln >= 0) uci->node_nb = ln;
661 } else if (my_string_equal(option,"nps")) {
663 ASSERT(!my_string_empty(argument));
668 if (n >= 0) uci->speed = ((double)n);
670 } else if (my_string_equal(option,"pv")) {
672 ASSERT(!my_string_empty(argument));
673 line_from_can(uci->pv,uci->board,argument,LineSize);
676 } else if (my_string_equal(option,"refutation")) {
678 ASSERT(!my_string_empty(argument));
680 line_from_can(uci->pv,uci->board,argument,LineSize);
682 } else if (my_string_equal(option,"score")) {
684 ASSERT(!my_string_empty(argument));
686 parse_score(uci,argument);
688 } else if (my_string_equal(option,"seldepth")) {
690 ASSERT(!my_string_empty(argument));
695 if (n >= 0) uci->sel_depth = n;
697 } else if (my_string_equal(option,"string")) {
698 if(my_string_case_equal(argument,"DrawOffer")){
700 }else if(my_string_case_equal(argument,"Resign")){
701 event |= EVENT_RESIGN;
703 snprintf(uci->info,sizeof(uci->info),"%s",argument);
704 uci->info[sizeof(uci->info)-1]='\0';
707 // TODO: argument to EOS
709 ASSERT(!my_string_empty(argument));
711 } else if (my_string_equal(option,"tbhits")) {
713 ASSERT(!my_string_empty(argument));
715 ln = my_atoll(argument);
718 if (ln >= 0) uci->tbhit_nb = ln;
720 } else if (my_string_equal(option,"time")) {
722 ASSERT(!my_string_empty(argument));
727 if (n >= 0) uci->time = ((double)n) / 1000.0;
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';
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);
749 if(uci->depth < uci->best_depth){
750 // ignore lines of lower depth
753 if(uci->depth > uci->best_depth) {
754 // clear stack when we start new depth
757 uci->best_depth = uci->depth;
758 if(multipvline >= 1) {
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
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;
772 my_fatal("parse_info(): multipv stack overflow.");
784 static void parse_option(uci_t * uci, const char string[]) {
788 char command[StringSize];
789 char option[StringSize];
790 char argument[StringSize];
793 ASSERT(string!=NULL);
797 strcpy(command,"option");
799 memset(opt,0,sizeof(option_t));
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>");
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");
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);
826 } else if (my_string_equal(option,"default")) {
828 // ASSERT(!my_string_empty(argument)); // HACK for Pepito
830 if (!my_string_empty(argument)) {
831 my_string_set(&opt->default_,argument);
832 my_string_set(&opt->value,argument);
835 } else if (my_string_equal(option,"max")) {
837 ASSERT(!my_string_empty(argument));
838 my_string_set(&opt->max,argument);
840 } else if (my_string_equal(option,"min")) {
842 ASSERT(!my_string_empty(argument));
843 my_string_set(&opt->min,argument);
845 } else if (my_string_equal(option,"name")) {
847 ASSERT(!my_string_empty(argument));
849 if (!my_string_empty(argument)) {
850 my_string_set(&opt->name,argument);
853 } else if (my_string_equal(option,"type")) {
855 ASSERT(!my_string_empty(argument));
856 my_string_set(&opt->type,argument);
858 } else if (my_string_equal(option,"var")) {
860 ASSERT(!my_string_empty(argument));
861 my_string_set(&opt->var[opt->var_nb++],argument);
862 if(opt->var_nb==VarNb) break;
866 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
872 apply_UCI3_heuristics(opt);
873 option_insert(uci->option,opt);
876 if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_);
881 static void parse_score(uci_t * uci, const char string[]) {
884 char command[StringSize];
885 char option[StringSize];
886 char argument[StringSize];
889 ASSERT(uci_is_ok(uci));
890 ASSERT(string!=NULL);
894 strcpy(command,"score");
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");
902 uci->bound_type = '\0'; // [HGM] bound: assume exact score
906 while (parse_get_word(parse,option,StringSize)) {
908 parse_get_string(parse,argument,StringSize);
910 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
914 } else if (my_string_equal(option,"cp")) {
916 ASSERT(!my_string_empty(argument));
922 } else if (my_string_equal(option,"lowerbound")) {
924 ASSERT(my_string_empty(argument));
926 uci->bound_type = '!';
928 } else if (my_string_equal(option,"mate")) {
930 ASSERT(!my_string_empty(argument));
935 uci->score = mate_score(n);
937 } else if (my_string_equal(option,"upperbound")) {
939 ASSERT(my_string_empty(argument));
941 uci->bound_type = '?';
945 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
954 static int mate_score(int dist) {
959 } else if (dist > 0) {
960 return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1;
961 } else if (dist < 0) {
962 return -option_get_int(Option,"MateScore") + (-dist) * 2;