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