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