22 #include "move_do.h"
\r
23 #include "move_legal.h"
\r
28 #include "uci2uci.h"
\r
30 #include "xboard2uci.h"
\r
34 #define StringSize 4096
\r
38 static const bool UseDebug = FALSE;
\r
39 static const bool DelayPong = FALSE;
\r
45 bool computer[ColourNb];
\r
48 my_timer_t timer[1];
\r
52 bool has_feature_memory;
\r
53 bool has_feature_smp;
\r
54 bool has_feature_egt;
\r
59 bool new_hack; // "new" is a C++ keyword
\r
82 typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t;
\r
86 static state_t State[1];
\r
91 static void comp_move (int move);
\r
92 static void move_step (int move);
\r
93 static void board_update ();
\r
95 static void mess ();
\r
96 static void no_mess (int move);
\r
98 static void search_update ();
\r
99 static void search_clear ();
\r
100 static void update_remaining_time();
\r
101 static int report_best_score();
\r
102 static bool kibitz_throttle (bool searching);
\r
103 static void start_protected_command();
\r
104 static void end_protected_command();
\r
106 static bool active ();
\r
107 static bool ponder ();
\r
108 static bool ponder_ok (int ponder_move);
\r
110 static void stop_search ();
\r
112 static void send_board (int extra_move);
\r
113 static void send_pv ();
\r
114 static void send_info ();
\r
116 static void send_xboard_options ();
\r
118 static void learn (int result);
\r
123 // xboard2uci_init()
\r
125 void xboard2uci_init() {
\r
132 State->state = WAIT;
\r
134 State->computer[White] = FALSE;
\r
135 State->computer[Black] = TRUE;
\r
137 State->exp_move = MoveNone;
\r
138 State->resign_nb = 0;
\r
139 my_timer_reset(State->timer);
\r
141 // yes there are engines that do not have the "Hash" option....
\r
142 XB->has_feature_memory= (option_find(Uci->option,"Hash")!=NULL);
\r
143 XB->has_feature_smp = (uci_thread_option(Uci)!=NULL);
\r
144 // TODO: support for other types of table bases
\r
145 XB->has_feature_egt = (option_find(Uci->option,"NalimovPath")!=NULL);
\r
146 XB->analyse = FALSE;
\r
147 XB->computer = FALSE;
\r
149 my_string_set(&XB->name,"<empty>");
\r
151 XB->new_hack = TRUE;
\r
153 XB->ponder = FALSE;
\r
156 XB->result = FALSE;
\r
162 XB->time_limit = FALSE;
\r
163 XB->time_max = 5.0;
\r
165 XB->depth_limit = FALSE;
\r
166 XB->depth_max = 127;
\r
168 XB->my_time = 300.0;
\r
169 XB->opp_time = 300.0;
\r
171 XB->node_rate = -1;
\r
174 // xboard2uci_gui_step()
\r
176 void xboard2uci_gui_step(char string[]) {
\r
179 char move_string[256];
\r
184 } else if (match(string,"accepted *")) {
\r
188 } else if (match(string,"analyze")) {
\r
190 State->computer[White] = FALSE;
\r
191 State->computer[Black] = FALSE;
\r
193 XB->analyse = TRUE;
\r
194 XB->new_hack = FALSE;
\r
195 ASSERT(!XB->result);
\r
196 XB->result = FALSE;
\r
200 } else if (match(string,"bk")) {
\r
202 if (option_get_bool(Option,"Book")) {
\r
203 game_get_board(Game,board);
\r
207 } else if (match(string,"black")) {
\r
209 if (colour_is_black(game_turn(Game))) {
\r
211 State->computer[White] = TRUE;
\r
212 State->computer[Black] = FALSE;
\r
214 XB->new_hack = TRUE;
\r
215 XB->result = FALSE;
\r
220 } else if (match(string,"computer")) {
\r
222 XB->computer = TRUE;
\r
224 } else if (match(string,"draw")) {
\r
225 if(option_find(Uci->option,"UCI_DrawOffers")){
\r
226 my_log("POLYGLOT draw from XB received");
\r
227 uci_send_option(Uci,"DrawOffer","%s","draw");}
\r
228 } else if (match(string,"easy")) {
\r
230 XB->ponder = FALSE;
\r
234 } else if (match(string,"edit")) {
\r
238 gui_send(GUI,"Error (unknown command): %s",string);
\r
240 } else if (match(string,"exit")) {
\r
242 State->computer[White] = FALSE;
\r
243 State->computer[Black] = FALSE;
\r
245 XB->analyse = FALSE;
\r
249 } else if (match(string,"force")) {
\r
251 State->computer[White] = FALSE;
\r
252 State->computer[Black] = FALSE;
\r
256 } else if (match(string,"go")) {
\r
258 State->computer[game_turn(Game)] = TRUE;
\r
259 State->computer[colour_opp(game_turn(Game))] = FALSE;
\r
261 XB->new_hack = FALSE;
\r
262 ASSERT(!XB->result);
\r
263 XB->result = FALSE;
\r
267 } else if (match(string,"hard")) {
\r
273 } else if (match(string,"hint")) {
\r
275 if (option_get_bool(Option,"Book")) {
\r
277 game_get_board(Game,board);
\r
278 move = book_move(board,FALSE);
\r
280 if (move != MoveNone && move_is_legal(move,board)) {
\r
281 move_to_san(move,board,move_string,256);
\r
282 gui_send(GUI,"Hint: %s",move_string);
\r
286 } else if (match(string,"ics *")) {
\r
290 } else if (match(string,"level * *:* *")) {
\r
292 XB->mps = atoi(Star[0]);
\r
293 XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2]));
\r
294 XB->inc = ((double)atoi(Star[3]));
\r
296 } else if (match(string,"level * * *")) {
\r
298 XB->mps = atoi(Star[0]);
\r
299 XB->base = ((double)atoi(Star[1])) * 60.0;
\r
300 XB->inc = ((double)atoi(Star[2]));
\r
302 } else if (match(string,"name *")) {
\r
304 my_string_set(&XB->name,Star[0]);
\r
306 } else if (match(string,"new")) {
\r
308 uci_send_isready(Uci);
\r
309 my_log("POLYGLOT NEW GAME\n");
\r
311 option_set(Option,"Chess960","false");
\r
316 State->computer[White] = FALSE;
\r
317 State->computer[Black] = FALSE;
\r
319 State->computer[White] = FALSE;
\r
320 State->computer[Black] = TRUE;
\r
323 XB->new_hack = TRUE;
\r
324 XB->result = FALSE;
\r
326 XB->depth_limit = FALSE;
\r
329 XB->computer = FALSE;
\r
330 my_string_set(&XB->name,"<empty>");
\r
335 uci_send_ucinewgame(Uci);
\r
337 } else if (match(string,"nopost")) {
\r
341 } else if (match(string,"otim *")) {
\r
343 XB->opp_time = ((double)atoi(Star[0])) / 100.0;
\r
344 if (XB->opp_time < 0.0) XB->opp_time = 0.0;
\r
346 } else if (match(string,"pause")) {
\r
350 gui_send(GUI,"Error (unknown command): %s",string);
\r
352 } else if (match(string,"ping *")) {
\r
354 // HACK; TODO: answer only after an engine move
\r
357 if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping
\r
358 XB->ping = atoi(Star[0]);
\r
359 uci_send_isready(Uci);
\r
361 ASSERT(XB->ping==-1);
\r
362 gui_send(GUI,"pong %s",Star[0]);
\r
364 } else if (match(string,"nps *")) {
\r
366 // fake WB play-by-nodes mode
\r
367 XB->node_rate = atoi(Star[0]);
\r
368 } else if (match(string,"playother")) {
\r
370 State->computer[game_turn(Game)] = FALSE;
\r
371 State->computer[colour_opp(game_turn(Game))] = TRUE;
\r
373 XB->new_hack = FALSE;
\r
374 ASSERT(!XB->result);
\r
375 XB->result = FALSE;
\r
379 } else if (match(string,"post")) {
\r
383 } else if (match(string,"protover *")) {
\r
384 XB->proto_ver = atoi(Star[0]);
\r
385 ASSERT(XB->proto_ver>=2);
\r
386 send_xboard_options();
\r
388 } else if (match(string,"quit")) {
\r
389 my_log("POLYGLOT *** \"quit\" from GUI ***\n");
\r
391 } else if (match(string,"random")) {
\r
395 } else if (match(string,"rating * *")) {
\r
399 } else if (match(string,"remove")) {
\r
401 if (game_pos(Game) >= 2) {
\r
403 game_goto(Game,game_pos(Game)-2);
\r
405 ASSERT(!XB->new_hack);
\r
406 XB->new_hack = FALSE; // HACK?
\r
407 XB->result = FALSE;
\r
413 } else if (match(string,"rejected *")) {
\r
417 } else if (match(string,"reset")) { // protover 3?
\r
421 gui_send(GUI,"Error (unknown command): %s",string);
\r
424 || match(string,"result * {*}")
\r
425 || match(string,"result * {* }")
\r
426 || match(string,"result * { *}")
\r
427 || match(string,"result * { * }")) {
\r
429 my_log("POLYGLOT GAME END\n");
\r
437 if (option_get_bool(Option,"Book") &&
\r
438 option_get_bool(Option,"BookLearn")) {
\r
441 } else if (my_string_equal(Star[0],"1-0")) {
\r
443 } else if (my_string_equal(Star[0],"0-1")) {
\r
445 } else if (my_string_equal(Star[0],"1/2-1/2")) {
\r
449 } else if (match(string,"resume")) {
\r
453 gui_send(GUI,"Error (unknown command): %s",string);
\r
455 } else if (match(string,"option *=*") ||
\r
456 match(string,"option * =*") ||
\r
457 match(string,"option *= *") ||
\r
458 match(string,"option * = *")
\r
460 char *name=Star[0];
\r
461 char *value=Star[1];
\r
462 if(match(name, "Polyglot *")){
\r
463 char *pg_name=Star[0];
\r
464 polyglot_set_option(pg_name,value);
\r
466 option_t *opt=option_find(Uci->option,name);
\r
468 if(my_string_case_equal(opt->type,"check")){
\r
469 value=my_string_equal(value,"1")?"true":"false";
\r
471 start_protected_command();
\r
472 uci_send_option(Uci, name, "%s", value);
\r
473 end_protected_command();
\r
475 gui_send(GUI,"Error (unknown option): %s",name);
\r
478 } else if (match(string,"option *")){
\r
479 char *name=Star[0];
\r
480 if(match(name, "Polyglot *")){
\r
481 char *pg_name=Star[0];
\r
482 polyglot_set_option(pg_name,"<empty>");
\r
484 start_protected_command();
\r
485 // value is ignored
\r
486 if(!uci_send_option(Uci, name, "%s", "<empty>")){
\r
487 gui_send(GUI,"Error (unknown option): %s",name);
\r
489 end_protected_command();
\r
491 } else if (XB->has_feature_smp && match(string,"cores *")){
\r
492 int cores=atoi(Star[0]);
\r
494 // updating the number of cores
\r
495 my_log("POLYGLOT setting the number of cores to %d\n",cores);
\r
496 start_protected_command();
\r
497 uci_set_threads(Uci,cores);
\r
498 end_protected_command();
\r
501 gui_send(GUI,"Error (unknown command): %s",string);
\r
503 } else if (XB->has_feature_egt && match(string,"egtpath * *")){
\r
504 char *type=Star[0];
\r
505 char *path=Star[1];
\r
506 if(!my_string_case_equal(type,"nalimov")){
\r
508 gui_send(GUI,"Error (unsupported table base format): %s",string);
\r
509 }else if(my_string_empty(path)){
\r
511 gui_send(GUI,"Error (unknown command): %s",string);
\r
513 // updating NalimovPath
\r
514 my_log("POLYGLOT setting the Nalimov path to %s\n",path);
\r
515 start_protected_command();
\r
516 uci_send_option(Uci,"NalimovPath","%s",path);
\r
517 end_protected_command();
\r
519 } else if (XB->has_feature_memory && match(string,"memory *")){
\r
520 int memory = atoi(Star[0]);
\r
524 // updating the available memory
\r
526 my_log("POLYGLOT setting the amount of memory to %dMb\n",memory);
\r
527 if((opt=option_find(Uci->option,"NalimovCache"))){
\r
528 nalimov_cache=atoi(opt->value);
\r
532 my_log("POLYGLOT Nalimov Cache is %dMb\n",nalimov_cache);
\r
533 real_memory=memory-nalimov_cache;
\r
535 start_protected_command();
\r
536 uci_send_option(Uci,"Hash", "%d", real_memory);
\r
537 end_protected_command();
\r
541 gui_send(GUI,"Error (unknown command): %s",string);
\r
544 } else if (match(string,"sd *")) {
\r
546 XB->depth_limit = TRUE;
\r
547 XB->depth_max = atoi(Star[0]);
\r
549 } else if (match(string,"setboard *")) {
\r
551 my_log("POLYGLOT FEN %s\n",Star[0]);
\r
553 if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]);
\r
555 State->computer[White] = FALSE;
\r
556 State->computer[Black] = FALSE;
\r
558 XB->new_hack = TRUE; // HACK?
\r
559 XB->result = FALSE;
\r
564 } else if (match(string,"st *")) {
\r
566 XB->time_limit = TRUE;
\r
567 XB->time_max = ((double)atoi(Star[0]));
\r
569 } else if (match(string,"time *")) {
\r
571 XB->my_time = ((double)atoi(Star[0])) / 100.0;
\r
572 if (XB->my_time < 0.0) XB->my_time = 0.0;
\r
574 } else if (match(string,"undo")) {
\r
576 if (game_pos(Game) >= 1) {
\r
578 game_goto(Game,game_pos(Game)-1);
\r
580 ASSERT(!XB->new_hack);
\r
581 XB->new_hack = FALSE; // HACK?
\r
582 XB->result = FALSE;
\r
588 } else if (match(string,"usermove *")) {
\r
590 game_get_board(Game,board);
\r
591 move = move_from_san(Star[0],board);
\r
593 if (move != MoveNone && move_is_legal(move,board)) {
\r
595 XB->new_hack = FALSE;
\r
596 ASSERT(!XB->result);
\r
597 XB->result = FALSE;
\r
604 gui_send(GUI,"Illegal move: %s",Star[0]);
\r
607 } else if (match(string,"variant *")) {
\r
609 if (my_string_equal(Star[0],"fischerandom")) {
\r
610 option_set(Option,"Chess960","true");
\r
612 option_set(Option,"Chess960","false");
\r
615 } else if (match(string,"white")) {
\r
617 if (colour_is_white(game_turn(Game))) {
\r
619 State->computer[White] = FALSE;
\r
620 State->computer[Black] = TRUE;
\r
622 XB->new_hack = TRUE;
\r
623 XB->result = FALSE;
\r
628 } else if (match(string,"xboard")) {
\r
632 } else if (match(string,".")) { // analyse info
\r
634 if (State->state == ANALYSE) {
\r
635 int depth=Uci->best_depth;//HACK: don't clear engine-output window...
\r
637 ASSERT(Uci->searching);
\r
638 ASSERT(Uci->pending_nb>=1);
\r
640 if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) {
\r
641 move_to_san(Uci->root_move,Uci->board,move_string,256);
\r
642 gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d %s",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,Uci->root_move_nb-(Uci->root_move_pos+1),Uci->root_move_nb,move_string);
\r
644 gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK
\r
648 } else if (match(string,"?")) { // move now
\r
650 if (State->state == THINK) {
\r
652 ASSERT(Uci->searching);
\r
653 ASSERT(Uci->pending_nb>=1);
\r
655 // HACK: just send "stop" to the engine
\r
657 if (Uci->searching) {
\r
658 my_log("POLYGLOT STOP SEARCH\n");
\r
659 engine_send(Engine,"stop");
\r
663 } else { // unknown command, maybe a move?
\r
665 game_get_board(Game,board);
\r
666 move = move_from_san(string,board);
\r
668 if (move != MoveNone && move_is_legal(move,board)) {
\r
670 XB->new_hack = FALSE;
\r
671 ASSERT(!XB->result);
\r
672 XB->result = FALSE;
\r
677 } else if (move != MoveNone) {
\r
679 gui_send(GUI,"Illegal move: %s",string);
\r
683 gui_send(GUI,"Error (unknown command): %s",string);
\r
689 // xboard2uci_engine_step()
\r
691 void xboard2uci_engine_step(char string[]) {
\r
695 event = uci_parse(Uci,string);
\r
699 if ((event & EVENT_READY) != 0) {
\r
701 // the engine is now ready
\r
705 // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1");
\r
708 if (!DelayPong && XB->ping >= 0) {
\r
709 gui_send(GUI,"pong %d",XB->ping);
\r
714 if ((event & EVENT_MOVE) != 0 && State->state == THINK) {
\r
716 // the engine is playing a move
\r
718 // MEGA HACK: estimate remaining time because XBoard won't send it!
\r
720 my_timer_stop(State->timer);
\r
722 XB->my_time -= my_timer_elapsed_real(State->timer);
\r
723 XB->my_time += XB->inc;
\r
724 if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base;
\r
726 if (XB->my_time < 0.0) XB->my_time = 0.0;
\r
728 // play the engine move
\r
730 comp_move(Uci->best_move);
\r
733 if ((event & EVENT_PV) != 0) {
\r
735 // the engine has sent a new PV
\r
739 if ((event & EVENT_INFO) != 0) {
\r
741 // the engine has sent info
\r
745 if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){
\r
746 my_log("POYGLOT draw offer/resign from engine\n");
\r
747 if(option_find(Uci->option,"UCI_DrawOffers")){
\r
748 if(event & EVENT_DRAW)
\r
749 gui_send(GUI,"offer draw");
\r
751 gui_send(GUI,"resign");
\r
754 if(((event & EVENT_ILLEGAL_MOVE)!=0) && (State->state == THINK)){
\r
755 game_get_board(Game,board);
\r
756 if(board->turn==White){
\r
757 gui_send(GUI,"0-1 {polyglot: resign"
\r
758 " (illegal engine move white)}");
\r
760 gui_send(GUI,"1-0 {polyglot: resign"
\r
761 " (illegal engine move black)}");
\r
769 // format_xboard_option_line
\r
771 void format_xboard_option_line(char * option_line, option_t *opt){
\r
773 char option_string[StringSize];
\r
775 strcpy(option_line,"");
\r
776 // buffer overflow alert
\r
777 strcat(option_line,"feature option=\"");
\r
779 strcat(option_line,"Polyglot ");
\r
781 sprintf(option_string,"%s",opt->name);
\r
782 strcat(option_line,option_string);
\r
783 sprintf(option_string," -%s",opt->type);
\r
784 strcat(option_line,option_string);
\r
785 if(!IS_BUTTON(opt->type) && strcmp(opt->type,"combo")){
\r
786 if(strcmp(opt->type,"check")){
\r
787 sprintf(option_string," %s",opt->value);
\r
789 sprintf(option_string," %d",
\r
790 my_string_case_equal(opt->value,"true")||
\r
791 my_string_equal(opt->value,"1")
\r
794 strcat(option_line,option_string);
\r
796 if(IS_SPIN(opt->type)){
\r
797 sprintf(option_string," %s",opt->min);
\r
798 strcat(option_line,option_string);
\r
800 if(IS_SPIN(opt->type)){
\r
801 sprintf(option_string," %s",opt->max);
\r
802 strcat(option_line,option_string);
\r
804 for(j=0;j<opt->var_nb;j++){
\r
805 if(!strcmp(opt->var[j],opt->value)){
\r
806 sprintf(option_string," *%s",opt->var[j]);
\r
808 sprintf(option_string," %s",opt->var[j]);
\r
810 strcat(option_line,option_string);
\r
811 if(j!=opt->var_nb-1){
\r
812 strcat(option_line," ///");
\r
815 strcat(option_line,"\"");
\r
816 if(option_get_bool(Option,"WbWorkArounds") &&
\r
817 (tmp=strstr(option_line,"Draw"))){
\r
819 my_log("POLYGLOT Decapitalizing \"Draw\" in option \"%s\"\n",
\r
824 // send_xboard_options()
\r
826 static void send_xboard_options(){
\r
829 gui_send(GUI,"feature done=0");
\r
831 gui_send(GUI,"feature analyze=1");
\r
832 gui_send(GUI,"feature colors=0");
\r
833 gui_send(GUI,"feature draw=1");
\r
834 gui_send(GUI,"feature ics=1");
\r
835 gui_send(GUI,"feature myname=\"%s\"",
\r
836 option_get_string(Option,"EngineName"));
\r
837 gui_send(GUI,"feature name=1");
\r
838 gui_send(GUI,"feature pause=0");
\r
839 gui_send(GUI,"feature ping=1");
\r
840 gui_send(GUI,"feature playother=1");
\r
841 gui_send(GUI,"feature sigint=1");
\r
842 gui_send(GUI,"feature reuse=1");
\r
843 gui_send(GUI,"feature san=0");
\r
844 gui_send(GUI,"feature setboard=1");
\r
845 gui_send(GUI,"feature sigint=0");
\r
846 gui_send(GUI,"feature sigterm=0");
\r
847 gui_send(GUI,"feature time=1");
\r
848 gui_send(GUI,"feature usermove=1");
\r
849 gui_send(GUI,"feature nps=1");
\r
850 if (XB->has_feature_memory){
\r
851 gui_send(GUI,"feature memory=1");
\r
853 gui_send(GUI,"feature memory=0");
\r
855 if (XB->has_feature_smp){
\r
856 gui_send(GUI,"feature smp=1");
\r
858 gui_send(GUI,"feature smp=0");
\r
860 if (XB->has_feature_egt){
\r
861 // TODO: support for other types of table bases
\r
862 gui_send(GUI,"feature egt=\"nalimov\"");
\r
864 gui_send(GUI,"feature egt=\"\"");
\r
867 if (option_find(Uci->option,"UCI_Chess960")) {
\r
868 gui_send(GUI,"feature variants=\"normal,fischerandom\"");
\r
870 gui_send(GUI,"feature variants=\"normal\"");
\r
873 xboard2uci_send_options();
\r
876 void xboard2uci_send_options(){
\r
877 char option_line[StringSize]="";
\r
881 option_start_iter(Uci->option);
\r
882 while((opt=option_next(Uci->option))){
\r
883 if(my_string_case_equal(opt->name,"UCI_AnalyseMode")) continue;
\r
884 if(my_string_case_equal(opt->name,"UCI_Opponent")) continue;
\r
885 if(my_string_case_equal(opt->name,"UCI_Chess960")) continue;
\r
886 if(my_string_case_equal(opt->name,"UCI_ShowCurrLine")) continue;
\r
887 if(my_string_case_equal(opt->name,"UCI_ShowRefutations")) continue;
\r
888 if(my_string_case_equal(opt->name,"UCI_ShredderbasesPath")) continue;
\r
889 if(my_string_case_equal(opt->name,"UCI_SetPositionValue")) continue;
\r
890 if(my_string_case_equal(opt->name,"UCI_DrawOffers")) continue;
\r
891 if(my_string_case_equal(opt->name,"Ponder")) continue;
\r
892 if(my_string_case_equal(opt->name,"Hash")) continue;
\r
893 if(my_string_case_equal(opt->name,"NalimovPath")) continue;
\r
894 if((name=uci_thread_option(Uci))!=NULL &&
\r
895 my_string_case_equal(opt->name,name)) continue;
\r
896 format_xboard_option_line(option_line,opt);
\r
898 gui_send(GUI,"%s",option_line);
\r
902 option_start_iter(Option);
\r
903 while((opt=option_next(Option))){
\r
904 if(opt->mode &XBOARD){
\r
905 format_xboard_option_line(option_line,opt);
\r
906 gui_send(GUI,"%s",option_line);
\r
909 gui_send(GUI,"feature done=1");
\r
913 // report_best_score()
\r
915 static int report_best_score(){
\r
916 if(!option_get_bool(Option,"ScoreWhite") ||
\r
917 colour_is_white(Uci->board->turn)){
\r
918 return Uci->best_score;
\r
920 return -Uci->best_score;
\r
926 static void comp_move(int move) {
\r
931 ASSERT(move_is_ok(move));
\r
933 ASSERT(State->state==THINK);
\r
934 ASSERT(!XB->analyse);
\r
936 if(option_get_bool(Option,"RepeatPV"))
\r
937 send_pv(); // to update time and nodes
\r
941 game_get_board(Game,board);
\r
943 if (move_is_castle(move,board) && option_get_bool(Option,"Chess960")) {
\r
944 if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O
\r
946 if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n");
\r
949 gui_send(GUI,"move %s",string);
\r
953 if (option_get_bool(Option,"Resign") && Uci->root_move_nb > 1) {
\r
955 if (Uci->best_score <= -abs(option_get_int(Option,"ResignScore"))) {
\r
957 State->resign_nb++;
\r
958 my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":"");
\r
960 if (State->resign_nb >= option_get_int(Option,"ResignMoves")) {
\r
961 my_log("POLYGLOT *** RESIGN ***\n");
\r
962 gui_send(GUI,"resign");
\r
967 if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb);
\r
968 State->resign_nb = 0;
\r
980 static void move_step(int move) {
\r
983 char move_string[256];
\r
985 ASSERT(move_is_ok(move));
\r
989 game_get_board(Game,board);
\r
991 if (move != MoveNone && move_is_legal(move,board)) {
\r
993 move_to_san(move,board,move_string,256);
\r
994 my_log("POLYGLOT MOVE %s\n",move_string);
\r
998 move_to_can(move,board,move_string,256);
\r
999 my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string);
\r
1000 board_disp(board);
\r
1002 my_fatal("move_step(): illegal move \"%s\"\n",move_string);
\r
1007 game_add_move(Game,move);
\r
1013 static void board_update() {
\r
1015 // handle game end
\r
1017 ASSERT(!XB->result);
\r
1019 switch (game_status(Game)) {
\r
1023 gui_send(GUI,"1-0 {White mates}");
\r
1026 gui_send(GUI,"0-1 {Black mates}");
\r
1029 gui_send(GUI,"1/2-1/2 {Stalemate}");
\r
1031 case DRAW_MATERIAL:
\r
1032 gui_send(GUI,"1/2-1/2 {Draw by insufficient material}");
\r
1035 gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}");
\r
1037 case DRAW_REPETITION:
\r
1038 gui_send(GUI,"1/2-1/2 {Draw by repetition}");
\r
1048 static void mess() {
\r
1050 // clear state variables
\r
1052 State->resign_nb = 0;
\r
1053 State->exp_move = MoveNone;
\r
1054 my_timer_reset(State->timer);
\r
1056 // abort a possible search
\r
1060 // calculate the new state
\r
1063 } else if (!active()) {
\r
1064 State->state = WAIT;
\r
1065 my_log("POLYGLOT WAIT\n");
\r
1066 } else if (XB->analyse) {
\r
1067 State->state = ANALYSE;
\r
1068 my_log("POLYGLOT ANALYSE\n");
\r
1069 } else if (State->computer[game_turn(Game)]) {
\r
1070 State->state = THINK;
\r
1071 my_log("POLYGLOT THINK\n");
\r
1073 State->state = WAIT;
\r
1074 my_log("POLYGLOT WAIT\n");
\r
1082 static void no_mess(int move) {
\r
1084 ASSERT(move_is_ok(move));
\r
1086 // just received a move, calculate the new state
\r
1090 } else if (!active()) {
\r
1092 stop_search(); // abort a possible search
\r
1094 State->state = WAIT;
\r
1095 State->exp_move = MoveNone;
\r
1097 my_log("POLYGLOT WAIT\n");
\r
1099 } else if (State->state == WAIT) {
\r
1101 ASSERT(State->computer[game_turn(Game)]);
\r
1102 ASSERT(!State->computer[colour_opp(game_turn(Game))]);
\r
1103 ASSERT(!XB->analyse);
\r
1105 my_log("POLYGLOT WAIT -> THINK\n");
\r
1107 State->state = THINK;
\r
1108 State->exp_move = MoveNone;
\r
1110 } else if (State->state == THINK) {
\r
1112 ASSERT(!State->computer[game_turn(Game)]);
\r
1113 ASSERT(State->computer[colour_opp(game_turn(Game))]);
\r
1114 ASSERT(!XB->analyse);
\r
1116 if (ponder() && ponder_ok(Uci->ponder_move)) {
\r
1118 my_log("POLYGLOT THINK -> PONDER\n");
\r
1120 State->state = PONDER;
\r
1121 State->exp_move = Uci->ponder_move;
\r
1125 my_log("POLYGLOT THINK -> WAIT\n");
\r
1127 State->state = WAIT;
\r
1128 State->exp_move = MoveNone;
\r
1131 } else if (State->state == PONDER) {
\r
1133 ASSERT(State->computer[game_turn(Game)]);
\r
1134 ASSERT(!State->computer[colour_opp(game_turn(Game))]);
\r
1135 ASSERT(!XB->analyse);
\r
1137 if (move == State->exp_move && Uci->searching) {
\r
1139 ASSERT(Uci->searching);
\r
1140 ASSERT(Uci->pending_nb>=1);
\r
1142 my_timer_start(State->timer);//also resets
\r
1144 my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n");
\r
1145 engine_send(Engine,"ponderhit");
\r
1147 State->state = THINK;
\r
1148 State->exp_move = MoveNone;
\r
1150 send_pv(); // update display
\r
1152 return; // do not launch a new search
\r
1156 my_log("POLYGLOT PONDER -> THINK (miss)\n");
\r
1160 State->state = THINK;
\r
1161 State->exp_move = MoveNone;
\r
1164 } else if (State->state == ANALYSE) {
\r
1166 ASSERT(XB->analyse);
\r
1168 my_log("POLYGLOT ANALYSE -> ANALYSE\n");
\r
1180 // start_protected_command()
\r
1182 static void start_protected_command(){
\r
1186 static void end_protected_command(){
\r
1187 if(Uci->ready){ // not init faze
\r
1188 uci_send_isready_sync(Uci); // gobble up spurious "bestmove"
\r
1190 update_remaining_time();
\r
1191 search_update(); // relaunch search if necessary
\r
1194 // update_remaining_time()
\r
1196 static void update_remaining_time(){
\r
1198 if(State->timer->running){
\r
1199 my_timer_stop(State->timer);
\r
1200 reduce = my_timer_elapsed_real(State->timer);
\r
1201 my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce);
\r
1202 XB->my_time -= reduce;
\r
1203 if(XB->my_time<0.0){
\r
1210 // search_update()
\r
1212 static void search_update() {
\r
1218 ASSERT(!Uci->searching);
\r
1223 // launch a new search if needed
\r
1227 if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {
\r
1229 // [VdB] moved up as we need the move number
\r
1231 game_get_board(Game,Uci->board);
\r
1235 if (State->state == THINK &&
\r
1236 option_get_bool(Option,"Book") &&
\r
1237 Uci->board->move_nb<option_get_int(Option,"BookDepth")
\r
1241 move = book_move(Uci->board,option_get_bool(Option,"BookRandom"));
\r
1243 if (move != MoveNone && move_is_legal(move,Uci->board)) {
\r
1245 my_log("POLYGLOT *BOOK MOVE*\n");
\r
1247 search_clear(); // clears Uci->ponder_move
\r
1248 Uci->best_move = move;
\r
1250 board_copy(board,Uci->board);
\r
1251 move_do(board,move);
\r
1252 Uci->ponder_move = book_move(board,FALSE); // expected move = best book move
\r
1254 Uci->best_pv[0] = Uci->best_move;
\r
1255 Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone
\r
1256 Uci->best_pv[2] = MoveNone;
\r
1258 comp_move(Uci->best_move);
\r
1266 my_log("POLYGLOT START SEARCH\n");
\r
1270 uci_send_option(Uci,"UCI_Chess960","%s",
\r
1271 option_get_bool(Option,"Chess960")?"true":"false");
\r
1273 if (option_get_int(Option,"UCIVersion") >= 2) {
\r
1274 uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);
\r
1275 uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false");
\r
1278 uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false");
\r
1282 move = (State->state == PONDER) ? State->exp_move : MoveNone;
\r
1283 send_board(move); // updates Uci->board global variable
\r
1287 if (State->state == THINK || State->state == PONDER) {
\r
1289 engine_send_queue(Engine,"go");
\r
1291 if (XB->time_limit) {
\r
1293 // fixed time per move
\r
1295 if(XB->node_rate > 0){
\r
1296 engine_send_queue(Engine,
\r
1298 XB->time_max*((double)XB->node_rate));
\r
1300 engine_send_queue(Engine,
\r
1302 XB->time_max*1000.0);
\r
1309 if(XB->node_rate > 0) {
\r
1312 if (XB->mps != 0){
\r
1313 move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
\r
1315 time = XB->my_time / move_nb;
\r
1319 if(time > XB->my_time){
\r
1320 time = XB->my_time;
\r
1322 engine_send_queue(Engine,
\r
1324 time*XB->node_rate);
\r
1327 if (colour_is_white(Uci->board->turn)) {
\r
1328 engine_send_queue(Engine,
\r
1329 " wtime %.0f btime %.0f",
\r
1330 XB->my_time*1000.0,XB->opp_time*1000.0);
\r
1332 engine_send_queue(Engine,
\r
1333 " wtime %.0f btime %.0f",
\r
1334 XB->opp_time*1000.0,XB->my_time*1000.0);
\r
1337 if (XB->inc != 0.0){
\r
1338 engine_send_queue(Engine,
\r
1339 " winc %.0f binc %.0f",
\r
1340 XB->inc*1000.0,XB->inc*1000.0);
\r
1342 if (XB->mps != 0) {
\r
1344 move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
\r
1345 ASSERT(move_nb>=1&&move_nb<=XB->mps);
\r
1347 engine_send_queue(Engine," movestogo %d",move_nb);
\r
1351 if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);
\r
1353 if (State->state == PONDER) engine_send_queue(Engine," ponder");
\r
1355 engine_send(Engine,""); // newline
\r
1357 } else if (State->state == ANALYSE) {
\r
1359 engine_send(Engine,"go infinite");
\r
1366 // init search info
\r
1368 ASSERT(!Uci->searching);
\r
1372 Uci->searching = TRUE;
\r
1373 Uci->pending_nb++;
\r
1379 static void search_clear() {
\r
1385 my_timer_start(State->timer);//also resets
\r
1390 static bool active() {
\r
1394 if (game_status(Game) != PLAYING) return FALSE; // game ended
\r
1398 if (XB->analyse) return TRUE; // analysing
\r
1399 if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode
\r
1400 if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game
\r
1402 return TRUE; // playing
\r
1407 static bool ponder() {
\r
1409 return XB->ponder && (option_get_bool(Option,"CanPonder") ||
\r
1410 option_find(Uci->option,"Ponder"));
\r
1414 static bool ponder_ok(int move) {
\r
1418 ASSERT(move==MoveNone||move_is_ok(move));
\r
1420 // legal ponder move?
\r
1422 if (move == MoveNone) return FALSE;
\r
1424 game_get_board(Game,board);
\r
1425 if (!move_is_legal(move,board)) return FALSE;
\r
1427 // UCI-legal resulting position?
\r
1429 game_add_move(Game,move);
\r
1431 game_get_board(Game,board);
\r
1432 status = game_status(Game);
\r
1434 game_rem_move(Game);
\r
1436 if (status != PLAYING) return FALSE; // game ended
\r
1438 if (option_get_bool(Option,"Book") && is_in_book(board)) {
\r
1447 static void stop_search() {
\r
1449 if (Uci->searching) {
\r
1451 ASSERT(Uci->searching);
\r
1452 ASSERT(Uci->pending_nb>=1);
\r
1454 my_log("POLYGLOT STOP SEARCH\n");
\r
1457 engine_send(Engine,"stop");
\r
1458 Uci->searching = FALSE;
\r
1461 if (option_get_bool(Option,"SyncStop")) {
\r
1462 uci_send_stop_sync(Uci);
\r
1464 uci_send_stop(Uci);
\r
1471 static void send_board(int extra_move) {
\r
1480 ASSERT(extra_move==MoveNone||move_is_ok(extra_move));
\r
1482 ASSERT(!Uci->searching);
\r
1486 game_get_board(Game,Uci->board);
\r
1487 if (extra_move != MoveNone) move_do(Uci->board,extra_move);
\r
1489 board_to_fen(Uci->board,fen,256);
\r
1490 my_log("POLYGLOT FEN %s\n",fen);
\r
1492 ASSERT(board_can_play(Uci->board));
\r
1497 end = game_pos(Game);
\r
1498 ASSERT(end>=start);
\r
1502 game_get_board_ex(Game,board,start);
\r
1503 board_to_fen(board,string,256);
\r
1505 engine_send_queue(Engine,"position");
\r
1507 if (my_string_equal(string,StartFen)) {
\r
1508 engine_send_queue(Engine," startpos");
\r
1510 engine_send_queue(Engine," fen %s",string);
\r
1515 if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves");
\r
1517 for (pos = start; pos < end; pos++) { // game moves
\r
1519 move = game_move(Game,pos);
\r
1521 move_to_can(move,board,string,256);
\r
1522 engine_send_queue(Engine," %s",string);
\r
1524 move_do(board,move);
\r
1527 if (extra_move != MoveNone) { // move to ponder on
\r
1528 move_to_can(extra_move,board,string,256);
\r
1529 engine_send_queue(Engine," %s",string);
\r
1534 engine_send(Engine,""); // newline
\r
1539 static void send_info() {
\r
1541 if(option_get_bool(Option,"WbWorkArounds2")){
\r
1542 // Silly bug in some versions of WinBoard.
\r
1543 // depth <=1 clears the engine output window.
\r
1544 // Why shouldn't an engine be allowed to send info at depth 1?
\r
1549 gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth>min_depth?Uci->best_depth:min_depth,
\r
1550 0,0,0.0,0,Uci->info);
\r
1555 static void send_pv() {
\r
1557 char pv_string[StringSize];
\r
1560 char move_string[StringSize];
\r
1562 ASSERT(State->state!=WAIT);
\r
1564 if (Uci->best_depth == 0) return;
\r
1566 // xboard search information
\r
1570 if (State->state == THINK || State->state == ANALYSE) {
\r
1572 line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
\r
1574 if(Uci->depth==-1) //hack to clear the engine output window
\r
1575 gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb);
\r
1577 gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,pv_string);
\r
1579 } else if (State->state == PONDER &&
\r
1580 option_get_bool(Option,"ShowPonder")) {
\r
1582 game_get_board(Game,board);
\r
1583 move = State->exp_move;
\r
1585 if (move != MoveNone && move_is_legal(move,board)) {
\r
1586 move_to_san(move,board,move_string,256);
\r
1587 line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
\r
1588 gui_send(GUI,"%d %+d %.0f "S64_FORMAT" (%s) %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,move_string,pv_string);
\r
1595 if ((Uci->searching &&
\r
1596 option_get_bool(Option,"KibitzPV") &&
\r
1597 Uci->time >= option_get_double(Option,"KibitzDelay"))
\r
1598 || (!Uci->searching && option_get_bool(Option,"KibitzMove"))) {
\r
1600 if (State->state == THINK || State->state == ANALYSE) {
\r
1602 line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
\r
1603 if(kibitz_throttle(Uci->searching)){
\r
1604 gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"%s\"",option_get_string(Option,"KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,((double)report_best_score())/100.0,pv_string);
\r
1606 } else if (State->state == PONDER) {
\r
1608 game_get_board(Game,board);
\r
1609 move = State->exp_move;
\r
1611 if (move != MoveNone && move_is_legal(move,board)) {
\r
1612 move_to_san(move,board,move_string,256);
\r
1613 line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
\r
1614 if(kibitz_throttle(Uci->searching)){
\r
1615 gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"(%s) %s\"",option_get_string(Option,"KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,((double)report_best_score())/100.0,move_string,pv_string);
\r
1622 // kibitz_throttle()
\r
1624 static bool kibitz_throttle(bool searching){
\r
1626 static time_t lastKibitzMove=0;
\r
1627 static time_t lastKibitzPV=0;
\r
1628 curr_time = time(NULL);
\r
1629 if(searching){ // KibitzPV
\r
1631 (option_get_int(Option,"KibitzInterval") + lastKibitzPV)){
\r
1632 lastKibitzPV=curr_time;
\r
1635 }else{ // KibitzMove
\r
1637 (option_get_int(Option,"KibitzInterval") + lastKibitzMove)){
\r
1638 lastKibitzPV=curr_time;
\r
1639 lastKibitzMove=curr_time;
\r
1648 static void learn(int result) {
\r
1654 ASSERT(result>=-1&&result<=+1);
\r
1656 ASSERT(XB->result);
\r
1657 ASSERT(State->computer[White]||State->computer[Black]);
\r
1664 } else if (State->computer[White]) {
\r
1666 } else if (State->computer[Black]) {
\r
1670 my_fatal("learn(): unknown side\n");
\r
1674 } else if (result > 0) {
\r
1675 my_log("POLYGLOT *LEARN WIN*\n");
\r
1676 } else if (result < 0) {
\r
1677 my_log("POLYGLOT *LEARN LOSS*\n");
\r
1679 my_log("POLYGLOT *LEARN DRAW*\n");
\r
1684 for (; pos < Game->size; pos += 2) {
\r
1686 game_get_board_ex(Game,board,pos);
\r
1687 move = game_move(Game,pos);
\r
1689 book_learn_move(board,move,result);
\r
1695 // end of xboard2uci.c
\r