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