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