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