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