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