14 #include "move_do.h"
\r
15 #include "move_legal.h"
\r
23 static const bool UseDebug = false;
\r
25 static const int StringSize = 4096;
\r
31 // Hopefully the following confusion is temporary
\r
32 // Normally we should check for the engine name but this is a hack anyway
\r
33 // Some of there where provided by Marc Lacrosse
\r
35 const char * thread_options[]={
\r
36 "number of threads", // toga
\r
37 "number threads", // Deep Learning Toga
\r
38 "threads", // glaurung, zappa, cyclone, grapefruit,
\r
39 // Deep Shredder, Deep Junior
\r
40 "core threads", // HIARCS
\r
41 "max cpus", // rybka
\r
42 "cpus", // Deep Sjeng, Fruit2.3.5
\r
43 "maxthreads", // Naum
\r
49 static bool uci_is_ok (const uci_t * uci);
\r
51 static int parse_bestmove (uci_t * uci, const char string[]);
\r
52 static void parse_id (uci_t * uci, const char string[]);
\r
53 static int parse_info (uci_t * uci, const char string[]);
\r
54 static void parse_option (uci_t * uci, const char string[]);
\r
55 static void parse_score (uci_t * uci, const char string[]);
\r
57 static int mate_score (int dist);
\r
61 // uci_set_threads()
\r
63 void uci_set_threads(uci_t * uci, int n) {
\r
64 const char **thread_options_copy = thread_options;
\r
65 const char *thread_option;
\r
67 while((thread_option = *(thread_options_copy++))){
\r
68 uci_send_option(uci,thread_option,"%d",n); // checks also for existence
\r
72 // uci_thread_option_exists()
\r
74 bool uci_thread_option_exist(uci_t * uci) {
\r
75 const char **thread_options_copy = thread_options;
\r
76 const char *thread_option;
\r
77 while((thread_option = *(thread_options_copy++))){
\r
78 if(uci_option_exist(uci,thread_option)) return true;
\r
83 const char * uci_thread_option(uci_t * uci){
\r
84 const char **thread_options_copy = thread_options;
\r
85 const char *thread_option;
\r
87 while((thread_option = *(thread_options_copy++))){
\r
88 i=uci_get_option(uci,thread_option);
\r
90 return Uci->option[i].name;
\r
99 static bool uci_is_ok(const uci_t * uci) {
\r
101 if (uci == NULL) return false;
\r
102 if (uci->engine == NULL) return false;
\r
103 if (uci->option_nb < 0 || uci->option_nb >= OptionNb) return false;
\r
110 void uci_open(uci_t * uci, engine_t * engine) {
\r
112 char string[StringSize];
\r
116 ASSERT(engine!=NULL);
\r
120 uci->engine = engine;
\r
123 my_string_set(&uci->name,"<empty>");
\r
124 uci->author = NULL;
\r
125 my_string_set(&uci->author,"<empty>");
\r
126 uci->option_nb = 0;
\r
129 uci->searching = 0;
\r
130 uci->pending_nb = 0;
\r
131 uci->multipv_mode = false;
\r
132 board_start(uci->board);
\r
135 // send "uci" and wait for "uciok"
\r
137 engine_send(uci->engine,"uci");
\r
140 engine_get(uci->engine,string,StringSize);
\r
141 event = uci_parse(uci,string);
\r
142 } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0);
\r
147 void uci_close(uci_t * uci) {
\r
152 ASSERT(uci_is_ok(uci));
\r
153 engine_close(uci->engine);
\r
154 uci->engine = NULL;
\r
155 my_string_clear(&uci->name);
\r
156 my_string_clear(&uci->author);
\r
158 for (i = 0; i < uci->option_nb; i++) {
\r
159 opt = &uci->option[i];
\r
160 my_string_clear(&opt->name);
\r
161 my_string_clear(&opt->default_);
\r
164 uci->option_nb = 0;
\r
169 void uci_clear(uci_t * uci) {
\r
171 ASSERT(uci_is_ok(uci));
\r
173 ASSERT(!uci->searching);
\r
175 uci->best_move = MoveNone;
\r
176 uci->ponder_move = MoveNone;
\r
180 uci->sel_depth = 0;
\r
181 line_clear(uci->pv);
\r
183 uci->best_score = 0;
\r
184 uci->best_depth = 0;
\r
185 uci->best_sel_depth = 0;
\r
186 line_clear(uci->best_pv);
\r
193 line_clear(uci->current_line);
\r
195 uci->root_move = MoveNone;
\r
196 uci->root_move_pos = 0;
\r
197 uci->root_move_nb = board_mobility(uci->board);
\r
200 // uci_send_isready()
\r
202 void uci_send_isready(uci_t * uci) {
\r
206 engine_send(uci->engine,"isready");
\r
210 // uci_send_isready_sync()
\r
212 void uci_send_isready_sync(uci_t * uci) {
\r
214 char string[StringSize];
\r
217 ASSERT(uci_is_ok(uci));
\r
219 // send "isready" and wait for "readyok"
\r
221 uci_send_isready(uci);
\r
224 engine_get(uci->engine,string,StringSize);
\r
225 event = uci_parse(uci,string);
\r
226 } while (!engine_eof(Engine) && (event & EVENT_READY) == 0);
\r
231 void uci_send_stop(uci_t * uci) {
\r
233 ASSERT(uci_is_ok(uci));
\r
235 ASSERT(uci->searching);
\r
236 ASSERT(uci->pending_nb>=1);
\r
238 engine_send(Engine,"stop");
\r
239 uci->searching = false;
\r
242 // uci_send_stop_sync()
\r
244 void uci_send_stop_sync(uci_t * uci) {
\r
246 char string[StringSize];
\r
249 ASSERT(uci_is_ok(uci));
\r
251 ASSERT(uci->searching);
\r
252 ASSERT(uci->pending_nb>=1);
\r
254 // send "stop" and wait for "bestmove"
\r
256 uci_send_stop(uci);
\r
259 engine_get(uci->engine,string,StringSize);
\r
260 event = uci_parse(uci,string);
\r
261 } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0);
\r
264 // uci_send_ucinewgame()
\r
266 void uci_send_ucinewgame(uci_t * uci) {
\r
270 if (option_get_int("UCIVersion") >= 2) {
\r
271 engine_send(uci->engine,"ucinewgame");
\r
275 // uci_option_exist()
\r
277 bool uci_option_exist(uci_t * uci, const char option[]) {
\r
282 ASSERT(uci_is_ok(uci));
\r
283 ASSERT(option!=NULL);
\r
287 for (i = 0; i < uci->option_nb; i++) {
\r
288 opt = &uci->option[i];
\r
289 if (my_string_case_equal(opt->name,option)) return true;
\r
295 // uci_send_option()
\r
297 void uci_send_option(uci_t * uci, const char option[], const char format[], ...) {
\r
300 char value[StringSize];
\r
304 ASSERT(uci_is_ok(uci));
\r
305 ASSERT(option!=NULL);
\r
306 ASSERT(format!=NULL);
\r
310 va_start(arg_list,format);
\r
311 vsprintf(value,format,arg_list);
\r
314 if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value);
\r
318 for (i = 0; i < uci->option_nb; i++) {
\r
320 opt = &uci->option[i];
\r
322 if (my_string_case_equal(opt->name,option) && !my_string_equal(opt->default_,value)) {
\r
323 engine_send(uci->engine,"setoption name %s value %s",opt->name,value);
\r
324 my_string_set(&opt->default_,value);
\r
332 int uci_parse(uci_t * uci, const char string[]) {
\r
336 char command[StringSize];
\r
337 char argument[StringSize];
\r
339 ASSERT(uci_is_ok(uci));
\r
340 ASSERT(string!=NULL);
\r
344 event = EVENT_NONE;
\r
348 parse_open(parse,string);
\r
350 if (parse_get_word(parse,command,StringSize)) {
\r
352 parse_get_string(parse,argument,StringSize);
\r
353 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument);
\r
357 } else if (my_string_equal(command,"bestmove")) {
\r
361 ASSERT(uci->pending_nb>0);
\r
363 if (uci->searching && uci->pending_nb == 1) {
\r
367 uci->searching = false;
\r
370 event = parse_bestmove(uci,argument); // updates uci->best_move and uci->ponder_move
\r
376 if (uci->pending_nb > 0) {
\r
378 if (uci->pending_nb == 0) event = EVENT_STOP;
\r
382 } else if (my_string_equal(command,"id")) {
\r
384 parse_id(uci,argument);
\r
386 } else if (my_string_equal(command,"info")) {
\r
388 // search information
\r
390 if (uci->searching && uci->pending_nb == 1) { // current search
\r
391 event = parse_info(uci,argument);
\r
394 } else if (my_string_equal(command,"option")) {
\r
396 parse_option(uci,argument);
\r
398 } else if (my_string_equal(command,"readyok")) {
\r
402 ASSERT(uci->ready_nb>0);
\r
404 if (uci->ready_nb > 0) {
\r
406 if (uci->ready_nb == 0) event = EVENT_READY;
\r
409 } else if (my_string_equal(command,"uciok")) {
\r
415 if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command);
\r
419 parse_close(parse);
\r
424 // parse_bestmove()
\r
426 static int parse_bestmove(uci_t * uci, const char string[]) {
\r
429 char command[StringSize];
\r
430 char option[StringSize];
\r
431 char argument[StringSize];
\r
434 ASSERT(uci_is_ok(uci));
\r
435 ASSERT(string!=NULL);
\r
439 strcpy(command,"bestmove");
\r
441 parse_open(parse,string);
\r
442 parse_add_keyword(parse,"ponder");
\r
446 if (!parse_get_string(parse,argument,StringSize)) {
\r
447 my_fatal("parse_bestmove(): missing argument\n");
\r
450 uci->best_move = move_from_can(argument,uci->board);
\r
451 if (uci->best_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);
\r
453 ASSERT(uci->best_move!=MoveNone);
\r
454 ASSERT(move_is_legal(uci->best_move,uci->board));
\r
458 while (parse_get_word(parse,option,StringSize)) {
\r
460 parse_get_string(parse,argument,StringSize);
\r
462 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
\r
466 } else if (my_string_equal(option,"ponder")) {
\r
468 ASSERT(!my_string_empty(argument));
\r
470 board_copy(board,uci->board);
\r
471 move_do(board,uci->best_move);
\r
473 uci->ponder_move = move_from_can(argument,board);
\r
474 // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);
\r
476 ASSERT(uci->ponder_move!=MoveNone);
\r
477 ASSERT(move_is_legal(uci->ponder_move,board));
\r
481 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
\r
485 parse_close(parse);
\r
492 static void parse_id(uci_t * uci, const char string[]) {
\r
495 char command[StringSize];
\r
496 char option[StringSize];
\r
497 char argument[StringSize];
\r
500 ASSERT(string!=NULL);
\r
504 strcpy(command,"id");
\r
506 parse_open(parse,string);
\r
507 parse_add_keyword(parse,"author");
\r
508 parse_add_keyword(parse,"name");
\r
512 while (parse_get_word(parse,option,StringSize)) {
\r
514 parse_get_string(parse,argument,StringSize);
\r
515 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
\r
518 } else if (my_string_equal(option,"author")) {
\r
519 ASSERT(!my_string_empty(argument));
\r
520 my_string_set(&uci->author,argument);
\r
521 } else if (my_string_equal(option,"name")) {
\r
522 ASSERT(!my_string_empty(argument));
\r
523 my_string_set(&uci->name,argument);
\r
525 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
\r
529 parse_close(parse);
\r
531 if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author);
\r
536 static int parse_info(uci_t * uci, const char string[]) {
\r
540 char command[StringSize];
\r
541 char option[StringSize];
\r
542 char argument[StringSize];
\r
547 ASSERT(uci_is_ok(uci));
\r
548 ASSERT(string!=NULL);
\r
552 event = EVENT_NONE;
\r
554 strcpy(command,"info");
\r
556 parse_open(parse,string);
\r
557 parse_add_keyword(parse,"cpuload");
\r
558 parse_add_keyword(parse,"currline");
\r
559 parse_add_keyword(parse,"currmove");
\r
560 parse_add_keyword(parse,"currmovenumber");
\r
561 parse_add_keyword(parse,"depth");
\r
562 parse_add_keyword(parse,"hashfull");
\r
563 parse_add_keyword(parse,"multipv");
\r
564 parse_add_keyword(parse,"nodes");
\r
565 parse_add_keyword(parse,"nps");
\r
566 parse_add_keyword(parse,"pv");
\r
567 parse_add_keyword(parse,"refutation");
\r
568 parse_add_keyword(parse,"score");
\r
569 parse_add_keyword(parse,"seldepth");
\r
570 parse_add_keyword(parse,"string");
\r
571 parse_add_keyword(parse,"tbhits");
\r
572 parse_add_keyword(parse,"time");
\r
576 while (parse_get_word(parse,option,StringSize)) {
\r
578 parse_get_string(parse,argument,StringSize);
\r
580 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
\r
584 } else if (my_string_equal(option,"cpuload")) {
\r
586 ASSERT(!my_string_empty(argument));
\r
588 n = atoi(argument);
\r
591 if (n >= 0) uci->cpu = double(n) / 1000.0;
\r
593 } else if (my_string_equal(option,"currline")) {
\r
595 ASSERT(!my_string_empty(argument));
\r
597 line_from_can(uci->current_line,uci->board,argument,LineSize);
\r
599 } else if (my_string_equal(option,"currmove")) {
\r
601 ASSERT(!my_string_empty(argument));
\r
603 uci->root_move = move_from_can(argument,uci->board);
\r
604 ASSERT(uci->root_move!=MoveNone);
\r
606 } else if (my_string_equal(option,"currmovenumber")) {
\r
608 ASSERT(!my_string_empty(argument));
\r
610 n = atoi(argument);
\r
611 ASSERT(n>=1&&n<=uci->root_move_nb);
\r
613 if (n >= 1 && n <= uci->root_move_nb) {
\r
614 uci->root_move_pos = n - 1;
\r
615 ASSERT(uci->root_move_pos>=0&&uci->root_move_pos<uci->root_move_nb);
\r
618 } else if (my_string_equal(option,"depth")) {
\r
620 ASSERT(!my_string_empty(argument));
\r
622 n = atoi(argument);
\r
626 if (n > uci->depth) event |= EVENT_DEPTH;
\r
630 } else if (my_string_equal(option,"hashfull")) {
\r
632 ASSERT(!my_string_empty(argument));
\r
634 n = atoi(argument);
\r
637 if (n >= 0) uci->hash = double(n) / 1000.0;
\r
639 } else if (my_string_equal(option,"multipv")) {
\r
641 ASSERT(!my_string_empty(argument));
\r
643 n = atoi(argument);
\r
644 if(Uci->multipv_mode) multipvline=n;
\r
648 } else if (my_string_equal(option,"nodes")) {
\r
650 ASSERT(!my_string_empty(argument));
\r
652 ln = my_atoll(argument);
\r
655 if (ln >= 0) uci->node_nb = ln;
\r
657 } else if (my_string_equal(option,"nps")) {
\r
659 ASSERT(!my_string_empty(argument));
\r
661 n = atoi(argument);
\r
664 if (n >= 0) uci->speed = double(n);
\r
666 } else if (my_string_equal(option,"pv")) {
\r
668 ASSERT(!my_string_empty(argument));
\r
670 line_from_can(uci->pv,uci->board,argument,LineSize);
\r
673 } else if (my_string_equal(option,"refutation")) {
\r
675 ASSERT(!my_string_empty(argument));
\r
677 line_from_can(uci->pv,uci->board,argument,LineSize);
\r
679 } else if (my_string_equal(option,"score")) {
\r
681 ASSERT(!my_string_empty(argument));
\r
683 parse_score(uci,argument);
\r
685 } else if (my_string_equal(option,"seldepth")) {
\r
687 ASSERT(!my_string_empty(argument));
\r
689 n = atoi(argument);
\r
692 if (n >= 0) uci->sel_depth = n;
\r
694 } else if (my_string_equal(option,"string")) {
\r
695 if(!strncmp(argument,"DrawOffer",9))
\r
696 event |= EVENT_DRAW;
\r
697 if(!strncmp(argument,"Resign",6))
\r
698 event |= EVENT_RESIGN;
\r
700 // TODO: argument to EOS
\r
702 ASSERT(!my_string_empty(argument));
\r
704 } else if (my_string_equal(option,"tbhits")) {
\r
706 ASSERT(!my_string_empty(argument));
\r
708 ln = my_atoll(argument);
\r
711 } else if (my_string_equal(option,"time")) {
\r
713 ASSERT(!my_string_empty(argument));
\r
715 n = atoi(argument);
\r
718 if (n >= 0) uci->time = double(n) / 1000.0;
\r
722 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
\r
726 parse_close(parse);
\r
729 //lousy uci,filter out lower depth multipv lines that have been repeated from the engine
\r
730 if(multipvline>1 && uci->depth<uci->best_depth) event &= ~EVENT_PV;
\r
731 if ((event & EVENT_PV) != 0) {
\r
732 uci->best_score = uci->score;
\r
733 uci->best_depth = uci->depth;
\r
734 if(multipvline==1)uci->depth=-1; //HACK ,clears the engine outpout window,see send_pv in adapter.cpp
\r
735 uci->best_sel_depth = uci->sel_depth;
\r
736 line_copy(uci->best_pv,uci->pv);
\r
741 int uci_get_option(uci_t * uci, const char * name){
\r
743 for(i=0;i<Uci->option_nb;i++){
\r
744 if(my_string_case_equal(Uci->option[i].name,name)){
\r
753 // uci_set_option()
\r
755 void uci_set_option(uci_t * uci,
\r
757 const char * default_,
\r
762 const char * var[]){
\r
764 for(i=0;i<Uci->option_nb;i++){
\r
765 if(my_string_equal(Uci->option[i].name,name)){
\r
770 my_string_set(&(Uci->option[i].name),name);
\r
771 my_string_set(&(Uci->option[i].default_),default_);
\r
772 my_string_set(&(Uci->option[i].type),type);
\r
773 my_string_set(&(Uci->option[i].min),min);
\r
774 my_string_set(&(Uci->option[i].max),max);
\r
775 Uci->option[i].var_nb=var_nb;
\r
776 for(j=0;j<var_nb;j++){
\r
777 my_string_set(&(Uci->option[i].var[j]),var[j]);
\r
779 if(i==Uci->option_nb){
\r
787 static void parse_option(uci_t * uci, const char string[]) {
\r
791 char command[StringSize];
\r
792 char option[StringSize];
\r
793 char argument[StringSize];
\r
796 ASSERT(string!=NULL);
\r
800 strcpy(command,"option");
\r
802 if (uci->option_nb >= OptionNb) return;
\r
804 opt = &uci->option[uci->option_nb];
\r
808 my_string_set(&opt->value,"<empty>");
\r
812 my_string_set(&opt->name,"<empty>");
\r
815 opt->default_ = NULL;
\r
816 my_string_set(&opt->default_,"<empty>");
\r
819 my_string_set(&opt->max,"<empty>");
\r
822 my_string_set(&opt->min,"<empty>");
\r
825 my_string_set(&opt->type,"<empty>");
\r
829 parse_open(parse,string);
\r
830 parse_add_keyword(parse,"default");
\r
831 parse_add_keyword(parse,"max");
\r
832 parse_add_keyword(parse,"min");
\r
833 parse_add_keyword(parse,"name");
\r
834 parse_add_keyword(parse,"type");
\r
835 parse_add_keyword(parse,"var");
\r
839 while (parse_get_word(parse,option,StringSize)) {
\r
840 parse_get_string(parse,argument,StringSize);
\r
841 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
\r
845 } else if (my_string_equal(option,"default")) {
\r
847 // ASSERT(!my_string_empty(argument)); // HACK for Pepito
\r
849 if (!my_string_empty(argument)) {
\r
850 my_string_set(&opt->default_,argument);
\r
851 my_string_set(&opt->value,argument);
\r
854 } else if (my_string_equal(option,"max")) {
\r
856 ASSERT(!my_string_empty(argument));
\r
857 my_string_set(&opt->max,argument);
\r
859 } else if (my_string_equal(option,"min")) {
\r
861 ASSERT(!my_string_empty(argument));
\r
862 my_string_set(&opt->min,argument);
\r
864 } else if (my_string_equal(option,"name")) {
\r
866 ASSERT(!my_string_empty(argument));
\r
868 if (!my_string_empty(argument)) {
\r
869 my_string_set(&opt->name,argument);
\r
872 } else if (my_string_equal(option,"type")) {
\r
874 ASSERT(!my_string_empty(argument));
\r
875 my_string_set(&opt->type,argument);
\r
877 } else if (my_string_equal(option,"var")) {
\r
879 ASSERT(!my_string_empty(argument));
\r
880 my_string_set(&opt->var[opt->var_nb++],argument);
\r
881 if(opt->var_nb==VarNb) break;
\r
885 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
\r
889 parse_close(parse);
\r
891 if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_);
\r
896 static void parse_score(uci_t * uci, const char string[]) {
\r
899 char command[StringSize];
\r
900 char option[StringSize];
\r
901 char argument[StringSize];
\r
904 ASSERT(uci_is_ok(uci));
\r
905 ASSERT(string!=NULL);
\r
909 strcpy(command,"score");
\r
911 parse_open(parse,string);
\r
912 parse_add_keyword(parse,"cp");
\r
913 parse_add_keyword(parse,"lowerbound");
\r
914 parse_add_keyword(parse,"mate");
\r
915 parse_add_keyword(parse,"upperbound");
\r
919 while (parse_get_word(parse,option,StringSize)) {
\r
921 parse_get_string(parse,argument,StringSize);
\r
923 if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
\r
927 } else if (my_string_equal(option,"cp")) {
\r
929 ASSERT(!my_string_empty(argument));
\r
931 n = atoi(argument);
\r
935 } else if (my_string_equal(option,"lowerbound")) {
\r
937 ASSERT(my_string_empty(argument));
\r
939 } else if (my_string_equal(option,"mate")) {
\r
941 ASSERT(!my_string_empty(argument));
\r
943 n = atoi(argument);
\r
946 uci->score = mate_score(n);
\r
948 } else if (my_string_equal(option,"upperbound")) {
\r
950 ASSERT(my_string_empty(argument));
\r
954 my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
\r
958 parse_close(parse);
\r
963 static int mate_score(int dist) {
\r
968 } else if (dist > 0) {
\r
969 return +option_get_int("MateScore") - (+dist) * 2 + 1;
\r
970 } else if (dist < 0) {
\r
971 return -option_get_int("MateScore") + (-dist) * 2;
\r