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