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