1 
2 // xboard2uci.c
3 
4 // includes
5 
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 
12 #include "board.h"
13 #include "book.h"
14 #include "colour.h"
15 #include "engine.h"
16 #include "fen.h"
17 #include "game.h"
18 #include "gui.h"
19 #include "line.h"
20 #include "main.h"
21 #include "move.h"
22 #include "move_do.h"
23 #include "move_legal.h"
24 #include "option.h"
25 #include "parse.h"
26 #include "san.h"
27 #include "uci.h"
28 #include "uci2uci.h"
29 #include "util.h"
30 #include "xboard2uci.h"
31 
32 // defines
33 
34 #define StringSize 4096
35 
36 // constants
37 
38 static const bool UseDebug = FALSE;
39 static const bool DelayPong = FALSE;
40 
41 // types
42 
43 typedef struct {
44    int state;
45    bool computer[ColourNb];
46    int exp_move;
47    int hint_move;
48    int resign_nb;
49    my_timer_t timer[1];
50 } state_t;
51 
52 typedef struct {
53     bool has_feature_memory;
54     bool has_feature_smp;
55     bool has_feature_egt_nalimov;
56     bool has_feature_egt_gaviota;
57     bool analyse;
58     bool computer;
59     const char * name;
60     bool ics;
61     bool new_hack; // "new" is a C++ keyword
62     bool ponder;
63     int ping;
64     bool post;
65     int proto_ver;
66     bool result;
67 
68     int mps;
69     double base;
70     double inc;
71 
72     bool time_limit;
73     double time_max;
74 
75     bool depth_limit;
76     int depth_max;
77 
78     double my_time;
79     double opp_time;
80 
81     int node_rate;
82 } xb_t;
83 
84 typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t;
85 
86 // variables
87 
88 static state_t State[1];
89 static xb_t XB[1];
90 
91 // prototypes
92 
93 static void comp_move      (int move);
94 static void move_step      (int move);
95 static void board_update   ();
96 
97 static void mess           ();
98 static void no_mess        (int move);
99 
100 static void search_update  ();
101 static void search_clear   ();
102 static void update_remaining_time();
103 static int  report_best_score();
104 static bool kibitz_throttle (bool searching);
105 static void start_protected_command();
106 static void end_protected_command();
107 
108 static bool active         ();
109 static bool ponder         ();
110 static bool ponder_ok      (int ponder_move);
111 
112 static void stop_search    ();
113 
114 static void send_board     (int extra_move);
115 static void send_pv        ();
116 static void send_info      ();
117 
118 static void send_xboard_options ();
119 
120 static void learn          (int result);
121 
122 
123 // functions
124 
125 // xboard2uci_init()
126 
xboard2uci_init()127 void xboard2uci_init() {
128    // init
129 
130    game_clear(Game);
131 
132    // state
133 
134    State->state = WAIT;
135 
136    State->computer[White] = FALSE;
137    State->computer[Black] = TRUE;
138 
139    State->exp_move = MoveNone;
140    State->hint_move = MoveNone;
141    State->resign_nb = 0;
142    my_timer_reset(State->timer);
143 
144    // yes there are engines that do not have the "Hash" option....
145    XB->has_feature_memory= (option_find(Uci->option,"Hash")!=NULL);
146    XB->has_feature_smp = (uci_thread_option(Uci)!=NULL);
147    // TODO: support for other types of table bases
148    // This is a quick hack.
149    XB->has_feature_egt_nalimov = (option_find(Uci->option,"NalimovPath")!=NULL);
150    XB->has_feature_egt_gaviota = (option_find(Uci->option,"GaviotaTbPath")!=NULL);
151    XB->analyse = FALSE;
152    XB->computer = FALSE;
153    XB->name = NULL;
154    my_string_set(&XB->name,"<empty>");
155    XB->ics = FALSE;
156    XB->new_hack = TRUE;
157    XB->ping = -1;
158    XB->ponder = FALSE;
159    XB->post = FALSE;
160    XB->proto_ver = 1;
161    XB->result = FALSE;
162 
163    XB->mps = 0;
164    XB->base = 300.0;
165    XB->inc = 0.0;
166 
167    XB->time_limit = FALSE;
168    XB->time_max = 5.0;
169 
170    XB->depth_limit = FALSE;
171    XB->depth_max = 127;
172 
173    XB->my_time = 300.0;
174    XB->opp_time = 300.0;
175 
176    XB->node_rate = -1;
177 }
178 
179 // xboard2uci_gui_step()
180 
xboard2uci_gui_step(char string[])181 void xboard2uci_gui_step(char string[]) {
182 
183 	int move;
184 	char move_string[256];
185 	board_t board[1];
186 
187 		if (FALSE) {
188 
189 		} else if (match(string,"accepted *")) {
190 
191 			// ignore
192 
193 		} else if (match(string,"analyze")) {
194 
195 			State->computer[White] = FALSE;
196 			State->computer[Black] = FALSE;
197 
198 			XB->analyse = TRUE;
199 			XB->new_hack = FALSE;
200 			ASSERT(!XB->result);
201 			XB->result = FALSE;
202 
203 			mess();
204 
205 		} else if (match(string,"bk")) {
206 
207 			if (option_get_bool(Option,"Book")) {
208 				game_get_board(Game,board);
209 				book_disp(board);
210 			}
211 
212 		} else if (match(string,"black")) {
213 
214 			if (colour_is_black(game_turn(Game))) {
215 
216 				State->computer[White] = TRUE;
217 				State->computer[Black] = FALSE;
218 
219 				XB->new_hack = TRUE;
220 				XB->result = FALSE;
221 
222 				mess();
223 			}
224 
225 		} else if (match(string,"computer")) {
226 
227 			XB->computer = TRUE;
228 
229 		} else if (match(string,"draw")) {
230 			if(option_find(Uci->option,"UCI_DrawOffers")){
231 			    my_log("POLYGLOT draw from XB received");
232 				uci_send_option(Uci,"DrawOffer","%s","draw");}
233 		} else if (match(string,"easy")) {
234 
235 			XB->ponder = FALSE;
236 
237 			mess();
238 
239 		} else if (match(string,"edit")) {
240 
241 			// refuse
242 
243 			gui_send(GUI,"Error (unknown command): %s",string);
244 
245 		} else if (match(string,"exit")) {
246 
247 			State->computer[White] = FALSE;
248 			State->computer[Black] = FALSE;
249 
250 			XB->analyse = FALSE;
251 
252 			mess();
253 
254 		} else if (match(string,"force")) {
255 
256 			State->computer[White] = FALSE;
257 			State->computer[Black] = FALSE;
258 
259 			mess();
260 
261 		} else if (match(string,"go")) {
262 
263 			State->computer[game_turn(Game)] = TRUE;
264 			State->computer[colour_opp(game_turn(Game))] = FALSE;
265 
266 			XB->new_hack = FALSE;
267 			ASSERT(!XB->result);
268 			XB->result = FALSE;
269 
270 			mess();
271 
272 		} else if (match(string,"hard")) {
273 
274 			XB->ponder = TRUE;
275 
276 			mess();
277 
278 		} else if (match(string,"hint")) {
279 
280 		        move=MoveNone;
281 			game_get_board(Game,board);
282 			if (option_get_bool(Option,"Book")) {
283 
284 				move = book_move(board,FALSE);
285 			}
286 			if(move==MoveNone && State->hint_move!=MoveNone){
287 			    move=State->hint_move;
288 
289 			}
290 			if (move != MoveNone && move_is_legal(move,board)) {
291 			    move_to_san(move,board,move_string,256);
292 			    gui_send(GUI,"Hint: %s",move_string);
293 			}
294 
295 		} else if (match(string,"ics *")) {
296 
297 			XB->ics = TRUE;
298 
299 		} else if (match(string,"level * *:* *")) {
300 
301 			XB->mps  = atoi(Star[0]);
302 			XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2]));
303 			XB->inc  = ((double)atoi(Star[3]));
304 
305 		} else if (match(string,"level * * *")) {
306 
307 			XB->mps  = atoi(Star[0]);
308 			XB->base = ((double)atoi(Star[1])) * 60.0;
309 			XB->inc  = ((double)atoi(Star[2]));
310 
311 		} else if (match(string,"name *")) {
312 
313 			my_string_set(&XB->name,Star[0]);
314 
315 		} else if (match(string,"new")) {
316 
317 		    uci_send_isready_sync(Uci);
318 			my_log("POLYGLOT NEW GAME\n");
319 
320 			option_set(Option,"Chess960","false");
321 
322 			game_clear(Game);
323 
324 			if (XB->analyse) {
325 				State->computer[White] = FALSE;
326 				State->computer[Black] = FALSE;
327 			} else {
328 				State->computer[White] = FALSE;
329 				State->computer[Black] = TRUE;
330 			}
331 
332 			XB->new_hack = TRUE;
333 			XB->result = FALSE;
334 
335 			XB->depth_limit = FALSE;
336             XB->node_rate=-1;
337 
338 			XB->computer = FALSE;
339 			my_string_set(&XB->name,"<empty>");
340 
341 			board_update();
342 			mess();
343 
344 			uci_send_ucinewgame(Uci);
345 
346 		} else if (match(string,"nopost")) {
347 
348 			XB->post = FALSE;
349 
350 		} else if (match(string,"otim *")) {
351 
352 			XB->opp_time = ((double)atoi(Star[0])) / 100.0;
353 			if (XB->opp_time < 0.0) XB->opp_time = 0.0;
354 
355 		} else if (match(string,"pause")) {
356 
357 			// refuse
358 
359 			gui_send(GUI,"Error (unknown command): %s",string);
360 
361 		} else if (match(string,"ping *")) {
362 
363 			// HACK; TODO: answer only after an engine move
364 
365 			if (DelayPong) {
366 				if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping
367 				XB->ping = atoi(Star[0]);
368 				uci_send_isready_sync(Uci);
369 			} else {
370 				ASSERT(XB->ping==-1);
371 				gui_send(GUI,"pong %s",Star[0]);
372 			}
373         } else if (match(string,"nps *")) {
374 
375                 // fake WB play-by-nodes mode
376             XB->node_rate = atoi(Star[0]);
377 		} else if (match(string,"playother")) {
378 
379 			State->computer[game_turn(Game)] = FALSE;
380 			State->computer[colour_opp(game_turn(Game))] = TRUE;
381 
382 			XB->new_hack = FALSE;
383 			ASSERT(!XB->result);
384 			XB->result = FALSE;
385 
386 			mess();
387 
388 		} else if (match(string,"post")) {
389 
390 			XB->post = TRUE;
391 
392 		} else if (match(string,"protover *")) {
393             XB->proto_ver = atoi(Star[0]);
394             ASSERT(XB->proto_ver>=2);
395             send_xboard_options();
396 
397 		} else if (match(string,"quit")) {
398 			my_log("POLYGLOT *** \"quit\" from GUI ***\n");
399 			quit();
400 		} else if (match(string,"random")) {
401 
402 			// ignore
403 
404 		} else if (match(string,"rating * *")) {
405 
406 			// ignore
407 
408 		} else if (match(string,"remove")) {
409 
410 			if (game_pos(Game) >= 2) {
411 
412 				game_goto(Game,game_pos(Game)-2);
413 
414 				ASSERT(!XB->new_hack);
415 				XB->new_hack = FALSE; // HACK?
416 				XB->result = FALSE;
417 
418 				board_update();
419 				mess();
420 			}
421 
422 		} else if (match(string,"rejected *")) {
423 
424 			// ignore
425 
426 		} else if (match(string,"reset")) { // protover 3?
427 
428 			// refuse
429 
430 			gui_send(GUI,"Error (unknown command): %s",string);
431 
432 		} else if (FALSE
433 			|| match(string,"result * {*}")
434 			|| match(string,"result * {* }")
435 			|| match(string,"result * { *}")
436 			|| match(string,"result * { * }")) {
437 
438 				my_log("POLYGLOT GAME END\n");
439 
440 				XB->result = TRUE;
441 
442 				mess();
443 
444 				// book learning
445 
446 				if (FALSE && option_get_bool(Option,"Book") &&
447                     option_get_bool(Option,"BookLearn")) {
448 
449 					if (FALSE) {
450 					} else if (my_string_equal(Star[0],"1-0")) {
451 						learn(+1);
452 					} else if (my_string_equal(Star[0],"0-1")) {
453 						learn(-1);
454 					} else if (my_string_equal(Star[0],"1/2-1/2")) {
455 						learn(0);
456 					}
457 				}
458 		} else if (match(string,"resume")) {
459 
460 			// refuse
461 
462 			gui_send(GUI,"Error (unknown command): %s",string);
463 
464         } else if (match(string,"option *=*")   ||
465                    match(string,"option * =*") ||
466                    match(string,"option *= *") ||
467                    match(string,"option * = *")
468                    ){
469             char *name=Star[0];
470             char *value=Star[1];
471             if(match(name, "Polyglot *")){
472                 char *pg_name=Star[0];
473                 polyglot_set_option(pg_name,value);
474             }else{
475                 option_t *opt=option_find(Uci->option,name);
476                 if(opt){
477                     if(my_string_case_equal(opt->type,"check")){
478                        value=my_string_equal(value,"1")?"true":"false";
479                     }
480                     start_protected_command();
481                     uci_send_option(Uci, name, "%s", value);
482                     end_protected_command();
483                 }else{
484                     gui_send(GUI,"Error (unknown option): %s",name);
485                 }
486             }
487         } else if (match(string,"option *")){
488             char *name=Star[0];
489              if(match(name, "Polyglot *")){
490                 char *pg_name=Star[0];
491                 polyglot_set_option(pg_name,"<empty>");
492 	     }else{
493 	       start_protected_command();
494                 // value is ignored
495 	       if(!uci_send_option(Uci, name, "%s", "<empty>")){
496 		 gui_send(GUI,"Error (unknown option): %s",name);
497 	       };
498 	       end_protected_command();
499 	     }
500         } else if (XB->has_feature_smp && match(string,"cores *")){
501                 int cores=atoi(Star[0]);
502                 if(cores>=1){
503                     // updating the number of cores
504                     my_log("POLYGLOT setting the number of cores to %d\n",cores);
505                     start_protected_command();
506                     uci_set_threads(Uci,cores);
507                     end_protected_command();
508                 } else{
509                    // refuse
510                     gui_send(GUI,"Error (unknown command): %s",string);
511                 }
512         } else if (match(string,"egtpath * *")){
513                 char *type=Star[0];
514                 char *path=Star[1];
515                 if(my_string_empty(path)){
516                     // refuse
517                     gui_send(GUI,"Error (unknown command): %s",string);
518                 }else{
519 		    if(my_string_case_equal(type,"nalimov") && XB->has_feature_egt_nalimov){
520 			// updating NalimovPath
521 			my_log("POLYGLOT setting the Nalimov path to %s\n",path);
522 			start_protected_command();
523 			uci_send_option(Uci,"NalimovPath","%s",path);
524 			end_protected_command();
525 		    }else if(my_string_case_equal(type,"gaviota") && XB->has_feature_egt_gaviota){
526 			// updating GaviotaPath
527 			my_log("POLYGLOT setting the Gaviota path to %s\n",path);
528 			start_protected_command();
529 			uci_send_option(Uci,"GaviotaTbPath","%s",path);
530 			end_protected_command();
531 		    }else{
532 			// refuse
533 			gui_send(GUI,"Error (unsupported table base format): %s",string);
534 		    }
535                 }
536         } else if (XB->has_feature_memory && match(string,"memory *")){
537             int memory = atoi(Star[0]);
538             int egt_cache;
539             int real_memory;
540             if(memory>=1){
541                 // updating the available memory
542                 option_t *opt;
543                 my_log("POLYGLOT setting the amount of memory to %dMb\n",memory);
544                 if(XB->has_feature_egt_nalimov && (opt=option_find(Uci->option,"NalimovCache"))){
545                     egt_cache=atoi(opt->value);
546                 }else if(XB->has_feature_egt_gaviota &&
547 			 (opt=option_find(Uci->option,"GaviotaTbCache"))){
548 		    egt_cache=atoi(opt->value);
549 		}else{
550                     egt_cache=0;
551                 }
552                 my_log("POLYGLOT EGTB Cache is %dMb\n",egt_cache);
553                 real_memory=memory-egt_cache;
554                 if(real_memory>0){
555                     start_protected_command();
556                     uci_send_option(Uci,"Hash", "%d", real_memory);
557                     end_protected_command();
558                 }
559             }else{
560                 // refuse
561                 gui_send(GUI,"Error (unknown command): %s",string);
562             }
563 
564 		} else if (match(string,"sd *")) {
565 
566 			XB->depth_limit = TRUE;
567 			XB->depth_max = atoi(Star[0]);
568 
569 		} else if (match(string,"setboard *")) {
570 
571 			my_log("POLYGLOT FEN %s\n",Star[0]);
572 
573 			if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]);
574 
575 			State->computer[White] = FALSE;
576 			State->computer[Black] = FALSE;
577 
578 			XB->new_hack = TRUE; // HACK?
579 			XB->result = FALSE;
580 
581 			board_update();
582 			mess();
583 
584 		} else if (match(string,"st *")) {
585 
586 			XB->time_limit = TRUE;
587 			XB->time_max = ((double)atoi(Star[0]));
588 
589 		} else if (match(string,"time *")) {
590 
591 			XB->my_time = ((double)atoi(Star[0])) / 100.0;
592 			if (XB->my_time < 0.0) XB->my_time = 0.0;
593 
594 		} else if (match(string,"undo")) {
595 
596 			if (game_pos(Game) >= 1) {
597 
598 				game_goto(Game,game_pos(Game)-1);
599 
600 				ASSERT(!XB->new_hack);
601 				XB->new_hack = FALSE; // HACK?
602 				XB->result = FALSE;
603 
604 				board_update();
605 				mess();
606 			}
607 
608 		} else if (match(string,"usermove *")) {
609 
610 			game_get_board(Game,board);
611 			move = move_from_san(Star[0],board);
612 
613 			if (move != MoveNone && move_is_legal(move,board)) {
614 
615 				XB->new_hack = FALSE;
616 				ASSERT(!XB->result);
617 				XB->result = FALSE;
618 
619 				move_step(move);
620 				no_mess(move);
621 
622 			} else {
623 
624 				gui_send(GUI,"Illegal move: %s",Star[0]);
625 			}
626 
627 		} else if (match(string,"variant *")) {
628 
629 			if (my_string_equal(Star[0],"fischerandom")) {
630 				option_set(Option,"Chess960","true");
631 			} else {
632 				option_set(Option,"Chess960","false");
633 			}
634 
635 		} else if (match(string,"white")) {
636 
637 			if (colour_is_white(game_turn(Game))) {
638 
639 				State->computer[White] = FALSE;
640 				State->computer[Black] = TRUE;
641 
642 				XB->new_hack = TRUE;
643 				XB->result = FALSE;
644 
645 				mess();
646 			}
647 
648 		} else if (match(string,"xboard")) {
649 
650 			// ignore
651 
652 		} else if (match(string,".")) { // analyse info
653 
654 			if (State->state == ANALYSE) {
655 				int depth=Uci->best_depth;//HACK: don't clear engine-output window...
656 
657 				ASSERT(Uci->searching);
658 				ASSERT(Uci->pending_nb>=1);
659 
660 				if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) {
661 					move_to_san(Uci->root_move,Uci->board,move_string,256);
662 					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);
663 				} else {
664 					gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK
665 				}
666 			}
667 
668 		} else if (match(string,"?")) { // move now
669 
670 			if (State->state == THINK) {
671 
672 				ASSERT(Uci->searching);
673 				ASSERT(Uci->pending_nb>=1);
674 
675 				// HACK: just send "stop" to the engine
676 
677 				if (Uci->searching) {
678 					my_log("POLYGLOT STOP SEARCH\n");
679 					engine_send(Engine,"stop");
680 				}
681 			}
682 
683 		} else { // unknown command, maybe a move?
684 
685 			game_get_board(Game,board);
686 			move = move_from_san(string,board);
687 
688 			if (move != MoveNone && move_is_legal(move,board)) {
689 
690 				XB->new_hack = FALSE;
691 				ASSERT(!XB->result);
692 				XB->result = FALSE;
693 
694 				move_step(move);
695 				no_mess(move);
696 
697 			} else if (move != MoveNone) {
698 
699 				gui_send(GUI,"Illegal move: %s",string);
700 
701 			} else {
702 
703 				gui_send(GUI,"Error (unknown command): %s",string);
704 			}
705 		}
706 	return;
707 }
708 
709 // xboard2uci_engine_step()
710 
xboard2uci_engine_step(char string[])711 void xboard2uci_engine_step(char string[]) {
712 
713 	int event;
714     board_t board[1];
715 		event = uci_parse(Uci,string);
716 
717 		// react to events
718 
719 		if ((event & EVENT_READY) != 0) {
720 
721 			// the engine is now ready
722 
723 			if (!Uci->ready) {
724 				Uci->ready = TRUE;
725                     //	if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1");
726 			}
727 
728 			if (!DelayPong && XB->ping >= 0) {
729 				gui_send(GUI,"pong %d",XB->ping);
730 				XB->ping = -1;
731 			}
732 		}
733 
734 		if ((event & EVENT_MOVE) != 0 && State->state == THINK) {
735 
736 			// the engine is playing a move
737 
738 			// MEGA HACK: estimate remaining time because XBoard won't send it!
739 
740 			my_timer_stop(State->timer);
741 
742 			XB->my_time -= my_timer_elapsed_real(State->timer);
743 			XB->my_time += XB->inc;
744 			if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base;
745 
746 			if (XB->my_time < 0.0) XB->my_time = 0.0;
747 
748 			// make sure to remember the ponder move
749 
750 			State->hint_move=Uci->ponder_move;
751 
752 			// play the engine move
753 
754 			comp_move(Uci->best_move);
755 
756 		}
757 
758 		if ((event & EVENT_PV) != 0) {
759 
760 			// the engine has sent a new PV
761 
762 			send_pv();
763 		}
764 		if ((event & EVENT_INFO) != 0) {
765 
766 			// the engine has sent info
767 
768 			send_info();
769 		}
770 		if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){
771 			my_log("POYGLOT draw offer/resign from engine\n");
772 			if(option_find(Uci->option,"UCI_DrawOffers")){
773 				if(event & EVENT_DRAW)
774 					gui_send(GUI,"offer draw");
775 				else
776 					gui_send(GUI,"resign");
777 			}
778 		}
779 		if(((event & EVENT_ILLEGAL_MOVE)!=0) && (State->state == THINK)){
780 		    game_get_board(Game,board);
781 		    if(board->turn==White){
782 			gui_send(GUI,"0-1 {polyglot: resign"
783 				 " (illegal engine move by white: %s)}",Uci->bestmove);
784 		    }else{
785 			gui_send(GUI,"1-0 {polyglot: resign"
786 				 " (illegal engine move by black: %s)}",Uci->bestmove);
787 		    }
788 		    board_disp(board);
789 		    XB->result = TRUE;
790 		    mess();
791 		}
792 }
793 
794 // format_xboard_option_line
795 
format_xboard_option_line(char * option_line,option_t * opt)796 void format_xboard_option_line(char * option_line, option_t *opt){
797     int j;
798     char option_string[StringSize];
799     char *tmp;
800     strcpy(option_line,"");
801         // buffer overflow alert
802     strcat(option_line,"feature option=\"");
803     if(opt->mode&PG){
804         strcat(option_line,"Polyglot ");
805     }
806     sprintf(option_string,"%s",opt->name);
807     strcat(option_line,option_string);
808     sprintf(option_string," -%s",opt->type);
809     strcat(option_line,option_string);
810     if(!IS_BUTTON(opt->type) && strcmp(opt->type,"combo")){
811         if(strcmp(opt->type,"check")){
812             sprintf(option_string," %s",opt->value);
813         }else{
814             sprintf(option_string," %d",
815                     my_string_case_equal(opt->value,"true")||
816                     my_string_equal(opt->value,"1")
817                     ?1:0);
818         }
819         strcat(option_line,option_string);
820     }
821     if(IS_SPIN(opt->type)){
822         sprintf(option_string," %s",opt->min);
823             strcat(option_line,option_string);
824     }
825     if(IS_SPIN(opt->type)){
826         sprintf(option_string," %s",opt->max);
827         strcat(option_line,option_string);
828     }
829     for(j=0;j<opt->var_nb;j++){
830         if(!strcmp(opt->var[j],opt->value)){
831             sprintf(option_string," *%s",opt->var[j]);
832         }else{
833             sprintf(option_string," %s",opt->var[j]);
834         }
835         strcat(option_line,option_string);
836         if(j!=opt->var_nb-1){
837             strcat(option_line," ///");
838         }
839     }
840     strcat(option_line,"\"");
841     if(option_get_bool(Option,"WbWorkArounds") &&
842        (tmp=strstr(option_line,"Draw"))){
843         *tmp='d';
844         my_log("POLYGLOT Decapitalizing \"Draw\" in option \"%s\"\n",
845                opt->name);
846     }
847 }
848 
849 // send_xboard_options()
850 
send_xboard_options()851 static void send_xboard_options(){
852 
853     char egtfeature[StringSize];
854     int tbs=0;
855 
856     gui_send(GUI,"feature done=0");
857 
858     gui_send(GUI,"feature analyze=1");
859     gui_send(GUI,"feature colors=0");
860     gui_send(GUI,"feature draw=1");
861     gui_send(GUI,"feature ics=1");
862     gui_send(GUI,"feature myname=\"%s\"",
863              option_get_string(Option,"EngineName"));
864     gui_send(GUI,"feature name=1");
865     gui_send(GUI,"feature pause=0");
866     gui_send(GUI,"feature ping=1");
867     gui_send(GUI,"feature playother=1");
868     gui_send(GUI,"feature sigint=1");
869     gui_send(GUI,"feature reuse=1");
870     gui_send(GUI,"feature san=0");
871     gui_send(GUI,"feature setboard=1");
872     gui_send(GUI,"feature sigint=0");
873     gui_send(GUI,"feature sigterm=0");
874     gui_send(GUI,"feature time=1");
875     gui_send(GUI,"feature usermove=1");
876     gui_send(GUI,"feature nps=1");
877     if (XB->has_feature_memory){
878         gui_send(GUI,"feature memory=1");
879     }else{
880         gui_send(GUI,"feature memory=0");
881     }
882     if (XB->has_feature_smp){
883         gui_send(GUI,"feature smp=1");
884     }else{
885         gui_send(GUI,"feature smp=0");
886     }
887     egtfeature[0]='\0';
888     strncat(egtfeature,"feature egt=\"",StringSize);
889     if (XB->has_feature_egt_nalimov){
890 	tbs++;
891 	strncat(egtfeature,"nalimov",StringSize-strlen(egtfeature));
892     }
893     if (XB->has_feature_egt_gaviota){
894 	if(tbs>0){
895 	    strncat(egtfeature,",",StringSize-strlen(egtfeature));
896 	}
897 	strncat(egtfeature,"gaviota",StringSize-strlen(egtfeature));
898     }
899     strncat(egtfeature,"\"",StringSize-strlen(egtfeature));
900     egtfeature[StringSize-1]='\0';
901     gui_send(GUI,egtfeature);
902 
903     if (option_find(Uci->option,"UCI_Chess960")) {
904         gui_send(GUI,"feature variants=\"normal,fischerandom\"");
905     } else {
906         gui_send(GUI,"feature variants=\"normal\"");
907     }
908 
909     xboard2uci_send_options();
910 }
911 
xboard2uci_send_options()912 void xboard2uci_send_options(){
913   char option_line[StringSize]="";
914   const char * name;
915   option_t *opt;
916 
917   option_start_iter(Uci->option);
918   while((opt=option_next(Uci->option))){
919     if(my_string_case_equal(opt->name,"UCI_AnalyseMode")) continue;
920     if(my_string_case_equal(opt->name,"UCI_Opponent")) continue;
921     if(my_string_case_equal(opt->name,"UCI_Chess960")) continue;
922     if(my_string_case_equal(opt->name,"UCI_ShowCurrLine")) continue;
923     if(my_string_case_equal(opt->name,"UCI_ShowRefutations")) continue;
924     if(my_string_case_equal(opt->name,"UCI_ShredderbasesPath")) continue;
925     if(my_string_case_equal(opt->name,"UCI_SetPositionValue")) continue;
926     if(my_string_case_equal(opt->name,"UCI_DrawOffers")) continue;
927     if(my_string_case_equal(opt->name,"Ponder")) continue;
928     if(my_string_case_equal(opt->name,"Hash")) continue;
929     if(my_string_case_equal(opt->name,"NalimovPath")) continue;
930     if(my_string_case_equal(opt->name,"GaviotaTbPath")) continue;
931     if((name=uci_thread_option(Uci))!=NULL &&
932        my_string_case_equal(opt->name,name)) continue;
933     format_xboard_option_line(option_line,opt);
934 
935     gui_send(GUI,"%s",option_line);
936   }
937 
938 
939   option_start_iter(Option);
940   while((opt=option_next(Option))){
941     if(opt->mode &XBOARD){
942       format_xboard_option_line(option_line,opt);
943       gui_send(GUI,"%s",option_line);
944     }
945   }
946   gui_send(GUI,"feature done=1");
947 
948 }
949 
950 // report_best_score()
951 
report_best_score()952 static int report_best_score(){
953     if(!option_get_bool(Option,"ScoreWhite") ||
954        colour_is_white(Uci->board->turn)){
955         return Uci->best_score;
956     }else{
957         return -Uci->best_score;
958     }
959 }
960 
961 // comp_move()
962 
comp_move(int move)963 static void comp_move(int move) {
964 
965    board_t board[1];
966    char string[256];
967 
968    ASSERT(move_is_ok(move));
969 
970    ASSERT(State->state==THINK);
971    ASSERT(!XB->analyse);
972 
973    if(option_get_bool(Option,"RepeatPV"))
974 	   send_pv(); // to update time and nodes
975 
976    // send the move
977 
978    game_get_board(Game,board);
979 
980    if (move_is_castle(move,board) && option_get_bool(Option,"Chess960")) {
981       if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O
982    } else {
983       if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n");
984    }
985 
986    gui_send(GUI,"move %s",string);
987 
988    // resign?
989 
990    if (option_get_bool(Option,"Resign") && Uci->root_move_nb > 1) {
991 
992        if (Uci->best_score <= -abs(option_get_int(Option,"ResignScore"))) {
993 
994          State->resign_nb++;
995          my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":"");
996 
997          if (State->resign_nb >= option_get_int(Option,"ResignMoves")) {
998             my_log("POLYGLOT *** RESIGN ***\n");
999             gui_send(GUI,"resign");
1000          }
1001 
1002       } else {
1003 
1004          if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb);
1005          State->resign_nb = 0;
1006       }
1007    }
1008 
1009    // play the move
1010 
1011    move_step(move);
1012    no_mess(move);
1013 }
1014 
1015 // move_step()
1016 
move_step(int move)1017 static void move_step(int move) {
1018 
1019    board_t board[1];
1020    char move_string[256];
1021 
1022    ASSERT(move_is_ok(move));
1023 
1024    // log
1025 
1026    game_get_board(Game,board);
1027 
1028    if (move != MoveNone && move_is_legal(move,board)) {
1029 
1030       move_to_san(move,board,move_string,256);
1031       my_log("POLYGLOT MOVE %s\n",move_string);
1032 
1033    } else {
1034 
1035       move_to_can(move,board,move_string,256);
1036       my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string);
1037       board_disp(board);
1038 
1039       my_fatal("move_step(): illegal move \"%s\"\n",move_string);
1040    }
1041 
1042    // play the move
1043 
1044    game_add_move(Game,move);
1045    board_update();
1046 }
1047 
1048 // board_update()
1049 
board_update()1050 static void board_update() {
1051 
1052    // handle game end
1053 
1054    ASSERT(!XB->result);
1055 
1056    switch (game_status(Game)) {
1057    case PLAYING:
1058       break;
1059    case WHITE_MATES:
1060       gui_send(GUI,"1-0 {White mates}");
1061       break;
1062    case BLACK_MATES:
1063       gui_send(GUI,"0-1 {Black mates}");
1064       break;
1065    case STALEMATE:
1066       gui_send(GUI,"1/2-1/2 {Stalemate}");
1067       break;
1068    case DRAW_MATERIAL:
1069       gui_send(GUI,"1/2-1/2 {Draw by insufficient material}");
1070       break;
1071    case DRAW_FIFTY:
1072       gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}");
1073       break;
1074    case DRAW_REPETITION:
1075       gui_send(GUI,"1/2-1/2 {Draw by repetition}");
1076       break;
1077    default:
1078       ASSERT(FALSE);
1079       break;
1080    }
1081 }
1082 
1083 // mess()
1084 
mess()1085 static void mess() {
1086 
1087    // clear state variables
1088 
1089    State->resign_nb = 0;
1090    State->exp_move = MoveNone;
1091    my_timer_reset(State->timer);
1092 
1093    // abort a possible search
1094 
1095    stop_search();
1096 
1097    // calculate the new state
1098 
1099    if (FALSE) {
1100    } else if (!active()) {
1101       State->state = WAIT;
1102       my_log("POLYGLOT WAIT\n");
1103    } else if (XB->analyse) {
1104       State->state = ANALYSE;
1105       my_log("POLYGLOT ANALYSE\n");
1106    } else if (State->computer[game_turn(Game)]) {
1107       State->state = THINK;
1108       my_log("POLYGLOT THINK\n");
1109    } else {
1110       State->state = WAIT;
1111       my_log("POLYGLOT WAIT\n");
1112    }
1113 
1114    search_update();
1115 }
1116 
1117 // no_mess()
1118 
no_mess(int move)1119 static void no_mess(int move) {
1120 
1121    ASSERT(move_is_ok(move));
1122 
1123    // just received a move, calculate the new state
1124 
1125    if (FALSE) {
1126 
1127    } else if (!active()) {
1128 
1129       stop_search(); // abort a possible search
1130 
1131       State->state = WAIT;
1132       State->exp_move = MoveNone;
1133 
1134       my_log("POLYGLOT WAIT\n");
1135 
1136    } else if (State->state == WAIT) {
1137 
1138       ASSERT(State->computer[game_turn(Game)]);
1139       ASSERT(!State->computer[colour_opp(game_turn(Game))]);
1140       ASSERT(!XB->analyse);
1141 
1142       my_log("POLYGLOT WAIT -> THINK\n");
1143 
1144       State->state = THINK;
1145       State->exp_move = MoveNone;
1146 
1147    } else if (State->state == THINK) {
1148 
1149       ASSERT(!State->computer[game_turn(Game)]);
1150       ASSERT(State->computer[colour_opp(game_turn(Game))]);
1151       ASSERT(!XB->analyse);
1152 
1153       if (ponder() && ponder_ok(Uci->ponder_move)) {
1154 
1155          my_log("POLYGLOT THINK -> PONDER\n");
1156 
1157          State->state = PONDER;
1158          State->exp_move = Uci->ponder_move;
1159 
1160       } else {
1161 
1162          my_log("POLYGLOT THINK -> WAIT\n");
1163 
1164          State->state = WAIT;
1165          State->exp_move = MoveNone;
1166       }
1167 
1168    } else if (State->state == PONDER) {
1169 
1170       ASSERT(State->computer[game_turn(Game)]);
1171       ASSERT(!State->computer[colour_opp(game_turn(Game))]);
1172       ASSERT(!XB->analyse);
1173 
1174       if (move == State->exp_move && Uci->searching) {
1175 
1176          ASSERT(Uci->searching);
1177          ASSERT(Uci->pending_nb>=1);
1178 
1179          my_timer_start(State->timer);//also resets
1180 
1181          my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n");
1182          engine_send(Engine,"ponderhit");
1183 
1184          State->state = THINK;
1185          State->exp_move = MoveNone;
1186 
1187          send_pv(); // update display
1188 
1189          return; // do not launch a new search
1190 
1191       } else {
1192 
1193          my_log("POLYGLOT PONDER -> THINK (miss)\n");
1194 
1195          stop_search();
1196 
1197          State->state = THINK;
1198          State->exp_move = MoveNone;
1199       }
1200 
1201    } else if (State->state == ANALYSE) {
1202 
1203       ASSERT(XB->analyse);
1204 
1205       my_log("POLYGLOT ANALYSE -> ANALYSE\n");
1206 
1207       stop_search();
1208 
1209    } else {
1210 
1211       ASSERT(FALSE);
1212    }
1213 
1214    search_update();
1215 }
1216 
1217 // start_protected_command()
1218 
start_protected_command()1219 static void start_protected_command(){
1220     stop_search();
1221 }
1222 
end_protected_command()1223 static void end_protected_command(){
1224     if(Uci->ready){ // not init faze
1225         uci_send_isready_sync(Uci); // gobble up spurious "bestmove"
1226     }
1227     update_remaining_time();
1228     search_update();   // relaunch search if necessary
1229 }
1230 
1231 // update_remaining_time()
1232 
update_remaining_time()1233 static void update_remaining_time(){
1234    double reduce;
1235    if(State->timer->running){
1236        my_timer_stop(State->timer);
1237        reduce = my_timer_elapsed_real(State->timer);
1238        my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce);
1239        XB->my_time -= reduce;
1240        if(XB->my_time<0.0){
1241            XB->my_time=0.0;
1242        }
1243    }
1244 }
1245 
1246 
1247 // search_update()
1248 
search_update()1249 static void search_update() {
1250 
1251    int move;
1252    int move_nb;
1253    board_t board[1];
1254 
1255    ASSERT(!Uci->searching);
1256 
1257 
1258 
1259 
1260    // launch a new search if needed
1261 
1262 
1263 
1264    if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {
1265 
1266       // [VdB] moved up as we need the move number
1267 
1268        game_get_board(Game,Uci->board);
1269 
1270       // opening book
1271 
1272        if (State->state == THINK &&
1273            option_get_bool(Option,"Book") &&
1274            Uci->board->move_nb<option_get_int(Option,"BookDepth")
1275            ) {
1276 
1277 
1278          move = book_move(Uci->board,option_get_bool(Option,"BookRandom"));
1279 
1280          if (move != MoveNone && move_is_legal(move,Uci->board)) {
1281 
1282             my_log("POLYGLOT *BOOK MOVE*\n");
1283 
1284             search_clear(); // clears Uci->ponder_move
1285             Uci->best_move = move;
1286 
1287             board_copy(board,Uci->board);
1288             move_do(board,move);
1289             Uci->ponder_move = book_move(board,FALSE); // expected move = best book move
1290 
1291             Uci->best_pv[0] = Uci->best_move;
1292             Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone
1293             Uci->best_pv[2] = MoveNone;
1294 
1295             comp_move(Uci->best_move);
1296 
1297             return;
1298          }
1299       }
1300 
1301       // engine search
1302 
1303       my_log("POLYGLOT START SEARCH\n");
1304 
1305       // options
1306 
1307       uci_send_option(Uci,"UCI_Chess960","%s",
1308                       option_get_bool(Option,"Chess960")?"true":"false");
1309 
1310       if (option_get_int(Option,"UCIVersion") >= 2) {
1311          uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);
1312          uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false");
1313       }
1314 
1315       uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false");
1316 
1317       // position
1318 
1319       move = (State->state == PONDER) ? State->exp_move : MoveNone;
1320       send_board(move); // updates Uci->board global variable
1321 
1322       // search
1323 
1324       if (State->state == THINK || State->state == PONDER) {
1325 
1326          engine_send_queue(Engine,"go");
1327 
1328          if (XB->time_limit) {
1329 
1330             // fixed time per move
1331 
1332              if(XB->node_rate > 0){
1333                  engine_send_queue(Engine,
1334                                    " nodes %.0f",
1335                                    XB->time_max*((double)XB->node_rate));
1336              }else{
1337 		 double computed_time;
1338 		 double st_fudge;
1339 		 st_fudge=(double) option_get_int(Option,"STFudge");
1340 		 my_log("POLYGLOT Giving engine %.0fmsec extra time.\n",st_fudge);
1341 		 computed_time=XB->time_max*1000.0-st_fudge;
1342 		 if(computed_time< 1.0){
1343 		     computed_time=1.0;
1344 		 }
1345                  engine_send_queue(Engine,
1346                                    " movetime %.0f",
1347                                    computed_time);
1348              }
1349 
1350          } else {
1351 
1352             // time controls
1353 
1354                  if(XB->node_rate > 0) {
1355                      double time;
1356                      move_nb = 40;
1357                      if (XB->mps != 0){
1358                          move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
1359                      }
1360                      time = XB->my_time / move_nb;
1361                      if(XB->inc != 0){
1362                          time += XB->inc;
1363                      }
1364                      if(time > XB->my_time){
1365                          time = XB->my_time;
1366                      }
1367                      engine_send_queue(Engine,
1368                                        " nodes %.0f",
1369                                        time*XB->node_rate);
1370                  } else {
1371 
1372                      if (colour_is_white(Uci->board->turn)) {
1373                          engine_send_queue(Engine,
1374                                            " wtime %.0f btime %.0f",
1375                                            XB->my_time*1000.0,XB->opp_time*1000.0);
1376                      } else {
1377                          engine_send_queue(Engine,
1378                                            " wtime %.0f btime %.0f",
1379                                            XB->opp_time*1000.0,XB->my_time*1000.0);
1380                      }
1381 
1382                      if (XB->inc != 0.0){
1383                          engine_send_queue(Engine,
1384                                            " winc %.0f binc %.0f",
1385                                            XB->inc*1000.0,XB->inc*1000.0);
1386                      }
1387                      if (XB->mps != 0) {
1388 
1389                          move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
1390                          ASSERT(move_nb>=1&&move_nb<=XB->mps);
1391 
1392                          engine_send_queue(Engine," movestogo %d",move_nb);
1393                      }
1394                  }
1395          }
1396          if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);
1397 
1398          if (State->state == PONDER) engine_send_queue(Engine," ponder");
1399 
1400          engine_send(Engine,""); // newline
1401 
1402       } else if (State->state == ANALYSE) {
1403 
1404          engine_send(Engine,"go infinite");
1405 
1406       } else {
1407 
1408          ASSERT(FALSE);
1409       }
1410 
1411       // init search info
1412 
1413       ASSERT(!Uci->searching);
1414 
1415       search_clear();
1416 
1417       Uci->searching = TRUE;
1418       Uci->pending_nb++;
1419    }
1420 }
1421 
1422 // search_clear()
1423 
search_clear()1424 static void search_clear() {
1425 
1426    uci_clear(Uci);
1427 
1428    // TODO: MOVE ME
1429 
1430    my_timer_start(State->timer);//also resets
1431 }
1432 
1433 // active()
1434 
active()1435 static bool active() {
1436 
1437    // position state
1438 
1439    if (game_status(Game) != PLAYING) return FALSE; // game ended
1440 
1441    // xboard state
1442 
1443    if (XB->analyse) return TRUE; // analysing
1444    if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode
1445    if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game
1446 
1447    return TRUE; // playing
1448 }
1449 
1450 // ponder()
1451 
ponder()1452 static bool ponder() {
1453 
1454     return XB->ponder && (option_get_bool(Option,"CanPonder") ||
1455                           option_find(Uci->option,"Ponder"));
1456 }
1457 // ponder_ok()
1458 
ponder_ok(int move)1459 static bool ponder_ok(int move) {
1460    int status;
1461    board_t board[1];
1462 
1463    ASSERT(move==MoveNone||move_is_ok(move));
1464 
1465    // legal ponder move?
1466 
1467    if (move == MoveNone) return FALSE;
1468 
1469    game_get_board(Game,board);
1470    if (!move_is_legal(move,board)) return FALSE;
1471 
1472    // UCI-legal resulting position?
1473 
1474    game_add_move(Game,move);
1475 
1476    game_get_board(Game,board);
1477    status = game_status(Game);
1478 
1479    game_rem_move(Game);
1480 
1481    if (status != PLAYING) return FALSE; // game ended
1482 
1483    if (option_get_bool(Option,"Book") && is_in_book(board)) {
1484       return FALSE;
1485    }
1486 
1487    return TRUE;
1488 }
1489 
1490 // stop_search()
1491 
stop_search()1492 static void stop_search() {
1493 
1494    if (Uci->searching) {
1495 
1496       ASSERT(Uci->searching);
1497       ASSERT(Uci->pending_nb>=1);
1498 
1499       my_log("POLYGLOT STOP SEARCH\n");
1500 
1501 /*
1502       engine_send(Engine,"stop");
1503       Uci->searching = FALSE;
1504 */
1505 
1506       if (option_get_bool(Option,"SyncStop")) {
1507          uci_send_stop_sync(Uci);
1508       } else {
1509          uci_send_stop(Uci);
1510       }
1511 	}
1512 }
1513 
1514 // send_board()
1515 
send_board(int extra_move)1516 static void send_board(int extra_move) {
1517 
1518    char fen[256];
1519    int start, end;
1520    board_t board[1];
1521    int pos;
1522    int move;
1523    char string[256];
1524 
1525    ASSERT(extra_move==MoveNone||move_is_ok(extra_move));
1526 
1527    ASSERT(!Uci->searching);
1528 
1529    // init
1530 
1531    game_get_board(Game,Uci->board);
1532    if (extra_move != MoveNone) move_do(Uci->board,extra_move);
1533 
1534    board_to_fen(Uci->board,fen,256);
1535    my_log("POLYGLOT FEN %s\n",fen);
1536 
1537    ASSERT(board_can_play(Uci->board));
1538 
1539    // more init
1540 
1541    start = 0;
1542    end = game_pos(Game);
1543    ASSERT(end>=start);
1544 
1545    // position
1546 
1547    game_get_board_ex(Game,board,start);
1548    board_to_fen(board,string,256);
1549 
1550    engine_send_queue(Engine,"position");
1551 
1552    if (my_string_equal(string,StartFen)) {
1553       engine_send_queue(Engine," startpos");
1554    } else {
1555       engine_send_queue(Engine," fen %s",string);
1556    }
1557 
1558    // move list
1559 
1560    if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves");
1561 
1562    for (pos = start; pos < end; pos++) { // game moves
1563 
1564       move = game_move(Game,pos);
1565 
1566       move_to_can(move,board,string,256);
1567       engine_send_queue(Engine," %s",string);
1568 
1569       move_do(board,move);
1570    }
1571 
1572    if (extra_move != MoveNone) { // move to ponder on
1573       move_to_can(extra_move,board,string,256);
1574       engine_send_queue(Engine," %s",string);
1575    }
1576 
1577    // end
1578 
1579    engine_send(Engine,""); // newline
1580 }
1581 
1582 // send_info()
1583 
send_info()1584 static void send_info() {
1585     int min_depth;
1586     if(option_get_bool(Option,"WbWorkArounds2")){
1587             // Silly bug in some versions of WinBoard.
1588             // depth <=1 clears the engine output window.
1589             // Why shouldn't an engine be allowed to send info at depth 1?
1590         min_depth=2;
1591     }else{
1592         min_depth=1;
1593     }
1594     gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth>min_depth?Uci->best_depth:min_depth,
1595 	     0,0.0,U64(0),Uci->info);
1596 }
1597 
1598 // send_pv()
1599 
send_pv()1600 static void send_pv() {
1601 
1602    char pv_string[StringSize];
1603    board_t board[1];
1604    int move;
1605    char move_string[StringSize];
1606 
1607    ASSERT(State->state!=WAIT);
1608 
1609    if (Uci->best_depth == 0) return;
1610 
1611    // xboard search information
1612 
1613    if (XB->post) {
1614 
1615       if (State->state == THINK || State->state == ANALYSE) {
1616 
1617          line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
1618 
1619 		 if(Uci->depth==-1) //hack to clear the engine output window
1620              gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb);
1621 
1622 		 gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,pv_string);
1623 
1624       } else if (State->state == PONDER &&
1625                  option_get_bool(Option,"ShowPonder")) {
1626 
1627          game_get_board(Game,board);
1628          move = State->exp_move;
1629 
1630          if (move != MoveNone && move_is_legal(move,board)) {
1631             move_to_san(move,board,move_string,256);
1632             line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
1633             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);
1634          }
1635       }
1636    }
1637 
1638    // kibitz
1639 
1640    if ((Uci->searching &&
1641         option_get_bool(Option,"KibitzPV") &&
1642         Uci->time >= option_get_double(Option,"KibitzDelay"))
1643        || (!Uci->searching && option_get_bool(Option,"KibitzMove"))) {
1644 
1645       if (State->state == THINK || State->state == ANALYSE) {
1646 
1647          line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
1648          if(kibitz_throttle(Uci->searching)){
1649              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);
1650          }
1651       } else if (State->state == PONDER) {
1652 
1653          game_get_board(Game,board);
1654          move = State->exp_move;
1655 
1656          if (move != MoveNone && move_is_legal(move,board)) {
1657             move_to_san(move,board,move_string,256);
1658             line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
1659             if(kibitz_throttle(Uci->searching)){
1660                 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);
1661             }
1662          }
1663       }
1664    }
1665 }
1666 
1667 // kibitz_throttle()
1668 
kibitz_throttle(bool searching)1669 static bool kibitz_throttle(bool searching){
1670     time_t curr_time;
1671     static time_t lastKibitzMove=0;
1672     static time_t lastKibitzPV=0;
1673     curr_time = time(NULL);
1674     if(searching){   // KibitzPV
1675         if(curr_time >=
1676            (option_get_int(Option,"KibitzInterval") + lastKibitzPV)){
1677             lastKibitzPV=curr_time;
1678             return TRUE;
1679         }
1680     }else{       // KibitzMove
1681         if(curr_time >=
1682            (option_get_int(Option,"KibitzInterval") + lastKibitzMove)){
1683             lastKibitzPV=curr_time;
1684             lastKibitzMove=curr_time;
1685             return TRUE;
1686         }
1687     }
1688     return FALSE;
1689 }
1690 
1691 // learn()
1692 
learn(int result)1693 static void learn(int result) {
1694 
1695    int pos;
1696    board_t board[1];
1697    int move;
1698 
1699    ASSERT(result>=-1&&result<=+1);
1700 
1701    ASSERT(XB->result);
1702    ASSERT(State->computer[White]||State->computer[Black]);
1703 
1704    // init
1705 
1706    pos = 0;
1707 
1708    if (FALSE) {
1709    } else if (State->computer[White]) {
1710       pos = 0;
1711    } else if (State->computer[Black]) {
1712       pos = 1;
1713       result = -result;
1714    } else {
1715       my_fatal("learn(): unknown side\n");
1716    }
1717 
1718    if (FALSE) {
1719    } else if (result > 0) {
1720       my_log("POLYGLOT *LEARN WIN*\n");
1721    } else if (result < 0) {
1722       my_log("POLYGLOT *LEARN LOSS*\n");
1723    } else {
1724       my_log("POLYGLOT *LEARN DRAW*\n");
1725    }
1726 
1727    // loop
1728 
1729    for (; pos < Game->size; pos += 2) {
1730 
1731       game_get_board_ex(Game,board,pos);
1732       move = game_move(Game,pos);
1733 
1734       book_learn_move(board,move,result);
1735    }
1736 
1737    book_flush();
1738 }
1739 
1740 // end of xboard2uci.c
1741