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