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