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