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