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