-\r
-// xboard2uci.c\r
-\r
-// includes\r
-\r
-#include <errno.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <time.h>\r
-\r
-#include "board.h"\r
-#include "book.h"\r
-#include "colour.h"\r
-#include "engine.h"\r
-#include "fen.h"\r
-#include "game.h"\r
-#include "gui.h"\r
-#include "line.h"\r
-#include "main.h"\r
-#include "move.h"\r
-#include "move_do.h"\r
-#include "move_legal.h"\r
-#include "option.h"\r
-#include "parse.h"\r
-#include "san.h"\r
-#include "uci.h"\r
-#include "uci2uci.h"\r
-#include "util.h"\r
-\r
-// defines\r
-\r
-#define StringSize 4096\r
-\r
-// constants\r
-\r
-static const bool UseDebug = FALSE;\r
-static const bool DelayPong = FALSE;\r
-\r
-// types\r
-\r
-typedef struct {\r
- int state;\r
- bool computer[ColourNb];\r
- int exp_move;\r
- int resign_nb;\r
- my_timer_t timer[1];\r
-} state_t;\r
-\r
-typedef struct {\r
- bool has_feature_memory;\r
- bool has_feature_smp;\r
- bool has_feature_egt;\r
- bool analyse;\r
- bool computer;\r
- const char * name;\r
- bool ics;\r
- bool new_hack; // "new" is a C++ keyword\r
- bool ponder;\r
- int ping;\r
- bool post;\r
- int proto_ver;\r
- bool result;\r
-\r
- int mps;\r
- double base;\r
- double inc;\r
- \r
- bool time_limit;\r
- double time_max;\r
- \r
- bool depth_limit;\r
- int depth_max;\r
- \r
- double my_time;\r
- double opp_time;\r
-} xb_t;\r
-\r
-typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t;\r
-\r
-// variables\r
-\r
-static state_t State[1];\r
-static xb_t XB[1];\r
-\r
-// prototypes\r
-\r
-static void comp_move (int move);\r
-static void move_step (int move);\r
-static void board_update ();\r
-\r
-static void mess ();\r
-static void no_mess (int move);\r
-\r
-static void search_update ();\r
-static void search_clear ();\r
-static void update_remaining_time();\r
-static int report_best_score();\r
-static bool kibitz_throttle (bool searching);\r
-static void start_protected_command();\r
-static void end_protected_command();\r
-\r
-static bool active ();\r
-static bool ponder ();\r
-static bool ponder_ok (int ponder_move);\r
-\r
-static void stop_search ();\r
-\r
-static void send_board (int extra_move);\r
-static void send_pv ();\r
-static void send_info ();\r
-\r
-static void send_xboard_options ();\r
-\r
-static void learn (int result);\r
-\r
-\r
-// functions\r
-\r
-// xboard2uci_init()\r
-\r
-void xboard2uci_init() {\r
- // init\r
-\r
- game_clear(Game);\r
-\r
- // state\r
-\r
- State->state = WAIT;\r
-\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = TRUE;\r
-\r
- State->exp_move = MoveNone;\r
- State->resign_nb = 0;\r
- my_timer_reset(State->timer);\r
-\r
- // yes there are engines that do not have the "Hash" option....\r
- XB->has_feature_memory= (option_find(Uci->option,"Hash")!=NULL);\r
- XB->has_feature_smp = (uci_thread_option(Uci)!=NULL);\r
- // TODO: support for other types of table bases\r
- XB->has_feature_egt = (option_find(Uci->option,"NalimovPath")!=NULL);\r
- XB->analyse = FALSE;\r
- XB->computer = FALSE;\r
- XB->name = NULL;\r
- my_string_set(&XB->name,"<empty>");\r
- XB->ics = FALSE;\r
- XB->new_hack = TRUE;\r
- XB->ping = -1;\r
- XB->ponder = FALSE;\r
- XB->post = FALSE;\r
- XB->proto_ver = 1;\r
- XB->result = FALSE;\r
-\r
- XB->mps = 0;\r
- XB->base = 300.0;\r
- XB->inc = 0.0;\r
-\r
- XB->time_limit = FALSE;\r
- XB->time_max = 5.0;\r
-\r
- XB->depth_limit = FALSE;\r
- XB->depth_max = 127;\r
-\r
- XB->my_time = 300.0;\r
- XB->opp_time = 300.0;\r
-}\r
-\r
-// xboard2uci_gui_step()\r
-\r
-void xboard2uci_gui_step(char string[]) {\r
-\r
- int move;\r
- char move_string[256];\r
- board_t board[1];\r
-\r
- if (FALSE) {\r
- \r
- } else if (match(string,"accepted *")) {\r
-\r
- // ignore\r
-\r
- } else if (match(string,"analyze")) {\r
-\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = FALSE;\r
-\r
- XB->analyse = TRUE;\r
- XB->new_hack = FALSE;\r
- ASSERT(!XB->result);\r
- XB->result = FALSE;\r
-\r
- mess();\r
-\r
- } else if (match(string,"bk")) {\r
-\r
- if (option_get_bool(Option,"Book")) {\r
- game_get_board(Game,board);\r
- book_disp(board);\r
- }\r
-\r
- } else if (match(string,"black")) {\r
-\r
- if (colour_is_black(game_turn(Game))) {\r
-\r
- State->computer[White] = TRUE;\r
- State->computer[Black] = FALSE;\r
-\r
- XB->new_hack = TRUE;\r
- XB->result = FALSE;\r
-\r
- mess();\r
- }\r
-\r
- } else if (match(string,"computer")) {\r
-\r
- XB->computer = TRUE;\r
-\r
- } else if (match(string,"draw")) {\r
- if(option_find(Uci->option,"UCI_DrawOffers")){\r
- my_log("POLYGLOT draw from XB received");\r
- uci_send_option(Uci,"DrawOffer","%s","draw");}\r
- } else if (match(string,"easy")) {\r
-\r
- XB->ponder = FALSE;\r
-\r
- mess();\r
-\r
- } else if (match(string,"edit")) {\r
-\r
- // refuse\r
-\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
-\r
- } else if (match(string,"exit")) {\r
-\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = FALSE;\r
-\r
- XB->analyse = FALSE;\r
-\r
- mess();\r
-\r
- } else if (match(string,"force")) {\r
-\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = FALSE;\r
-\r
- mess();\r
-\r
- } else if (match(string,"go")) {\r
-\r
- State->computer[game_turn(Game)] = TRUE;\r
- State->computer[colour_opp(game_turn(Game))] = FALSE;\r
-\r
- XB->new_hack = FALSE;\r
- ASSERT(!XB->result);\r
- XB->result = FALSE;\r
-\r
- mess();\r
-\r
- } else if (match(string,"hard")) {\r
-\r
- XB->ponder = TRUE;\r
-\r
- mess();\r
-\r
- } else if (match(string,"hint")) {\r
-\r
- if (option_get_bool(Option,"Book")) {\r
-\r
- game_get_board(Game,board);\r
- move = book_move(board,FALSE);\r
-\r
- if (move != MoveNone && move_is_legal(move,board)) {\r
- move_to_san(move,board,move_string,256);\r
- gui_send(GUI,"Hint: %s",move_string);\r
- }\r
- }\r
-\r
- } else if (match(string,"ics *")) {\r
-\r
- XB->ics = TRUE;\r
-\r
- } else if (match(string,"level * *:* *")) {\r
-\r
- XB->mps = atoi(Star[0]);\r
- XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2]));\r
- XB->inc = ((double)atoi(Star[3]));\r
-\r
- } else if (match(string,"level * * *")) {\r
-\r
- XB->mps = atoi(Star[0]);\r
- XB->base = ((double)atoi(Star[1])) * 60.0;\r
- XB->inc = ((double)atoi(Star[2]));\r
-\r
- } else if (match(string,"name *")) {\r
-\r
- my_string_set(&XB->name,Star[0]);\r
-\r
- } else if (match(string,"new")) {\r
-\r
- uci_send_isready(Uci);\r
- my_log("POLYGLOT NEW GAME\n");\r
-\r
- option_set(Option,"Chess960","false");\r
-\r
- game_clear(Game);\r
-\r
- if (XB->analyse) {\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = FALSE;\r
- } else {\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = TRUE;\r
- }\r
-\r
- XB->new_hack = TRUE;\r
- XB->result = FALSE;\r
-\r
- XB->depth_limit = FALSE;\r
-\r
- XB->computer = FALSE;\r
- my_string_set(&XB->name,"<empty>");\r
-\r
- board_update();\r
- mess();\r
-\r
- uci_send_ucinewgame(Uci);\r
-\r
- } else if (match(string,"nopost")) {\r
-\r
- XB->post = FALSE;\r
-\r
- } else if (match(string,"otim *")) {\r
-\r
- XB->opp_time = ((double)atoi(Star[0])) / 100.0;\r
- if (XB->opp_time < 0.0) XB->opp_time = 0.0;\r
-\r
- } else if (match(string,"pause")) {\r
-\r
- // refuse\r
-\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
-\r
- } else if (match(string,"ping *")) {\r
-\r
- // HACK; TODO: answer only after an engine move\r
-\r
- if (DelayPong) {\r
- if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping\r
- XB->ping = atoi(Star[0]);\r
- uci_send_isready(Uci);\r
- } else {\r
- ASSERT(XB->ping==-1);\r
- gui_send(GUI,"pong %s",Star[0]);\r
- }\r
-\r
- } else if (match(string,"playother")) {\r
-\r
- State->computer[game_turn(Game)] = FALSE;\r
- State->computer[colour_opp(game_turn(Game))] = TRUE;\r
-\r
- XB->new_hack = FALSE;\r
- ASSERT(!XB->result);\r
- XB->result = FALSE;\r
-\r
- mess();\r
-\r
- } else if (match(string,"post")) {\r
-\r
- XB->post = TRUE;\r
-\r
- } else if (match(string,"protover *")) {\r
- XB->proto_ver = atoi(Star[0]);\r
- ASSERT(XB->proto_ver>=2);\r
- send_xboard_options();\r
-\r
- } else if (match(string,"quit")) {\r
- my_log("POLYGLOT *** \"quit\" from GUI ***\n");\r
- quit();\r
- } else if (match(string,"random")) {\r
-\r
- // ignore\r
-\r
- } else if (match(string,"rating * *")) {\r
-\r
- // ignore\r
-\r
- } else if (match(string,"remove")) {\r
-\r
- if (game_pos(Game) >= 2) {\r
-\r
- game_goto(Game,game_pos(Game)-2);\r
-\r
- ASSERT(!XB->new_hack);\r
- XB->new_hack = FALSE; // HACK?\r
- XB->result = FALSE;\r
-\r
- board_update();\r
- mess();\r
- }\r
-\r
- } else if (match(string,"rejected *")) {\r
-\r
- // ignore\r
-\r
- } else if (match(string,"reset")) { // protover 3?\r
-\r
- // refuse\r
-\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
-\r
- } else if (FALSE\r
- || match(string,"result * {*}")\r
- || match(string,"result * {* }")\r
- || match(string,"result * { *}")\r
- || match(string,"result * { * }")) {\r
-\r
- my_log("POLYGLOT GAME END\n");\r
-\r
- XB->result = TRUE;\r
-\r
- mess();\r
-\r
- // book learning\r
-\r
- if (option_get_bool(Option,"Book") &&\r
- option_get_bool(Option,"BookLearn")) {\r
-\r
- if (FALSE) {\r
- } else if (my_string_equal(Star[0],"1-0")) {\r
- learn(+1);\r
- } else if (my_string_equal(Star[0],"0-1")) {\r
- learn(-1);\r
- } else if (my_string_equal(Star[0],"1/2-1/2")) {\r
- learn(0);\r
- }\r
- }\r
- } else if (match(string,"resume")) {\r
-\r
- // refuse\r
-\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
-\r
- } else if (match(string,"option *=*") ||\r
- match(string,"option * =*") ||\r
- match(string,"option *= *") ||\r
- match(string,"option * = *")\r
- ){\r
- char *name=Star[0];\r
- char *value=Star[1];\r
- if(match(name, "Polyglot *")){\r
- char *pg_name=Star[0];\r
- polyglot_set_option(pg_name,value);\r
- }else{\r
- option_t *opt=option_find(Uci->option,name);\r
- if(opt){\r
- if(my_string_case_equal(opt->type,"check")){\r
- value=my_string_equal(value,"1")?"true":"false";\r
- }\r
- start_protected_command();\r
- uci_send_option(Uci, name, "%s", value);\r
- end_protected_command();\r
- }else{\r
- gui_send(GUI,"Error (unknown option): %s",name); \r
- }\r
- }\r
- } else if (match(string,"option *")){\r
- char *name=Star[0];\r
- start_protected_command();\r
- // value is ignored\r
- if(!uci_send_option(Uci, name, "%s", "<empty>")){\r
- gui_send(GUI,"Error (unknown option): %s",name); \r
- }; \r
- end_protected_command();\r
- } else if (XB->has_feature_smp && match(string,"cores *")){\r
- int cores=atoi(Star[0]);\r
- if(cores>=1){\r
- // updating the number of cores\r
- my_log("POLYGLOT setting the number of cores to %d\n",cores);\r
- start_protected_command();\r
- uci_set_threads(Uci,cores); \r
- end_protected_command();\r
- } else{\r
- // refuse\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
- }\r
- } else if (XB->has_feature_egt && match(string,"egtpath * *")){\r
- char *type=Star[0];\r
- char *path=Star[1];\r
- if(!my_string_case_equal(type,"nalimov")){\r
- // refuse\r
- gui_send(GUI,"Error (unsupported table base format): %s",string);\r
- }else if(my_string_empty(path)){\r
- // refuse\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
- }else{\r
- // updating NalimovPath\r
- my_log("POLYGLOT setting the Nalimov path to %s\n",path);\r
- start_protected_command();\r
- uci_send_option(Uci,"NalimovPath","%s",path);\r
- end_protected_command();\r
- }\r
- } else if (XB->has_feature_memory && match(string,"memory *")){\r
- int memory = atoi(Star[0]);\r
- int nalimov_cache;\r
- int real_memory;\r
- if(memory>=1){\r
- // updating the available memory\r
- option_t *opt;\r
- my_log("POLYGLOT setting the amount of memory to %dMb\n",memory);\r
- if((opt=option_find(Uci->option,"NalimovCache"))){\r
- nalimov_cache=atoi(opt->value);\r
- }else{\r
- nalimov_cache=0;\r
- }\r
- my_log("POLYGLOT Nalimov Cache is %dMb\n",nalimov_cache);\r
- real_memory=memory-nalimov_cache;\r
- if(real_memory>0){\r
- start_protected_command();\r
- uci_send_option(Uci,"Hash", "%d", real_memory);\r
- end_protected_command();\r
- }\r
- }else{\r
- // refuse\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
- }\r
-\r
- } else if (match(string,"sd *")) {\r
-\r
- XB->depth_limit = TRUE;\r
- XB->depth_max = atoi(Star[0]);\r
-\r
- } else if (match(string,"setboard *")) {\r
-\r
- my_log("POLYGLOT FEN %s\n",Star[0]);\r
-\r
- if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]);\r
-\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = FALSE;\r
-\r
- XB->new_hack = TRUE; // HACK?\r
- XB->result = FALSE;\r
-\r
- board_update();\r
- mess();\r
-\r
- } else if (match(string,"st *")) {\r
-\r
- XB->time_limit = TRUE;\r
- XB->time_max = ((double)atoi(Star[0]));\r
-\r
- } else if (match(string,"time *")) {\r
-\r
- XB->my_time = ((double)atoi(Star[0])) / 100.0;\r
- if (XB->my_time < 0.0) XB->my_time = 0.0;\r
-\r
- } else if (match(string,"undo")) {\r
-\r
- if (game_pos(Game) >= 1) {\r
-\r
- game_goto(Game,game_pos(Game)-1);\r
-\r
- ASSERT(!XB->new_hack);\r
- XB->new_hack = FALSE; // HACK?\r
- XB->result = FALSE;\r
-\r
- board_update();\r
- mess();\r
- }\r
-\r
- } else if (match(string,"usermove *")) {\r
-\r
- game_get_board(Game,board);\r
- move = move_from_san(Star[0],board);\r
-\r
- if (move != MoveNone && move_is_legal(move,board)) {\r
-\r
- XB->new_hack = FALSE;\r
- ASSERT(!XB->result);\r
- XB->result = FALSE;\r
-\r
- move_step(move);\r
- no_mess(move);\r
-\r
- } else {\r
-\r
- gui_send(GUI,"Illegal move: %s",Star[0]);\r
- }\r
-\r
- } else if (match(string,"variant *")) {\r
-\r
- if (my_string_equal(Star[0],"fischerandom")) {\r
- option_set(Option,"Chess960","true");\r
- } else {\r
- option_set(Option,"Chess960","false");\r
- }\r
-\r
- } else if (match(string,"white")) {\r
-\r
- if (colour_is_white(game_turn(Game))) {\r
-\r
- State->computer[White] = FALSE;\r
- State->computer[Black] = TRUE;\r
-\r
- XB->new_hack = TRUE;\r
- XB->result = FALSE;\r
-\r
- mess();\r
- }\r
-\r
- } else if (match(string,"xboard")) {\r
-\r
- // ignore\r
-\r
- } else if (match(string,".")) { // analyse info\r
-\r
- if (State->state == ANALYSE) {\r
- int depth=Uci->best_depth;//HACK: don't clear engine-output window...\r
-\r
- ASSERT(Uci->searching);\r
- ASSERT(Uci->pending_nb>=1);\r
-\r
- if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) {\r
- move_to_san(Uci->root_move,Uci->board,move_string,256);\r
- 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
- } else {\r
- gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK\r
- }\r
- }\r
-\r
- } else if (match(string,"?")) { // move now\r
-\r
- if (State->state == THINK) {\r
-\r
- ASSERT(Uci->searching);\r
- ASSERT(Uci->pending_nb>=1);\r
-\r
- // HACK: just send "stop" to the engine\r
-\r
- if (Uci->searching) {\r
- my_log("POLYGLOT STOP SEARCH\n");\r
- engine_send(Engine,"stop");\r
- }\r
- }\r
-\r
- } else { // unknown command, maybe a move?\r
-\r
- game_get_board(Game,board);\r
- move = move_from_san(string,board);\r
-\r
- if (move != MoveNone && move_is_legal(move,board)) {\r
-\r
- XB->new_hack = FALSE;\r
- ASSERT(!XB->result);\r
- XB->result = FALSE;\r
-\r
- move_step(move);\r
- no_mess(move);\r
-\r
- } else if (move != MoveNone) {\r
-\r
- gui_send(GUI,"Illegal move: %s",string);\r
-\r
- } else {\r
-\r
- gui_send(GUI,"Error (unknown command): %s",string);\r
- }\r
- }\r
- return;\r
-}\r
-\r
-// xboard2uci_engine_step()\r
-\r
-void xboard2uci_engine_step(char string[]) {\r
-\r
- int event;\r
- board_t board[1];\r
- event = uci_parse(Uci,string);\r
-\r
- // react to events\r
-\r
- if ((event & EVENT_READY) != 0) {\r
-\r
- // the engine is now ready\r
-\r
- if (!Uci->ready) {\r
- Uci->ready = TRUE;\r
- // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1");\r
- }\r
-\r
- if (!DelayPong && XB->ping >= 0) {\r
- gui_send(GUI,"pong %d",XB->ping);\r
- XB->ping = -1;\r
- }\r
- }\r
-\r
- if ((event & EVENT_MOVE) != 0 && State->state == THINK) {\r
-\r
- // the engine is playing a move\r
-\r
- // MEGA HACK: estimate remaining time because XBoard won't send it!\r
-\r
- my_timer_stop(State->timer);\r
-\r
- XB->my_time -= my_timer_elapsed_real(State->timer);\r
- XB->my_time += XB->inc;\r
- if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base;\r
-\r
- if (XB->my_time < 0.0) XB->my_time = 0.0;\r
-\r
- // play the engine move\r
-\r
- comp_move(Uci->best_move);\r
- }\r
-\r
- if ((event & EVENT_PV) != 0) {\r
-\r
- // the engine has sent a new PV\r
-\r
- send_pv();\r
- }\r
- if ((event & EVENT_INFO) != 0) {\r
-\r
- // the engine has sent info\r
-\r
- send_info();\r
- }\r
- if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){\r
- my_log("POYGLOT draw offer/resign from engine\n");\r
- if(option_find(Uci->option,"UCI_DrawOffers")){\r
- if(event & EVENT_DRAW)\r
- gui_send(GUI,"offer draw");\r
- else\r
- gui_send(GUI,"resign");\r
- }\r
- }\r
- if(((event & EVENT_ILLEGAL_MOVE)!=0) && (State->state == THINK)){\r
- game_get_board(Game,board);\r
- if(board->turn==White){\r
- gui_send(GUI,"0-1 {polyglot: resign"\r
- " (illegal engine move white)}");\r
- }else{\r
- gui_send(GUI,"1-0 {polyglot: resign"\r
- " (illegal engine move black)}");\r
- }\r
- board_disp(board);\r
- XB->result = TRUE;\r
- mess();\r
- }\r
-}\r
-\r
-// format_xboard_option_line\r
-\r
-void format_xboard_option_line(char * option_line, option_t *opt){\r
- int j;\r
- char option_string[StringSize];\r
- char *tmp;\r
- strcpy(option_line,"");\r
- // buffer overflow alert\r
- strcat(option_line,"feature option=\"");\r
- if(opt->mode&PG){\r
- strcat(option_line,"Polyglot ");\r
- }\r
- sprintf(option_string,"%s",opt->name);\r
- strcat(option_line,option_string);\r
- sprintf(option_string," -%s",opt->type);\r
- strcat(option_line,option_string);\r
- if(strcmp(opt->type,"button") && strcmp(opt->type,"combo")){\r
- if(strcmp(opt->type,"check")){\r
- sprintf(option_string," %s",opt->default_);\r
- }else{\r
- sprintf(option_string," %d",\r
- my_string_case_equal(opt->default_,"true")?1:0);\r
- }\r
- strcat(option_line,option_string);\r
- }\r
- if(!strcmp(opt->type,"spin")){\r
- sprintf(option_string," %s",opt->min);\r
- strcat(option_line,option_string);\r
- }\r
- if(!strcmp(opt->type,"spin")){\r
- sprintf(option_string," %s",opt->max);\r
- strcat(option_line,option_string);\r
- }\r
- for(j=0;j<opt->var_nb;j++){\r
- if(!strcmp(opt->var[j],opt->default_)){\r
- sprintf(option_string," *%s",opt->var[j]);\r
- }else{\r
- sprintf(option_string," %s",opt->var[j]);\r
- }\r
- strcat(option_line,option_string);\r
- if(j!=opt->var_nb-1){\r
- strcat(option_line," ///");\r
- }\r
- }\r
- strcat(option_line,"\"");\r
- if(option_get_bool(Option,"WbWorkArounds") &&\r
- (tmp=strstr(option_line,"Draw"))){\r
- *tmp='d';\r
- my_log("POLYGLOT Decapitalizing \"Draw\" in option \"%s\"\n",\r
- opt->name);\r
- }\r
-}\r
-\r
-// send_xboard_options()\r
-\r
-static void send_xboard_options(){\r
-\r
- char option_line[StringSize]="";\r
- const char * name;\r
- option_t *opt;\r
- \r
- gui_send(GUI,"feature done=0");\r
- \r
- gui_send(GUI,"feature analyze=1");\r
- gui_send(GUI,"feature colors=0");\r
- gui_send(GUI,"feature draw=1");\r
- gui_send(GUI,"feature ics=1");\r
- gui_send(GUI,"feature myname=\"%s\"",\r
- option_get_string(Option,"EngineName"));\r
- gui_send(GUI,"feature name=1");\r
- gui_send(GUI,"feature pause=0");\r
- gui_send(GUI,"feature ping=1");\r
- gui_send(GUI,"feature playother=1");\r
- gui_send(GUI,"feature reuse=1");\r
- gui_send(GUI,"feature san=0");\r
- gui_send(GUI,"feature setboard=1");\r
- gui_send(GUI,"feature sigint=0");\r
- gui_send(GUI,"feature sigterm=0");\r
- gui_send(GUI,"feature time=1");\r
- gui_send(GUI,"feature usermove=1");\r
- if (XB->has_feature_memory){\r
- gui_send(GUI,"feature memory=1");\r
- }else{\r
- gui_send(GUI,"feature memory=0");\r
- }\r
- if (XB->has_feature_smp){\r
- gui_send(GUI,"feature smp=1");\r
- }else{\r
- gui_send(GUI,"feature smp=0");\r
- }\r
- if (XB->has_feature_egt){\r
- // TODO: support for other types of table bases\r
- gui_send(GUI,"feature egt=\"nalimov\"");\r
- }else{\r
- gui_send(GUI,"feature egt=\"\"");\r
- }\r
- \r
- if (option_find(Uci->option,"UCI_Chess960")) {\r
- gui_send(GUI,"feature variants=\"normal,fischerandom\"");\r
- } else {\r
- gui_send(GUI,"feature variants=\"normal\"");\r
- }\r
-\r
- option_start_iter(Uci->option);\r
- while((opt=option_next(Uci->option))){\r
- if(my_string_case_equal(opt->name,"UCI_AnalyseMode")) continue;\r
- if(my_string_case_equal(opt->name,"Ponder")) continue;\r
- if(my_string_case_equal(opt->name,"Hash")) continue;\r
- if(my_string_case_equal(opt->name,"NalimovPath")) continue;\r
- if((name=uci_thread_option(Uci))!=NULL &&\r
- my_string_case_equal(opt->name,name)) continue;\r
- \r
- format_xboard_option_line(option_line,opt);\r
- \r
- gui_send(GUI,"%s",option_line);\r
- }\r
-\r
-\r
- option_start_iter(Option);\r
- while((opt=option_next(Option))){\r
- if(opt->mode &XBOARD){\r
- format_xboard_option_line(option_line,opt);\r
- gui_send(GUI,"%s",option_line);\r
- }\r
- } \r
- gui_send(GUI,"feature done=1"); \r
- \r
-}\r
-\r
-// report_best_score()\r
-\r
-static int report_best_score(){\r
- if(!option_get_bool(Option,"ScoreWhite") ||\r
- colour_is_white(Uci->board->turn)){\r
- return Uci->best_score;\r
- }else{\r
- return -Uci->best_score;\r
- }\r
-}\r
-\r
-// comp_move()\r
-\r
-static void comp_move(int move) {\r
-\r
- board_t board[1];\r
- char string[256];\r
-\r
- ASSERT(move_is_ok(move));\r
-\r
- ASSERT(State->state==THINK);\r
- ASSERT(!XB->analyse);\r
-\r
- if(option_get_bool(Option,"RepeatPV"))\r
- send_pv(); // to update time and nodes\r
-\r
- // send the move\r
-\r
- game_get_board(Game,board);\r
-\r
- if (move_is_castle(move,board) && option_get_bool(Option,"Chess960")) {\r
- if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O\r
- } else {\r
- if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n");\r
- }\r
-\r
- gui_send(GUI,"move %s",string);\r
-\r
- // resign?\r
-\r
- if (option_get_bool(Option,"Resign") && Uci->root_move_nb > 1) {\r
-\r
- if (Uci->best_score <= -abs(option_get_int(Option,"ResignScore"))) {\r
-\r
- State->resign_nb++;\r
- my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":"");\r
-\r
- if (State->resign_nb >= option_get_int(Option,"ResignMoves")) {\r
- my_log("POLYGLOT *** RESIGN ***\n");\r
- gui_send(GUI,"resign");\r
- }\r
-\r
- } else {\r
-\r
- if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb);\r
- State->resign_nb = 0;\r
- }\r
- }\r
-\r
- // play the move\r
-\r
- move_step(move);\r
- no_mess(move);\r
-}\r
-\r
-// move_step()\r
-\r
-static void move_step(int move) {\r
-\r
- board_t board[1];\r
- char move_string[256];\r
-\r
- ASSERT(move_is_ok(move));\r
-\r
- // log\r
-\r
- game_get_board(Game,board);\r
-\r
- if (move != MoveNone && move_is_legal(move,board)) {\r
-\r
- move_to_san(move,board,move_string,256);\r
- my_log("POLYGLOT MOVE %s\n",move_string);\r
-\r
- } else {\r
-\r
- move_to_can(move,board,move_string,256);\r
- my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string);\r
- board_disp(board);\r
-\r
- my_fatal("move_step(): illegal move \"%s\"\n",move_string);\r
- }\r
-\r
- // play the move\r
-\r
- game_add_move(Game,move);\r
- board_update();\r
-}\r
-\r
-// board_update()\r
-\r
-static void board_update() {\r
-\r
- // handle game end\r
-\r
- ASSERT(!XB->result);\r
-\r
- switch (game_status(Game)) {\r
- case PLAYING:\r
- break;\r
- case WHITE_MATES:\r
- gui_send(GUI,"1-0 {White mates}");\r
- break;\r
- case BLACK_MATES:\r
- gui_send(GUI,"0-1 {Black mates}");\r
- break;\r
- case STALEMATE:\r
- gui_send(GUI,"1/2-1/2 {Stalemate}");\r
- break;\r
- case DRAW_MATERIAL:\r
- gui_send(GUI,"1/2-1/2 {Draw by insufficient material}");\r
- break;\r
- case DRAW_FIFTY:\r
- gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}");\r
- break;\r
- case DRAW_REPETITION:\r
- gui_send(GUI,"1/2-1/2 {Draw by repetition}");\r
- break;\r
- default:\r
- ASSERT(FALSE);\r
- break;\r
- }\r
-}\r
-\r
-// mess()\r
-\r
-static void mess() {\r
-\r
- // clear state variables\r
-\r
- State->resign_nb = 0;\r
- State->exp_move = MoveNone;\r
- my_timer_reset(State->timer);\r
-\r
- // abort a possible search\r
-\r
- stop_search();\r
-\r
- // calculate the new state\r
-\r
- if (FALSE) {\r
- } else if (!active()) {\r
- State->state = WAIT;\r
- my_log("POLYGLOT WAIT\n");\r
- } else if (XB->analyse) {\r
- State->state = ANALYSE;\r
- my_log("POLYGLOT ANALYSE\n");\r
- } else if (State->computer[game_turn(Game)]) {\r
- State->state = THINK;\r
- my_log("POLYGLOT THINK\n");\r
- } else {\r
- State->state = WAIT;\r
- my_log("POLYGLOT WAIT\n");\r
- }\r
-\r
- search_update();\r
-}\r
-\r
-// no_mess()\r
-\r
-static void no_mess(int move) {\r
-\r
- ASSERT(move_is_ok(move));\r
-\r
- // just received a move, calculate the new state\r
-\r
- if (FALSE) {\r
-\r
- } else if (!active()) {\r
-\r
- stop_search(); // abort a possible search\r
-\r
- State->state = WAIT;\r
- State->exp_move = MoveNone;\r
-\r
- my_log("POLYGLOT WAIT\n");\r
-\r
- } else if (State->state == WAIT) {\r
-\r
- ASSERT(State->computer[game_turn(Game)]);\r
- ASSERT(!State->computer[colour_opp(game_turn(Game))]);\r
- ASSERT(!XB->analyse);\r
-\r
- my_log("POLYGLOT WAIT -> THINK\n");\r
-\r
- State->state = THINK;\r
- State->exp_move = MoveNone;\r
-\r
- } else if (State->state == THINK) {\r
-\r
- ASSERT(!State->computer[game_turn(Game)]);\r
- ASSERT(State->computer[colour_opp(game_turn(Game))]);\r
- ASSERT(!XB->analyse);\r
-\r
- if (ponder() && ponder_ok(Uci->ponder_move)) {\r
-\r
- my_log("POLYGLOT THINK -> PONDER\n");\r
-\r
- State->state = PONDER;\r
- State->exp_move = Uci->ponder_move;\r
-\r
- } else {\r
-\r
- my_log("POLYGLOT THINK -> WAIT\n");\r
-\r
- State->state = WAIT;\r
- State->exp_move = MoveNone;\r
- }\r
-\r
- } else if (State->state == PONDER) {\r
-\r
- ASSERT(State->computer[game_turn(Game)]);\r
- ASSERT(!State->computer[colour_opp(game_turn(Game))]);\r
- ASSERT(!XB->analyse);\r
-\r
- if (move == State->exp_move && Uci->searching) {\r
-\r
- ASSERT(Uci->searching);\r
- ASSERT(Uci->pending_nb>=1);\r
-\r
- my_timer_start(State->timer);//also resets\r
-\r
- my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n");\r
- engine_send(Engine,"ponderhit");\r
-\r
- State->state = THINK;\r
- State->exp_move = MoveNone;\r
-\r
- send_pv(); // update display\r
-\r
- return; // do not launch a new search\r
-\r
- } else {\r
-\r
- my_log("POLYGLOT PONDER -> THINK (miss)\n");\r
-\r
- stop_search();\r
-\r
- State->state = THINK;\r
- State->exp_move = MoveNone;\r
- }\r
-\r
- } else if (State->state == ANALYSE) {\r
-\r
- ASSERT(XB->analyse);\r
-\r
- my_log("POLYGLOT ANALYSE -> ANALYSE\n");\r
-\r
- stop_search();\r
-\r
- } else {\r
-\r
- ASSERT(FALSE);\r
- }\r
-\r
- search_update();\r
-}\r
-\r
-// start_protected_command()\r
-\r
-static void start_protected_command(){\r
- stop_search();\r
-}\r
-\r
-static void end_protected_command(){\r
- if(Uci->ready){ // not init faze\r
- uci_send_isready_sync(Uci); // gobble up spurious "bestmove"\r
- }\r
- update_remaining_time();\r
- search_update(); // relaunch search if necessary\r
-}\r
-\r
-// update_remaining_time()\r
-\r
-static void update_remaining_time(){\r
- double reduce;\r
- if(State->timer->running){\r
- my_timer_stop(State->timer);\r
- reduce = my_timer_elapsed_real(State->timer);\r
- my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce);\r
- XB->my_time -= reduce;\r
- if(XB->my_time<0.0){\r
- XB->my_time=0.0;\r
- }\r
- }\r
-}\r
-\r
-\r
-// search_update()\r
-\r
-static void search_update() {\r
-\r
- int move;\r
- int move_nb;\r
- board_t board[1];\r
-\r
- ASSERT(!Uci->searching);\r
-\r
-\r
-\r
- \r
- // launch a new search if needed\r
-\r
- \r
-\r
- if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {\r
-\r
- // opening book\r
-\r
- if (State->state == THINK && option_get_bool(Option,"Book")) {\r
-\r
- game_get_board(Game,Uci->board);\r
-\r
- move = book_move(Uci->board,option_get_bool(Option,"BookRandom"));\r
-\r
- if (move != MoveNone && move_is_legal(move,Uci->board)) {\r
-\r
- my_log("POLYGLOT *BOOK MOVE*\n");\r
-\r
- search_clear(); // clears Uci->ponder_move\r
- Uci->best_move = move;\r
-\r
- board_copy(board,Uci->board);\r
- move_do(board,move);\r
- Uci->ponder_move = book_move(board,FALSE); // expected move = best book move\r
-\r
- Uci->best_pv[0] = Uci->best_move;\r
- Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone\r
- Uci->best_pv[2] = MoveNone;\r
-\r
- comp_move(Uci->best_move);\r
-\r
- return;\r
- }\r
- }\r
-\r
- // engine search\r
-\r
- my_log("POLYGLOT START SEARCH\n");\r
-\r
- // options\r
-\r
- uci_send_option(Uci,"UCI_Chess960","%s",\r
- option_get_bool(Option,"Chess960")?"true":"false");\r
-\r
- if (option_get_int(Option,"UCIVersion") >= 2) {\r
- uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);\r
- uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false");\r
- }\r
-\r
- uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false");\r
-\r
- // position\r
-\r
- move = (State->state == PONDER) ? State->exp_move : MoveNone;\r
- send_board(move); // updates Uci->board global variable\r
-\r
- // search\r
-\r
- if (State->state == THINK || State->state == PONDER) {\r
-\r
- engine_send_queue(Engine,"go");\r
-\r
- if (XB->time_limit) {\r
-\r
- // fixed time per move\r
-\r
- engine_send_queue(Engine," movetime %.0f",XB->time_max*1000.0);\r
-\r
- } else {\r
-\r
- // time controls\r
-\r
- if (colour_is_white(Uci->board->turn)) {\r
- engine_send_queue(Engine," wtime %.0f btime %.0f",XB->my_time*1000.0,XB->opp_time*1000.0);\r
- } else {\r
- engine_send_queue(Engine," wtime %.0f btime %.0f",XB->opp_time*1000.0,XB->my_time*1000.0);\r
- }\r
-\r
- if (XB->inc != 0.0) engine_send_queue(Engine," winc %.0f binc %.0f",XB->inc*1000.0,XB->inc*1000.0);\r
-\r
- if (XB->mps != 0) {\r
-\r
- move_nb = XB->mps - (Uci->board->move_nb % XB->mps);\r
- ASSERT(move_nb>=1&&move_nb<=XB->mps);\r
-\r
- engine_send_queue(Engine," movestogo %d",move_nb);\r
- }\r
- }\r
-\r
- if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);\r
-\r
- if (State->state == PONDER) engine_send_queue(Engine," ponder");\r
-\r
- engine_send(Engine,""); // newline\r
-\r
- } else if (State->state == ANALYSE) {\r
-\r
- engine_send(Engine,"go infinite");\r
-\r
- } else {\r
-\r
- ASSERT(FALSE);\r
- }\r
-\r
- // init search info\r
-\r
- ASSERT(!Uci->searching);\r
-\r
- search_clear();\r
-\r
- Uci->searching = TRUE;\r
- Uci->pending_nb++;\r
- }\r
-}\r
-\r
-// search_clear()\r
-\r
-static void search_clear() {\r
-\r
- uci_clear(Uci);\r
-\r
- // TODO: MOVE ME\r
-\r
- my_timer_start(State->timer);//also resets\r
-}\r
-\r
-// active()\r
-\r
-static bool active() {\r
-\r
- // position state\r
-\r
- if (game_status(Game) != PLAYING) return FALSE; // game ended\r
-\r
- // xboard state\r
-\r
- if (XB->analyse) return TRUE; // analysing\r
- if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode\r
- if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game\r
-\r
- return TRUE; // playing\r
-}\r
-\r
-// ponder()\r
-\r
-static bool ponder() {\r
-\r
- return XB->ponder && (option_get_bool(Option,"CanPonder") ||\r
- option_find(Uci->option,"Ponder"));\r
-}\r
-// ponder_ok()\r
-\r
-static bool ponder_ok(int move) {\r
- int status;\r
- board_t board[1];\r
-\r
- ASSERT(move==MoveNone||move_is_ok(move));\r
-\r
- // legal ponder move?\r
-\r
- if (move == MoveNone) return FALSE;\r
-\r
- game_get_board(Game,board);\r
- if (!move_is_legal(move,board)) return FALSE;\r
-\r
- // UCI-legal resulting position?\r
-\r
- game_add_move(Game,move);\r
-\r
- game_get_board(Game,board);\r
- status = game_status(Game);\r
-\r
- game_rem_move(Game);\r
-\r
- if (status != PLAYING) return FALSE; // game ended\r
-\r
- if (option_get_bool(Option,"Book") && is_in_book(board)) {\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-// stop_search()\r
-\r
-static void stop_search() {\r
-\r
- if (Uci->searching) {\r
-\r
- ASSERT(Uci->searching);\r
- ASSERT(Uci->pending_nb>=1);\r
-\r
- my_log("POLYGLOT STOP SEARCH\n");\r
-\r
-/*\r
- engine_send(Engine,"stop");\r
- Uci->searching = FALSE;\r
-*/\r
-\r
- if (option_get_bool(Option,"SyncStop")) {\r
- uci_send_stop_sync(Uci);\r
- } else {\r
- uci_send_stop(Uci);\r
- }\r
- }\r
-}\r
-\r
-// send_board()\r
-\r
-static void send_board(int extra_move) {\r
-\r
- char fen[256];\r
- int start, end;\r
- board_t board[1];\r
- int pos;\r
- int move;\r
- char string[256];\r
-\r
- ASSERT(extra_move==MoveNone||move_is_ok(extra_move));\r
-\r
- ASSERT(!Uci->searching);\r
-\r
- // init\r
-\r
- game_get_board(Game,Uci->board);\r
- if (extra_move != MoveNone) move_do(Uci->board,extra_move);\r
-\r
- board_to_fen(Uci->board,fen,256);\r
- my_log("POLYGLOT FEN %s\n",fen);\r
-\r
- ASSERT(board_can_play(Uci->board));\r
-\r
- // more init\r
-\r
- start = 0;\r
- end = game_pos(Game);\r
- ASSERT(end>=start);\r
-\r
- // position\r
-\r
- game_get_board_ex(Game,board,start);\r
- board_to_fen(board,string,256);\r
-\r
- engine_send_queue(Engine,"position");\r
-\r
- if (my_string_equal(string,StartFen)) {\r
- engine_send_queue(Engine," startpos");\r
- } else {\r
- engine_send_queue(Engine," fen %s",string);\r
- }\r
-\r
- // move list\r
-\r
- if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves");\r
-\r
- for (pos = start; pos < end; pos++) { // game moves\r
-\r
- move = game_move(Game,pos);\r
-\r
- move_to_can(move,board,string,256);\r
- engine_send_queue(Engine," %s",string);\r
-\r
- move_do(board,move);\r
- }\r
-\r
- if (extra_move != MoveNone) { // move to ponder on\r
- move_to_can(extra_move,board,string,256);\r
- engine_send_queue(Engine," %s",string);\r
- }\r
-\r
- // end\r
-\r
- engine_send(Engine,""); // newline\r
-}\r
-\r
-// send_info()\r
-\r
-static void send_info() {\r
- int min_depth;\r
- if(option_get_bool(Option,"WbWorkArounds2")){\r
- // Silly bug in some versions of WinBoard.\r
- // depth <=1 clears the engine output window.\r
- // Why shouldn't an engine be allowed to send info at depth 1?\r
- min_depth=2;\r
- }else{\r
- min_depth=1;\r
- }\r
- gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth>min_depth?Uci->best_depth:min_depth,\r
- 0,0,0.0,0,Uci->info); \r
-}\r
-\r
-// send_pv()\r
-\r
-static void send_pv() {\r
-\r
- char pv_string[StringSize];\r
- board_t board[1];\r
- int move;\r
- char move_string[StringSize];\r
-\r
- ASSERT(State->state!=WAIT);\r
-\r
- if (Uci->best_depth == 0) return;\r
-\r
- // xboard search information\r
-\r
- if (XB->post) {\r
-\r
- if (State->state == THINK || State->state == ANALYSE) {\r
-\r
- line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
-\r
- if(Uci->depth==-1) //hack to clear the engine output window\r
- gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb);\r
-\r
- 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
-\r
- } else if (State->state == PONDER &&\r
- option_get_bool(Option,"ShowPonder")) {\r
-\r
- game_get_board(Game,board);\r
- move = State->exp_move;\r
-\r
- if (move != MoveNone && move_is_legal(move,board)) {\r
- move_to_san(move,board,move_string,256);\r
- line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
- 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
- }\r
- }\r
- }\r
-\r
- // kibitz\r
-\r
- if ((Uci->searching &&\r
- option_get_bool(Option,"KibitzPV") &&\r
- Uci->time >= option_get_double(Option,"KibitzDelay"))\r
- || (!Uci->searching && option_get_bool(Option,"KibitzMove"))) {\r
-\r
- if (State->state == THINK || State->state == ANALYSE) {\r
-\r
- line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
- if(kibitz_throttle(Uci->searching)){\r
- 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
- }\r
- } else if (State->state == PONDER) {\r
-\r
- game_get_board(Game,board);\r
- move = State->exp_move;\r
-\r
- if (move != MoveNone && move_is_legal(move,board)) {\r
- move_to_san(move,board,move_string,256);\r
- line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
- if(kibitz_throttle(Uci->searching)){\r
- 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
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-// kibitz_throttle()\r
-\r
-static bool kibitz_throttle(bool searching){\r
- time_t curr_time;\r
- static time_t lastKibitzMove=0;\r
- static time_t lastKibitzPV=0;\r
- curr_time = time(NULL);\r
- if(searching){ // KibitzPV\r
- if(curr_time >=\r
- (option_get_int(Option,"KibitzInterval") + lastKibitzPV)){\r
- lastKibitzPV=curr_time;\r
- return TRUE;\r
- }\r
- }else{ // KibitzMove\r
- if(curr_time >=\r
- (option_get_int(Option,"KibitzInterval") + lastKibitzMove)){\r
- lastKibitzPV=curr_time;\r
- lastKibitzMove=curr_time;\r
- return TRUE;\r
- } \r
- }\r
- return FALSE;\r
-}\r
-\r
-// learn()\r
-\r
-static void learn(int result) {\r
-\r
- int pos;\r
- board_t board[1];\r
- int move;\r
-\r
- ASSERT(result>=-1&&result<=+1);\r
-\r
- ASSERT(XB->result);\r
- ASSERT(State->computer[White]||State->computer[Black]);\r
-\r
- // init\r
-\r
- pos = 0;\r
-\r
- if (FALSE) {\r
- } else if (State->computer[White]) {\r
- pos = 0;\r
- } else if (State->computer[Black]) {\r
- pos = 1;\r
- result = -result;\r
- } else {\r
- my_fatal("learn(): unknown side\n");\r
- }\r
-\r
- if (FALSE) {\r
- } else if (result > 0) {\r
- my_log("POLYGLOT *LEARN WIN*\n");\r
- } else if (result < 0) {\r
- my_log("POLYGLOT *LEARN LOSS*\n");\r
- } else {\r
- my_log("POLYGLOT *LEARN DRAW*\n");\r
- }\r
-\r
- // loop\r
-\r
- for (; pos < Game->size; pos += 2) {\r
-\r
- game_get_board_ex(Game,board,pos);\r
- move = game_move(Game,pos);\r
-\r
- book_learn_move(board,move,result);\r
- }\r
-\r
- book_flush();\r
-}\r
-\r
-// end of xboard2uci.c\r
+
+// xboard2uci.c
+
+// includes
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "board.h"
+#include "book.h"
+#include "colour.h"
+#include "engine.h"
+#include "fen.h"
+#include "game.h"
+#include "gui.h"
+#include "line.h"
+#include "main.h"
+#include "move.h"
+#include "move_do.h"
+#include "move_legal.h"
+#include "option.h"
+#include "parse.h"
+#include "san.h"
+#include "uci.h"
+#include "uci2uci.h"
+#include "util.h"
+#include "xboard2uci.h"
+
+// defines
+
+#define StringSize 4096
+
+// constants
+
+static const bool UseDebug = FALSE;
+static const bool DelayPong = FALSE;
+
+// types
+
+typedef struct {
+ int state;
+ bool computer[ColourNb];
+ bool playedAllMoves[ColourNb];
+ int exp_move;
+ int hint_move;
+ int resign_nb;
+ my_timer_t timer[1];
+} state_t;
+
+typedef struct {
+ bool has_feature_memory;
+ bool has_feature_smp;
+ bool has_feature_egt_nalimov;
+ bool has_feature_egt_gaviota;
+ bool analyse;
+ bool computer;
+ const char * name;
+ bool ics;
+ bool new_hack; // "new" is a C++ keyword
+ bool ponder;
+ int ping;
+ bool post;
+ int proto_ver;
+ bool result;
+
+ int mps;
+ double base;
+ double inc;
+
+ bool time_limit;
+ double time_max;
+
+ bool depth_limit;
+ int depth_max;
+
+ double my_time;
+ double opp_time;
+
+ int node_rate;
+} xb_t;
+
+typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t;
+
+// variables
+
+static state_t State[1];
+static xb_t XB[1];
+
+// prototypes
+
+static void comp_move (int move);
+static void move_step (int move);
+static void board_update ();
+
+static void mess ();
+static void no_mess (int move);
+
+static void search_update ();
+static void search_clear ();
+static void update_remaining_time();
+static int report_best_score();
+static bool kibitz_throttle (bool searching);
+static void start_protected_command();
+static void end_protected_command();
+
+static bool active ();
+static bool ponder ();
+static bool ponder_ok (int ponder_move);
+
+static void stop_search ();
+
+static void send_board (int extra_move);
+static void send_pv ();
+static void send_info ();
+
+static void send_xboard_options ();
+
+static void learn (int result);
+
+
+// functions
+
+// xboard2uci_init()
+
+void xboard2uci_init() {
+ // init
+
+ game_clear(Game);
+
+ // state
+
+ State->state = WAIT;
+
+ State->computer[White] = FALSE;
+ State->computer[Black] = TRUE;
+
+ State->exp_move = MoveNone;
+ State->hint_move = MoveNone;
+ State->resign_nb = 0;
+ my_timer_reset(State->timer);
+
+ // yes there are engines that do not have the "Hash" option....
+ XB->has_feature_memory= (option_find(Uci->option,"Hash")!=NULL);
+ XB->has_feature_smp = (uci_thread_option(Uci)!=NULL);
+ // TODO: support for other types of table bases
+ // This is a quick hack.
+ XB->has_feature_egt_nalimov = (option_find(Uci->option,"NalimovPath")!=NULL);
+ XB->has_feature_egt_gaviota = (option_find(Uci->option,"GaviotaTbPath")!=NULL);
+ XB->analyse = FALSE;
+ XB->computer = FALSE;
+ XB->name = NULL;
+ my_string_set(&XB->name,"<empty>");
+ XB->ics = FALSE;
+ XB->new_hack = TRUE;
+ XB->ping = -1;
+ XB->ponder = FALSE;
+ XB->post = FALSE;
+ XB->proto_ver = 1;
+ XB->result = FALSE;
+
+ XB->mps = 0;
+ XB->base = 300.0;
+ XB->inc = 0.0;
+
+ XB->time_limit = FALSE;
+ XB->time_max = 5.0;
+
+ XB->depth_limit = FALSE;
+ XB->depth_max = 127;
+
+ XB->my_time = 300.0;
+ XB->opp_time = 300.0;
+
+ XB->node_rate = -1;
+}
+
+// xboard2uci_gui_step()
+
+void xboard2uci_gui_step(char string[]) {
+
+ int move;
+ char move_string[256];
+ board_t board[1];
+
+ if (FALSE) {
+
+ } else if (match(string,"accepted *")) {
+
+ // ignore
+
+ } else if (match(string,"analyze")) {
+
+ State->computer[White] = FALSE;
+ State->computer[Black] = FALSE;
+
+ XB->analyse = TRUE;
+ XB->new_hack = FALSE;
+ ASSERT(!XB->result);
+ XB->result = FALSE;
+
+ mess();
+
+ } else if (match(string,"bk")) {
+
+ if (option_get_bool(Option,"Book")) {
+ game_get_board(Game,board);
+ book_disp(board);
+ }
+
+ } else if (match(string,"black")) {
+
+ if (colour_is_black(game_turn(Game))) {
+
+ State->computer[White] = TRUE;
+ State->computer[Black] = FALSE;
+
+ XB->new_hack = TRUE;
+ XB->result = FALSE;
+
+ mess();
+ }
+
+ } else if (match(string,"computer")) {
+
+ XB->computer = TRUE;
+
+ } else if (match(string,"draw")) {
+ if(option_find(Uci->option,"UCI_DrawOffers")){
+ my_log("POLYGLOT draw from XB received");
+ uci_send_option(Uci,"DrawOffer","%s","draw");}
+ } else if (match(string,"easy")) {
+
+ XB->ponder = FALSE;
+
+ mess();
+
+ } else if (match(string,"edit")) {
+
+ // refuse
+
+ gui_send(GUI,"Error (unknown command): %s",string);
+
+ } else if (match(string,"exit")) {
+
+ State->computer[White] = FALSE;
+ State->computer[Black] = FALSE;
+
+ XB->analyse = FALSE;
+
+ mess();
+
+ } else if (match(string,"force")) {
+
+ State->computer[White] = FALSE;
+ State->computer[Black] = FALSE;
+
+ mess();
+
+ } else if (match(string,"go")) {
+
+ State->computer[game_turn(Game)] = TRUE;
+ State->computer[colour_opp(game_turn(Game))] = FALSE;
+
+ XB->new_hack = FALSE;
+ ASSERT(!XB->result);
+ XB->result = FALSE;
+
+ mess();
+
+ } else if (match(string,"hard")) {
+
+ XB->ponder = TRUE;
+
+ mess();
+
+ } else if (match(string,"hint")) {
+
+ move=MoveNone;
+ game_get_board(Game,board);
+ if (option_get_bool(Option,"Book")) {
+
+ move = book_move(board,FALSE);
+ }
+ if(move==MoveNone && State->hint_move!=MoveNone){
+ move=State->hint_move;
+
+ }
+ if (move != MoveNone && move_is_legal(move,board)) {
+ move_to_san(move,board,move_string,256);
+ gui_send(GUI,"Hint: %s",move_string);
+ }
+
+ } else if (match(string,"ics *")) {
+
+ XB->ics = TRUE;
+
+ } else if (match(string,"level * *:* *")) {
+
+ XB->mps = atoi(Star[0]);
+ XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2]));
+ XB->inc = ((double)atoi(Star[3]));
+
+ } else if (match(string,"level * * *")) {
+
+ XB->mps = atoi(Star[0]);
+ XB->base = ((double)atoi(Star[1])) * 60.0;
+ XB->inc = ((double)atoi(Star[2]));
+
+ } else if (match(string,"name *")) {
+
+ my_string_set(&XB->name,Star[0]);
+
+ } else if (match(string,"new")) {
+
+ uci_send_isready_sync(Uci);
+ my_log("POLYGLOT NEW GAME\n");
+
+ option_set(Option,"Chess960","false");
+
+ game_clear(Game);
+
+ if (XB->analyse) {
+ State->computer[White] = FALSE;
+ State->computer[Black] = FALSE;
+ } else {
+ State->computer[White] = FALSE;
+ State->computer[Black] = TRUE;
+ State->playedAllMoves[White] = TRUE; // [HGM]
+ State->playedAllMoves[Black] = TRUE;
+ }
+
+ XB->new_hack = TRUE;
+ XB->result = FALSE;
+
+ XB->depth_limit = FALSE;
+ XB->node_rate=-1;
+
+ XB->computer = FALSE;
+ my_string_set(&XB->name,"<empty>");
+
+ board_update();
+ mess();
+
+ uci_send_ucinewgame(Uci);
+
+ } else if (match(string,"nopost")) {
+
+ XB->post = FALSE;
+
+ } else if (match(string,"otim *")) {
+
+ XB->opp_time = ((double)atoi(Star[0])) / 100.0;
+ if (XB->opp_time < 0.0) XB->opp_time = 0.0;
+
+ } else if (match(string,"pause")) {
+
+ // refuse
+
+ gui_send(GUI,"Error (unknown command): %s",string);
+
+ } else if (match(string,"ping *")) {
+
+ // HACK; TODO: answer only after an engine move
+
+ if (DelayPong) {
+ if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping
+ XB->ping = atoi(Star[0]);
+ uci_send_isready_sync(Uci);
+ } else {
+ ASSERT(XB->ping==-1);
+ gui_send(GUI,"pong %s",Star[0]);
+ }
+ } else if (match(string,"nps *")) {
+
+ // fake WB play-by-nodes mode
+ XB->node_rate = atoi(Star[0]);
+ } else if (match(string,"playother")) {
+
+ State->computer[game_turn(Game)] = FALSE;
+ State->computer[colour_opp(game_turn(Game))] = TRUE;
+
+ XB->new_hack = FALSE;
+ ASSERT(!XB->result);
+ XB->result = FALSE;
+
+ mess();
+
+ } else if (match(string,"post")) {
+
+ XB->post = TRUE;
+
+ } else if (match(string,"protover *")) {
+ XB->proto_ver = atoi(Star[0]);
+ ASSERT(XB->proto_ver>=2);
+ send_xboard_options();
+
+ } else if (match(string,"quit")) {
+ my_log("POLYGLOT *** \"quit\" from GUI ***\n");
+ quit();
+ } else if (match(string,"random")) {
+
+ // ignore
+
+ } else if (match(string,"rating * *")) {
+
+ // ignore
+
+ } else if (match(string,"remove")) {
+
+ if (game_pos(Game) >= 2) {
+
+ game_goto(Game,game_pos(Game)-2);
+
+ ASSERT(!XB->new_hack);
+ XB->new_hack = FALSE; // HACK?
+ XB->result = FALSE;
+
+ board_update();
+ mess();
+ }
+
+ } else if (match(string,"rejected *")) {
+
+ // ignore
+
+ } else if (match(string,"reset")) { // protover 3?
+
+ // refuse
+
+ gui_send(GUI,"Error (unknown command): %s",string);
+
+ } else if (FALSE
+ || match(string,"result * {*}")
+ || match(string,"result * {* }")
+ || match(string,"result * { *}")
+ || match(string,"result * { * }")) {
+
+ my_log("POLYGLOT GAME END\n");
+
+ XB->result = TRUE;
+
+ mess();
+
+ // book learning
+
+ if (option_get_bool(Option,"Book") &&
+ option_get_bool(Option,"BookLearn")) {
+
+ if (FALSE) {
+ } else if (my_string_equal(Star[0],"1-0")) {
+ learn(+1);
+ } else if (my_string_equal(Star[0],"0-1")) {
+ learn(-1);
+ } else if (my_string_equal(Star[0],"1/2-1/2")) {
+ learn(0);
+ }
+ }
+ } else if (match(string,"resume")) {
+
+ // refuse
+
+ gui_send(GUI,"Error (unknown command): %s",string);
+
+ } else if (match(string,"option *=*") ||
+ match(string,"option * =*") ||
+ match(string,"option *= *") ||
+ match(string,"option * = *")
+ ){
+ char *name=Star[0];
+ char *value=Star[1];
+ if(match(name, "Polyglot *")){
+ char *pg_name=Star[0];
+ polyglot_set_option(pg_name,value);
+ }else{
+ option_t *opt=option_find(Uci->option,name);
+ if(opt){
+ if(my_string_case_equal(opt->type,"check")){
+ value=my_string_equal(value,"1")?"true":"false";
+ }
+ start_protected_command();
+ uci_send_option(Uci, name, "%s", value);
+ end_protected_command();
+ }else{
+ gui_send(GUI,"Error (unknown option): %s",name);
+ }
+ }
+ } else if (match(string,"option *")){
+ char *name=Star[0];
+ if(match(name, "Polyglot *")){
+ char *pg_name=Star[0];
+ polyglot_set_option(pg_name,"<empty>");
+ }else{
+ start_protected_command();
+ // value is ignored
+ if(!uci_send_option(Uci, name, "%s", "<empty>")){
+ gui_send(GUI,"Error (unknown option): %s",name);
+ };
+ end_protected_command();
+ }
+ } else if (XB->has_feature_smp && match(string,"cores *")){
+ int cores=atoi(Star[0]);
+ if(cores>=1){
+ // updating the number of cores
+ my_log("POLYGLOT setting the number of cores to %d\n",cores);
+ start_protected_command();
+ uci_set_threads(Uci,cores);
+ end_protected_command();
+ } else{
+ // refuse
+ gui_send(GUI,"Error (unknown command): %s",string);
+ }
+ } else if (match(string,"egtpath * *")){
+ char *type=Star[0];
+ char *path=Star[1];
+ if(my_string_empty(path)){
+ // refuse
+ gui_send(GUI,"Error (unknown command): %s",string);
+ }else{
+ if(my_string_case_equal(type,"nalimov") && XB->has_feature_egt_nalimov){
+ // updating NalimovPath
+ my_log("POLYGLOT setting the Nalimov path to %s\n",path);
+ start_protected_command();
+ uci_send_option(Uci,"NalimovPath","%s",path);
+ end_protected_command();
+ }else if(my_string_case_equal(type,"gaviota") && XB->has_feature_egt_gaviota){
+ // updating GaviotaPath
+ my_log("POLYGLOT setting the Gaviota path to %s\n",path);
+ start_protected_command();
+ uci_send_option(Uci,"GaviotaTbPath","%s",path);
+ end_protected_command();
+ }else{
+ // refuse
+ gui_send(GUI,"Error (unsupported table base format): %s",string);
+ }
+ }
+ } else if (XB->has_feature_memory && match(string,"memory *")){
+ int memory = atoi(Star[0]);
+ int egt_cache;
+ int real_memory;
+ if(memory>=1){
+ // updating the available memory
+ option_t *opt;
+ my_log("POLYGLOT setting the amount of memory to %dMb\n",memory);
+ if(XB->has_feature_egt_nalimov && (opt=option_find(Uci->option,"NalimovCache"))){
+ egt_cache=atoi(opt->value);
+ }else if(XB->has_feature_egt_gaviota &&
+ (opt=option_find(Uci->option,"GaviotaTbCache"))){
+ egt_cache=atoi(opt->value);
+ }else{
+ egt_cache=0;
+ }
+ my_log("POLYGLOT EGTB Cache is %dMb\n",egt_cache);
+ real_memory=memory-egt_cache;
+ if(real_memory>0){
+ start_protected_command();
+ uci_send_option(Uci,"Hash", "%d", real_memory);
+ end_protected_command();
+ }
+ }else{
+ // refuse
+ gui_send(GUI,"Error (unknown command): %s",string);
+ }
+
+ } else if (match(string,"sd *")) {
+
+ XB->depth_limit = TRUE;
+ XB->depth_max = atoi(Star[0]);
+
+ } else if (match(string,"setboard *")) {
+
+ my_log("POLYGLOT FEN %s\n",Star[0]);
+
+ if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]);
+
+ State->computer[White] = FALSE;
+ State->computer[Black] = FALSE;
+
+ XB->new_hack = TRUE; // HACK?
+ XB->result = FALSE;
+
+ board_update();
+ mess();
+
+ } else if (match(string,"st *")) {
+
+ XB->time_limit = TRUE;
+ XB->time_max = ((double)atoi(Star[0]));
+
+ } else if (match(string,"time *")) {
+
+ XB->my_time = ((double)atoi(Star[0])) / 100.0;
+ if (XB->my_time < 0.0) XB->my_time = 0.0;
+
+ } else if (match(string,"undo")) {
+
+ if (game_pos(Game) >= 1) {
+
+ game_goto(Game,game_pos(Game)-1);
+
+ ASSERT(!XB->new_hack);
+ XB->new_hack = FALSE; // HACK?
+ XB->result = FALSE;
+
+ board_update();
+ mess();
+ }
+
+ } else if (match(string,"usermove *")) {
+
+ game_get_board(Game,board);
+ move = move_from_san(Star[0],board);
+
+ if (move != MoveNone && move_is_legal(move,board)) {
+
+ XB->new_hack = FALSE;
+ ASSERT(!XB->result);
+ XB->result = FALSE;
+
+ // [HGM] externally supplied move means we did not fully play the current stm
+ State->playedAllMoves[colour_is_white(game_turn(Game)) ? White : Black] = FALSE;
+
+ move_step(move);
+ no_mess(move);
+
+ } else {
+
+ gui_send(GUI,"Illegal move: %s",Star[0]);
+ }
+
+ } else if (match(string,"variant *")) {
+
+ if (my_string_equal(Star[0],"fischerandom")) {
+ option_set(Option,"Chess960","true");
+ } else {
+ option_set(Option,"Chess960","false");
+ }
+
+ } else if (match(string,"white")) {
+
+ if (colour_is_white(game_turn(Game))) {
+
+ State->computer[White] = FALSE;
+ State->computer[Black] = TRUE;
+
+ XB->new_hack = TRUE;
+ XB->result = FALSE;
+
+ mess();
+ }
+
+ } else if (match(string,"xboard")) {
+
+ // ignore
+
+ } else if (match(string,".")) { // analyse info
+
+ if (State->state == ANALYSE) {
+ int depth=Uci->best_depth;//HACK: don't clear engine-output window...
+
+ ASSERT(Uci->searching);
+ ASSERT(Uci->pending_nb>=1);
+
+ if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) {
+ move_to_san(Uci->root_move,Uci->board,move_string,256);
+ 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);
+ } else {
+ gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK
+ }
+ }
+
+ } else if (match(string,"?")) { // move now
+
+ if (State->state == THINK) {
+
+ ASSERT(Uci->searching);
+ ASSERT(Uci->pending_nb>=1);
+
+ // HACK: just send "stop" to the engine
+
+ if (Uci->searching) {
+ my_log("POLYGLOT STOP SEARCH\n");
+ engine_send(Engine,"stop");
+ }
+ }
+
+ } else { // unknown command, maybe a move?
+
+ game_get_board(Game,board);
+ move = move_from_san(string,board);
+
+ if (move != MoveNone && move_is_legal(move,board)) {
+
+ XB->new_hack = FALSE;
+ ASSERT(!XB->result);
+ XB->result = FALSE;
+
+ move_step(move);
+ no_mess(move);
+
+ } else if (move != MoveNone) {
+
+ gui_send(GUI,"Illegal move: %s",string);
+
+ } else {
+
+ gui_send(GUI,"Error (unknown command): %s",string);
+ }
+ }
+ return;
+}
+
+// xboard2uci_engine_step()
+
+void xboard2uci_engine_step(char string[]) {
+
+ int event;
+ board_t board[1];
+ event = uci_parse(Uci,string);
+
+ // react to events
+
+ if ((event & EVENT_READY) != 0) {
+
+ // the engine is now ready
+
+ if (!Uci->ready) {
+ Uci->ready = TRUE;
+ // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1");
+ }
+
+ if (!DelayPong && XB->ping >= 0) {
+ gui_send(GUI,"pong %d",XB->ping);
+ XB->ping = -1;
+ }
+ }
+
+ if ((event & EVENT_MOVE) != 0 && State->state == THINK) {
+
+ // the engine is playing a move
+
+ // MEGA HACK: estimate remaining time because XBoard won't send it!
+
+ my_timer_stop(State->timer);
+
+ XB->my_time -= my_timer_elapsed_real(State->timer);
+ XB->my_time += XB->inc;
+ if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base;
+
+ if (XB->my_time < 0.0) XB->my_time = 0.0;
+
+ // make sure to remember the ponder move
+
+ State->hint_move=Uci->ponder_move;
+
+ // play the engine move
+
+ comp_move(Uci->best_move);
+
+ }
+
+ if ((event & EVENT_PV) != 0) {
+
+ // the engine has sent a new PV
+
+ send_pv();
+ }
+ if ((event & EVENT_INFO) != 0) {
+
+ // the engine has sent info
+
+ send_info();
+ }
+ if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){
+ my_log("POYGLOT draw offer/resign from engine\n");
+ if(option_find(Uci->option,"UCI_DrawOffers")){
+ if(event & EVENT_DRAW)
+ gui_send(GUI,"offer draw");
+ else
+ gui_send(GUI,"resign");
+ }
+ }
+ if(((event & EVENT_ILLEGAL_MOVE)!=0) && (State->state == THINK)){
+ game_get_board(Game,board);
+ if(board->turn==White){
+ gui_send(GUI,"0-1 {polyglot: resign"
+ " (illegal engine move by white: %s)}",Uci->bestmove);
+ }else{
+ gui_send(GUI,"1-0 {polyglot: resign"
+ " (illegal engine move by black: %s)}",Uci->bestmove);
+ }
+ board_disp(board);
+ XB->result = TRUE;
+ mess();
+ }
+}
+
+// format_xboard_option_line
+
+void format_xboard_option_line(char * option_line, option_t *opt){
+ int j;
+ char option_string[StringSize];
+ char *tmp;
+ strcpy(option_line,"");
+ // buffer overflow alert
+ strcat(option_line,"feature option=\"");
+ if(opt->mode&PG){
+ strcat(option_line,"Polyglot ");
+ }
+ sprintf(option_string,"%s",opt->name);
+ strcat(option_line,option_string);
+ sprintf(option_string," -%s",opt->type);
+ strcat(option_line,option_string);
+ if(!IS_BUTTON(opt->type) && strcmp(opt->type,"combo")){
+ if(strcmp(opt->type,"check")){
+ sprintf(option_string," %s",opt->value);
+ }else{
+ sprintf(option_string," %d",
+ my_string_case_equal(opt->value,"true")||
+ my_string_equal(opt->value,"1")
+ ?1:0);
+ }
+ strcat(option_line,option_string);
+ }
+ if(IS_SPIN(opt->type)){
+ sprintf(option_string," %s",opt->min);
+ strcat(option_line,option_string);
+ }
+ if(IS_SPIN(opt->type)){
+ sprintf(option_string," %s",opt->max);
+ strcat(option_line,option_string);
+ }
+ for(j=0;j<opt->var_nb;j++){
+ if(!strcmp(opt->var[j],opt->value)){
+ sprintf(option_string," *%s",opt->var[j]);
+ }else{
+ sprintf(option_string," %s",opt->var[j]);
+ }
+ strcat(option_line,option_string);
+ if(j!=opt->var_nb-1){
+ strcat(option_line," ///");
+ }
+ }
+ strcat(option_line,"\"");
+ if(option_get_bool(Option,"WbWorkArounds") &&
+ (tmp=strstr(option_line,"Draw"))){
+ *tmp='d';
+ my_log("POLYGLOT Decapitalizing \"Draw\" in option \"%s\"\n",
+ opt->name);
+ }
+}
+
+// disarm() // [HGM] cleanse a string of offending double-quotes
+
+static char*disarm(const char *s){
+ static char buf[25];
+ char *p = buf, *q;
+ strncpy(buf, s, 24);
+ q = buf + strlen(buf) - 1;
+ while(*q == '"') *q-- = '\0'; // strip trailing quotes
+ while(*p == '"') p++; // strip leading quotes
+ while((q = strchr(p, '"'))) *q = '\''; // replace internal quotes
+ return p;
+}
+
+// send_xboard_options()
+
+static void send_xboard_options(){
+
+ char egtfeature[StringSize];
+ int tbs=0;
+
+ gui_send(GUI,"feature done=0");
+
+ gui_send(GUI,"feature analyze=1");
+ gui_send(GUI,"feature colors=0");
+ gui_send(GUI,"feature draw=1");
+ gui_send(GUI,"feature ics=1");
+ gui_send(GUI,"feature myname=\"%s\"",
+ disarm(option_get_string(Option,"EngineName")));
+ gui_send(GUI,"feature name=1");
+ gui_send(GUI,"feature pause=0");
+ gui_send(GUI,"feature ping=1");
+ gui_send(GUI,"feature playother=1");
+ gui_send(GUI,"feature sigint=1");
+ gui_send(GUI,"feature reuse=1");
+ gui_send(GUI,"feature san=0");
+ gui_send(GUI,"feature setboard=1");
+ gui_send(GUI,"feature sigint=0");
+ gui_send(GUI,"feature sigterm=0");
+ gui_send(GUI,"feature time=1");
+ gui_send(GUI,"feature usermove=1");
+ gui_send(GUI,"feature nps=1");
+ if (XB->has_feature_memory){
+ gui_send(GUI,"feature memory=1");
+ }else{
+ gui_send(GUI,"feature memory=0");
+ }
+ if (XB->has_feature_smp){
+ gui_send(GUI,"feature smp=1");
+ }else{
+ gui_send(GUI,"feature smp=0");
+ }
+ egtfeature[0]='\0';
+ strncat(egtfeature,"feature egt=\"",StringSize);
+ if (XB->has_feature_egt_nalimov){
+ tbs++;
+ strncat(egtfeature,"nalimov",StringSize-strlen(egtfeature));
+ }
+ if (XB->has_feature_egt_gaviota){
+ if(tbs>0){
+ strncat(egtfeature,",",StringSize-strlen(egtfeature));
+ }
+ strncat(egtfeature,"gaviota",StringSize-strlen(egtfeature));
+ }
+ strncat(egtfeature,"\"",StringSize-strlen(egtfeature));
+ egtfeature[StringSize-1]='\0';
+ gui_send(GUI,egtfeature);
+
+ if (option_find(Uci->option,"UCI_Chess960")) {
+ gui_send(GUI,"feature variants=\"normal,fischerandom\"");
+ } else {
+ gui_send(GUI,"feature variants=\"normal\"");
+ }
+
+ xboard2uci_send_options();
+}
+
+void xboard2uci_send_options(){
+ char option_line[StringSize]="";
+ const char * name;
+ option_t *opt;
+
+ option_start_iter(Uci->option);
+ while((opt=option_next(Uci->option))){
+ if(my_string_case_equal(opt->name,"UCI_AnalyseMode")) continue;
+ if(my_string_case_equal(opt->name,"UCI_Opponent")) continue;
+ if(my_string_case_equal(opt->name,"UCI_Chess960")) continue;
+ if(my_string_case_equal(opt->name,"UCI_ShowCurrLine")) continue;
+ if(my_string_case_equal(opt->name,"UCI_ShowRefutations")) continue;
+ if(my_string_case_equal(opt->name,"UCI_ShredderbasesPath")) continue;
+ if(my_string_case_equal(opt->name,"UCI_SetPositionValue")) continue;
+ if(my_string_case_equal(opt->name,"UCI_DrawOffers")) continue;
+ if(my_string_case_equal(opt->name,"Ponder")) continue;
+ if(my_string_case_equal(opt->name,"Hash")) continue;
+ if(my_string_case_equal(opt->name,"NalimovPath")) continue;
+ if(my_string_case_equal(opt->name,"GaviotaTbPath")) continue;
+ if((name=uci_thread_option(Uci))!=NULL &&
+ my_string_case_equal(opt->name,name)) continue;
+ format_xboard_option_line(option_line,opt);
+
+ gui_send(GUI,"%s",option_line);
+ }
+
+
+ option_start_iter(Option);
+ while((opt=option_next(Option))){
+ if(opt->mode &XBOARD){
+ format_xboard_option_line(option_line,opt);
+ gui_send(GUI,"%s",option_line);
+ }
+ }
+ gui_send(GUI,"feature done=1");
+
+}
+
+// report_best_score()
+
+static int report_best_score(){
+ if(!option_get_bool(Option,"ScoreWhite") ||
+ colour_is_white(Uci->board->turn)){
+ return Uci->best_score;
+ }else{
+ return -Uci->best_score;
+ }
+}
+
+// comp_move()
+
+static void comp_move(int move) {
+
+ board_t board[1];
+ char string[256];
+
+ ASSERT(move_is_ok(move));
+
+ ASSERT(State->state==THINK);
+ ASSERT(!XB->analyse);
+
+ if(option_get_bool(Option,"RepeatPV"))
+ send_pv(); // to update time and nodes
+
+ // send the move
+
+ game_get_board(Game,board);
+
+ if (move_is_castle(move,board) && option_get_bool(Option,"Chess960")) {
+ if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O
+ } else {
+ if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n");
+ }
+
+ gui_send(GUI,"move %s",string);
+
+ // resign?
+
+ if (option_get_bool(Option,"Resign") && Uci->root_move_nb > 1) {
+
+ if (Uci->best_score <= -abs(option_get_int(Option,"ResignScore"))) {
+
+ State->resign_nb++;
+ my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":"");
+
+ if (State->resign_nb >= option_get_int(Option,"ResignMoves")) {
+ my_log("POLYGLOT *** RESIGN ***\n");
+ gui_send(GUI,"resign");
+ }
+
+ } else {
+
+ if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb);
+ State->resign_nb = 0;
+ }
+ }
+
+ // play the move
+
+ move_step(move);
+ no_mess(move);
+}
+
+// move_step()
+
+static void move_step(int move) {
+
+ board_t board[1];
+ char move_string[256];
+
+ ASSERT(move_is_ok(move));
+
+ // log
+
+ game_get_board(Game,board);
+
+ if (move != MoveNone && move_is_legal(move,board)) {
+
+ move_to_san(move,board,move_string,256);
+ my_log("POLYGLOT MOVE %s\n",move_string);
+
+ } else {
+
+ move_to_can(move,board,move_string,256);
+ my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string);
+ board_disp(board);
+
+ my_fatal("move_step(): illegal move \"%s\"\n",move_string);
+ }
+
+ // play the move
+
+ game_add_move(Game,move);
+ board_update();
+}
+
+// board_update()
+
+static void board_update() {
+
+ // handle game end
+
+ ASSERT(!XB->result);
+
+ switch (game_status(Game)) {
+ case PLAYING:
+ break;
+ case WHITE_MATES:
+ gui_send(GUI,"1-0 {White mates}");
+ break;
+ case BLACK_MATES:
+ gui_send(GUI,"0-1 {Black mates}");
+ break;
+ case STALEMATE:
+ gui_send(GUI,"1/2-1/2 {Stalemate}");
+ break;
+ case DRAW_MATERIAL:
+ gui_send(GUI,"1/2-1/2 {Draw by insufficient material}");
+ break;
+ case DRAW_FIFTY:
+ gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}");
+ break;
+ case DRAW_REPETITION:
+ gui_send(GUI,"1/2-1/2 {Draw by repetition}");
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+}
+
+// mess()
+
+static void mess() {
+
+ // clear state variables
+
+ State->resign_nb = 0;
+ State->exp_move = MoveNone;
+ my_timer_reset(State->timer);
+
+ // abort a possible search
+
+ stop_search();
+
+ // calculate the new state
+
+ if (FALSE) {
+ } else if (!active()) {
+ State->state = WAIT;
+ my_log("POLYGLOT WAIT\n");
+ } else if (XB->analyse) {
+ State->state = ANALYSE;
+ my_log("POLYGLOT ANALYSE\n");
+ } else if (State->computer[game_turn(Game)]) {
+ State->state = THINK;
+ my_log("POLYGLOT THINK\n");
+ } else {
+ State->state = WAIT;
+ my_log("POLYGLOT WAIT\n");
+ }
+
+ search_update();
+}
+
+// no_mess()
+
+static void no_mess(int move) {
+
+ ASSERT(move_is_ok(move));
+
+ // just received a move, calculate the new state
+
+ if (FALSE) {
+
+ } else if (!active()) {
+
+ stop_search(); // abort a possible search
+
+ State->state = WAIT;
+ State->exp_move = MoveNone;
+
+ my_log("POLYGLOT WAIT\n");
+
+ } else if (State->state == WAIT) {
+
+ ASSERT(State->computer[game_turn(Game)]);
+ ASSERT(!State->computer[colour_opp(game_turn(Game))]);
+ ASSERT(!XB->analyse);
+
+ my_log("POLYGLOT WAIT -> THINK\n");
+
+ State->state = THINK;
+ State->exp_move = MoveNone;
+
+ } else if (State->state == THINK) {
+
+ ASSERT(!State->computer[game_turn(Game)]);
+ ASSERT(State->computer[colour_opp(game_turn(Game))]);
+ ASSERT(!XB->analyse);
+
+ if (ponder() && ponder_ok(Uci->ponder_move)) {
+
+ my_log("POLYGLOT THINK -> PONDER\n");
+
+ State->state = PONDER;
+ State->exp_move = Uci->ponder_move;
+
+ } else {
+
+ my_log("POLYGLOT THINK -> WAIT\n");
+
+ State->state = WAIT;
+ State->exp_move = MoveNone;
+ }
+
+ } else if (State->state == PONDER) {
+
+ ASSERT(State->computer[game_turn(Game)]);
+ ASSERT(!State->computer[colour_opp(game_turn(Game))]);
+ ASSERT(!XB->analyse);
+
+ if (move == State->exp_move && Uci->searching) {
+
+ ASSERT(Uci->searching);
+ ASSERT(Uci->pending_nb>=1);
+
+ my_timer_start(State->timer);//also resets
+
+ my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n");
+ engine_send(Engine,"ponderhit");
+
+ State->state = THINK;
+ State->exp_move = MoveNone;
+
+ send_pv(); // update display
+
+ return; // do not launch a new search
+
+ } else {
+
+ my_log("POLYGLOT PONDER -> THINK (miss)\n");
+
+ stop_search();
+
+ State->state = THINK;
+ State->exp_move = MoveNone;
+ }
+
+ } else if (State->state == ANALYSE) {
+
+ ASSERT(XB->analyse);
+
+ my_log("POLYGLOT ANALYSE -> ANALYSE\n");
+
+ stop_search();
+
+ } else {
+
+ ASSERT(FALSE);
+ }
+
+ search_update();
+}
+
+// start_protected_command()
+
+static void start_protected_command(){
+ stop_search();
+}
+
+static void end_protected_command(){
+ if(Uci->ready){ // not init faze
+ uci_send_isready_sync(Uci); // gobble up spurious "bestmove"
+ }
+ update_remaining_time();
+ search_update(); // relaunch search if necessary
+}
+
+// update_remaining_time()
+
+static void update_remaining_time(){
+ double reduce;
+ if(State->timer->running){
+ my_timer_stop(State->timer);
+ reduce = my_timer_elapsed_real(State->timer);
+ my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce);
+ XB->my_time -= reduce;
+ if(XB->my_time<0.0){
+ XB->my_time=0.0;
+ }
+ }
+}
+
+
+// search_update()
+
+static void search_update() {
+
+ int move;
+ int move_nb;
+ board_t board[1];
+
+ ASSERT(!Uci->searching);
+
+
+
+
+ // launch a new search if needed
+
+
+
+ if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {
+
+ // [VdB] moved up as we need the move number
+
+ game_get_board(Game,Uci->board);
+
+ // opening book
+
+ if (State->state == THINK &&
+ option_get_bool(Option,"Book") &&
+ Uci->board->move_nb<option_get_int(Option,"BookDepth")
+ ) {
+
+
+ move = book_move(Uci->board,option_get_bool(Option,"BookRandom"));
+
+ if (move != MoveNone && move_is_legal(move,Uci->board)) {
+
+ my_log("POLYGLOT *BOOK MOVE*\n");
+
+ search_clear(); // clears Uci->ponder_move
+ Uci->best_move = move;
+
+ board_copy(board,Uci->board);
+ move_do(board,move);
+ Uci->ponder_move = book_move(board,FALSE); // expected move = best book move
+
+ Uci->best_pv[0] = Uci->best_move;
+ Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone
+ Uci->best_pv[2] = MoveNone;
+
+ comp_move(Uci->best_move);
+
+ return;
+ }
+ }
+
+ // engine search
+
+ my_log("POLYGLOT START SEARCH\n");
+
+ // options
+
+ uci_send_option(Uci,"UCI_Chess960","%s",
+ option_get_bool(Option,"Chess960")?"true":"false");
+
+ if (option_get_int(Option,"UCIVersion") >= 2) {
+ uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);
+ uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false");
+ }
+
+ uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false");
+
+ // position
+
+ move = (State->state == PONDER) ? State->exp_move : MoveNone;
+ send_board(move); // updates Uci->board global variable
+
+ // search
+
+ if (State->state == THINK || State->state == PONDER) {
+
+ engine_send_queue(Engine,"go");
+
+ if (XB->time_limit) {
+
+ // fixed time per move
+
+ if(XB->node_rate > 0){
+ engine_send_queue(Engine,
+ " nodes %.0f",
+ XB->time_max*((double)XB->node_rate));
+ }else{
+ double computed_time;
+ double st_fudge;
+ st_fudge=(double) option_get_int(Option,"STFudge");
+ my_log("POLYGLOT Giving engine %.0fmsec extra time.\n",st_fudge);
+ computed_time=XB->time_max*1000.0-st_fudge;
+ if(computed_time< 1.0){
+ computed_time=1.0;
+ }
+ engine_send_queue(Engine,
+ " movetime %.0f",
+ computed_time);
+ }
+
+ } else {
+
+ // time controls
+
+ if(XB->node_rate > 0) {
+ double time;
+ move_nb = 40;
+ if (XB->mps != 0){
+ move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
+ }
+ time = XB->my_time / move_nb;
+ if(XB->inc != 0){
+ time += XB->inc;
+ }
+ if(time > XB->my_time){
+ time = XB->my_time;
+ }
+ engine_send_queue(Engine,
+ " nodes %.0f",
+ time*XB->node_rate);
+ } else {
+
+ if (colour_is_white(Uci->board->turn)) {
+ engine_send_queue(Engine,
+ " wtime %.0f btime %.0f",
+ XB->my_time*1000.0,XB->opp_time*1000.0);
+ } else {
+ engine_send_queue(Engine,
+ " wtime %.0f btime %.0f",
+ XB->opp_time*1000.0,XB->my_time*1000.0);
+ }
+
+ if (XB->inc != 0.0){
+ engine_send_queue(Engine,
+ " winc %.0f binc %.0f",
+ XB->inc*1000.0,XB->inc*1000.0);
+ }
+ if (XB->mps != 0) {
+
+ move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
+ ASSERT(move_nb>=1&&move_nb<=XB->mps);
+
+ engine_send_queue(Engine," movestogo %d",move_nb);
+ }
+ }
+ }
+ if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);
+
+ if (State->state == PONDER) engine_send_queue(Engine," ponder");
+
+ engine_send(Engine,""); // newline
+
+ } else if (State->state == ANALYSE) {
+
+ engine_send(Engine,"go infinite");
+
+ } else {
+
+ ASSERT(FALSE);
+ }
+
+ // init search info
+
+ ASSERT(!Uci->searching);
+
+ search_clear();
+
+ Uci->searching = TRUE;
+ Uci->pending_nb++;
+ }
+}
+
+// search_clear()
+
+static void search_clear() {
+
+ uci_clear(Uci);
+
+ // TODO: MOVE ME
+
+ my_timer_start(State->timer);//also resets
+}
+
+// active()
+
+static bool active() {
+
+ // position state
+
+ if (game_status(Game) != PLAYING) return FALSE; // game ended
+
+ // xboard state
+
+ if (XB->analyse) return TRUE; // analysing
+ if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode
+ if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game
+
+ return TRUE; // playing
+}
+
+// ponder()
+
+static bool ponder() {
+
+ return XB->ponder && (option_get_bool(Option,"CanPonder") ||
+ option_find(Uci->option,"Ponder"));
+}
+// ponder_ok()
+
+static bool ponder_ok(int move) {
+ int status;
+ board_t board[1];
+
+ ASSERT(move==MoveNone||move_is_ok(move));
+
+ // legal ponder move?
+
+ if (move == MoveNone) return FALSE;
+
+ game_get_board(Game,board);
+ if (!move_is_legal(move,board)) return FALSE;
+
+ // UCI-legal resulting position?
+
+ game_add_move(Game,move);
+
+ game_get_board(Game,board);
+ status = game_status(Game);
+
+ game_rem_move(Game);
+
+ if (status != PLAYING) return FALSE; // game ended
+
+ if (option_get_bool(Option,"Book") && is_in_book(board)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// stop_search()
+
+static void stop_search() {
+
+ if (Uci->searching) {
+
+ ASSERT(Uci->searching);
+ ASSERT(Uci->pending_nb>=1);
+
+ my_log("POLYGLOT STOP SEARCH\n");
+
+/*
+ engine_send(Engine,"stop");
+ Uci->searching = FALSE;
+*/
+
+ if (option_get_bool(Option,"SyncStop")) {
+ uci_send_stop_sync(Uci);
+ } else {
+ uci_send_stop(Uci);
+ }
+ }
+}
+
+// send_board()
+
+static void send_board(int extra_move) {
+
+ char fen[256];
+ int start, end;
+ board_t board[1];
+ int pos;
+ int move;
+ char string[256];
+
+ ASSERT(extra_move==MoveNone||move_is_ok(extra_move));
+
+ ASSERT(!Uci->searching);
+
+ // init
+
+ game_get_board(Game,Uci->board);
+ if (extra_move != MoveNone) move_do(Uci->board,extra_move);
+
+ board_to_fen(Uci->board,fen,256);
+ my_log("POLYGLOT FEN %s\n",fen);
+
+ ASSERT(board_can_play(Uci->board));
+
+ // more init
+
+ start = 0;
+ end = game_pos(Game);
+ ASSERT(end>=start);
+
+ // position
+
+ game_get_board_ex(Game,board,start);
+ board_to_fen(board,string,256);
+
+ engine_send_queue(Engine,"position");
+
+ if (my_string_equal(string,StartFen)) {
+ engine_send_queue(Engine," startpos");
+ } else {
+ engine_send_queue(Engine," fen %s",string);
+ }
+
+ // move list
+
+ if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves");
+
+ for (pos = start; pos < end; pos++) { // game moves
+
+ move = game_move(Game,pos);
+
+ move_to_can(move,board,string,256);
+ engine_send_queue(Engine," %s",string);
+
+ move_do(board,move);
+ }
+
+ if (extra_move != MoveNone) { // move to ponder on
+ move_to_can(extra_move,board,string,256);
+ engine_send_queue(Engine," %s",string);
+ }
+
+ // end
+
+ engine_send(Engine,""); // newline
+}
+
+// send_info()
+
+static void send_info() {
+ int min_depth;
+ if(option_get_bool(Option,"WbWorkArounds2")){
+ // Silly bug in some versions of WinBoard.
+ // depth <=1 clears the engine output window.
+ // Why shouldn't an engine be allowed to send info at depth 1?
+ min_depth=2;
+ }else{
+ min_depth=1;
+ }
+ gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth>min_depth?Uci->best_depth:min_depth,
+ 0,0.0,U64(0),Uci->info);
+}
+
+// send_pv()
+
+static void send_pv() {
+
+ char pv_string[StringSize];
+ board_t board[1];
+ int move;
+ char move_string[StringSize];
+
+ ASSERT(State->state!=WAIT);
+
+ if (Uci->best_depth == 0) return;
+
+ // xboard search information
+
+ if (XB->post) {
+
+ if (State->state == THINK || State->state == ANALYSE) {
+
+ line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
+
+ if(Uci->depth==-1) //hack to clear the engine output window
+ gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb);
+
+ gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,pv_string);
+
+ } else if (State->state == PONDER &&
+ option_get_bool(Option,"ShowPonder")) {
+
+ game_get_board(Game,board);
+ move = State->exp_move;
+
+ if (move != MoveNone && move_is_legal(move,board)) {
+ move_to_san(move,board,move_string,256);
+ line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
+ 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);
+ }
+ }
+ }
+
+ // kibitz
+
+ if ((Uci->searching &&
+ option_get_bool(Option,"KibitzPV") &&
+ Uci->time >= option_get_double(Option,"KibitzDelay"))
+ || (!Uci->searching && option_get_bool(Option,"KibitzMove"))) {
+
+ if (State->state == THINK || State->state == ANALYSE) {
+
+ line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
+ if(kibitz_throttle(Uci->searching)){
+ 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);
+ }
+ } else if (State->state == PONDER) {
+
+ game_get_board(Game,board);
+ move = State->exp_move;
+
+ if (move != MoveNone && move_is_legal(move,board)) {
+ move_to_san(move,board,move_string,256);
+ line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);
+ if(kibitz_throttle(Uci->searching)){
+ 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);
+ }
+ }
+ }
+ }
+}
+
+// kibitz_throttle()
+
+static bool kibitz_throttle(bool searching){
+ time_t curr_time;
+ static time_t lastKibitzMove=0;
+ static time_t lastKibitzPV=0;
+ curr_time = time(NULL);
+ if(searching){ // KibitzPV
+ if(curr_time >=
+ (option_get_int(Option,"KibitzInterval") + lastKibitzPV)){
+ lastKibitzPV=curr_time;
+ return TRUE;
+ }
+ }else{ // KibitzMove
+ if(curr_time >=
+ (option_get_int(Option,"KibitzInterval") + lastKibitzMove)){
+ lastKibitzPV=curr_time;
+ lastKibitzMove=curr_time;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// learn()
+
+static void learn(int result) {
+
+ int pos;
+ board_t board[1];
+ int move;
+
+ ASSERT(result>=-1&&result<=+1);
+
+ ASSERT(XB->result);
+// ASSERT(State->computer[White]||State->computer[Black]);
+
+ // init
+
+ pos = 0;
+
+ // [HGM] does not account for the hypothetical possibility we played both sides!
+ if (State->playedAllMoves[White]) {
+ pos = 0;
+ } else if (State->playedAllMoves[Black]) {
+ pos = 1;
+ result = -result;
+ } else {
+ return; // [HGM] if we did not play all moves for some side, do not learn, but don't make a fuss!
+ }
+
+ if (FALSE) {
+ } else if (result > 0) {
+ my_log("POLYGLOT *LEARN WIN*\n");
+ } else if (result < 0) {
+ my_log("POLYGLOT *LEARN LOSS*\n");
+ } else {
+ my_log("POLYGLOT *LEARN DRAW*\n");
+ }
+
+ // loop
+
+ for (; pos < Game->size; pos += 2) {
+
+ game_get_board_ex(Game,board,pos);
+ move = game_move(Game,pos);
+
+ book_learn_move(board,move,result);
+ }
+
+ book_flush();
+}
+
+// end of xboard2uci.c