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