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 (XB->ics || (move != MoveNone && move_is_legal(move,board))) { move_to_san(move,board,move_string,sizeof(move_string)); my_log("POLYGLOT MOVE %s\n",move_string); } else { move_to_can(move,board,move_string,sizeof(move_string)); my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string); board_disp(board); //since we have threads my_fatal is not enough,1 thread will wait for xboard to end the game //stuff illegal move in the comment as well,not everybody logs all the time. if(board->turn==White) xboard_send(XBoard,"0-1 {polyglot: %s illegal engine move white}\n",move_string); else xboard_send(XBoard,"1-0 {polyglot: %s illegal engine move black}\n",move_string); my_fatal("move_step(): illegal move \"%s\"\n",move_string); } // play the move game_add_move(Game,move); //board_update(); }
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); xboard_send(XBoard,"%d %+d %.0f %lld %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,pv_string); } else if (State->state == PONDER && option_get_bool("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); xboard_send(XBoard,"%d %+d %.0f %lld (%s) %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,move_string,pv_string); } } } // kibitz if ((Uci->searching && option_get_bool("KibitzPV") && Uci->time >= option_get_double("KibitzDelay")) || (!Uci->searching && option_get_bool("KibitzMove"))) { if (State->state == THINK || State->state == ANALYSE) { line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); xboard_send(XBoard,"%s depth=%d time=%.2f node=%lld speed=%.0f score=%+.2f pv=\"%s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,pv_string); } 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); xboard_send(XBoard,"%s depth=%d time=%.2f node=%lld speed=%.0f score=%+.2f pv=\"(%s) %s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,move_string,pv_string); } } } }
// move_step() void engine_move_fail(char *move_string){ board_t board[1]; game_get_board(Game,board); if(XB->ics) return; // if(board->turn==White) xboard_send(XBoard,"0-1 {polyglot: %s engine move format-error white}\n",move_string); else xboard_send(XBoard,"1-0 {polyglot: %s engine move format-error black}\n",move_string); my_fatal("parse_bestmove(): not a move \"%s\"\n",move_string); }
static void send_pv() { char pv_string[StringSize]; board_t board[1]; int move; char move_string[256]; char tb_string[256]; ASSERT(State->state!=WAIT); if (Uci->best_depth == 0) return; // move_string[0]='\0'; // xboard search information if (XB->post && Uci->time >= option_get_double("PostDelay")) { if (State->state == THINK || State->state == ANALYSE) { line_to_san(Uci->best_pv,Uci->board,pv_string,sizeof(pv_string)); tb_to_string(tb_string,sizeof(tb_string)); if(Uci->depth==-1) //hack to clear the engine output window xboard_send(XBoard,"%d %+d %.0f " S64_FORMAT " ",0,Uci->best_score,Uci->time*100.0,Uci->node_nb); xboard_send(XBoard,"%d %+d %.0f " S64_FORMAT " %s %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,pv_string,tb_string); } else if (State->state == PONDER && option_get_bool("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,sizeof(move_string)); line_to_san(Uci->best_pv,Uci->board,pv_string,sizeof(pv_string)); tb_to_string(tb_string,sizeof(tb_string)); xboard_send(XBoard,"%d %+d %.0f " S64_FORMAT " (%s) %s %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,move_string,pv_string,tb_string); } } } // kibitz if ((Uci->searching && option_get_bool("KibitzPV") && Uci->time >= option_get_double("KibitzDelay")) || (!Uci->searching && option_get_bool("KibitzMove"))) { if (State->state == THINK || State->state == ANALYSE) { line_to_san(Uci->best_pv,Uci->board,pv_string,sizeof(pv_string)); xboard_send(XBoard,"%s depth=%d time=%.2f node=" S64_FORMAT " speed=%.0f score=%+.2f pv=\"%s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,pv_string); } 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,sizeof(move_string)); line_to_san(Uci->best_pv,Uci->board,pv_string,sizeof(pv_string)); xboard_send(XBoard,"%s depth=%d time=%.2f node=" S64_FORMAT " speed=%.0f score=%+.2f pv=\"(%s) %s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,move_string,pv_string); } } } }
static void engine_step() { char string[StringSize]; int event; // parse UCI line engine_get(Engine,string,StringSize); 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) { xboard_send(XBoard,"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; // play the engine move comp_move(Uci->best_move); } if ((event & EVENT_PV) != 0) { // the engine has sent a new PV send_pv(); } }
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); send_pv(); // to update time and nodes // send the move game_get_board(Game,board); if (move_is_castle(move,board) && option_get_bool("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"); } xboard_send(XBoard,"move %s",string); // resign? if (option_get_bool("Resign") && Uci->root_move_nb > 1) { if (Uci->best_score <= -abs(option_get_int("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("ResignMoves")) { my_log("POLYGLOT *** RESIGN ***\n"); xboard_send(XBoard,"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); }
static void board_update() { // handle game end ASSERT(!XB->result); switch (game_status(Game)) { case PLAYING: break; case WHITE_MATES: xboard_send(XBoard,"1-0 {White mates}"); break; case BLACK_MATES: xboard_send(XBoard,"0-1 {Black mates}"); break; case STALEMATE: xboard_send(XBoard,"1/2-1/2 {Stalemate}"); break; case DRAW_MATERIAL: xboard_send(XBoard,"1/2-1/2 {Draw by insufficient material}"); break; case DRAW_FIFTY: xboard_send(XBoard,"1/2-1/2 {Draw by fifty-move rule}"); break; case DRAW_REPETITION: xboard_send(XBoard,"1/2-1/2 {Draw by repetition}"); break; default: ASSERT(false); break; } }
static void xboard_step() { char string[StringSize]; int move; char move_string[256]; board_t board[1]; xboard_get(XBoard,string,StringSize); 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("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")) { // ignore } else if (match(string,"easy")) { XB->ponder = false; mess(); } else if (match(string,"edit")) { // refuse xboard_send(XBoard,"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")) { if (option_get_bool("Book")) { game_get_board(Game,board); move = book_move(board,false); if (move != MoveNone && move_is_legal(move,board)) { move_to_san(move,board,move_string,256); xboard_send(XBoard,"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")) { my_log("POLYGLOT NEW GAME\n"); option_set("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; } XB->new_hack = true; XB->result = false; XB->depth_limit = false; 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 xboard_send(XBoard,"Error (unknown command): %s",string); } else if (match(string,"ping *")) { // HACK; TODO: answer only after an engine move if (DelayPong) { if (XB->ping >= 0) xboard_send(XBoard,"pong %d",XB->ping); // HACK: get rid of old ping XB->ping = atoi(Star[0]); uci_send_isready(Uci); } else { ASSERT(XB->ping==-1); xboard_send(XBoard,"pong %s",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); xboard_send(XBoard,"feature done=0"); xboard_send(XBoard,"feature analyze=1"); xboard_send(XBoard,"feature colors=0"); xboard_send(XBoard,"feature draw=1"); xboard_send(XBoard,"feature ics=1"); xboard_send(XBoard,"feature myname=\"%s\"",option_get_string("EngineName")); xboard_send(XBoard,"feature name=1"); xboard_send(XBoard,"feature pause=0"); xboard_send(XBoard,"feature ping=1"); xboard_send(XBoard,"feature playother=1"); xboard_send(XBoard,"feature reuse=1"); xboard_send(XBoard,"feature san=0"); xboard_send(XBoard,"feature setboard=1"); xboard_send(XBoard,"feature sigint=0"); xboard_send(XBoard,"feature sigterm=0"); xboard_send(XBoard,"feature time=1"); xboard_send(XBoard,"feature usermove=1"); if (uci_option_exist(Uci,"UCI_Chess960")) { xboard_send(XBoard,"feature variants=\"normal,fischerandom\""); } else { xboard_send(XBoard,"feature variants=\"normal\""); } if (Uci->ready) xboard_send(XBoard,"feature done=1"); // otherwise "feature done=1" will be sent when the engine is ready } else if (match(string,"quit")) { my_log("POLYGLOT *** \"quit\" from XBoard ***\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 xboard_send(XBoard,"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("Book") && option_get_bool("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 xboard_send(XBoard,"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; move_step(move); no_mess(move); } else { xboard_send(XBoard,"Illegal move: %s",Star[0]); } } else if (match(string,"variant *")) { if (my_string_equal(Star[0],"fischerandom")) { option_set("Chess960","true"); } else { option_set("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) { 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); xboard_send(XBoard,"stat01: %.0f %lld %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 { xboard_send(XBoard,"stat01: %.0f %lld %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) { xboard_send(XBoard,"Illegal move: %s",string); } else { xboard_send(XBoard,"Error (unknown command): %s",string); } } }
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("RepeatPV")==true) send_pv(); // to update time and nodes // send the move game_get_board(Game,board); if (move_is_castle(move,board) && option_get_bool("Chess960")) { if (!move_to_san(move,board,string,sizeof(string))) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O } else { if (!move_to_can(move,board,string,sizeof(string))) my_fatal("comp_move(): move_to_can() failed\n"); } move_step(move); //game ended? if(game_status(Game)!= PLAYING){ //handle ics drawing stuff if(XB->ics){ switch (game_status(Game)){ case DRAW_MATERIAL: case DRAW_FIFTY: case DRAW_REPETITION: xboard_send(XBoard,"offer draw"); break; default: break; } } xboard_send(XBoard,"move %s",string); board_update(); no_mess(move); return; } // engine sended a move while in ponder mode? if(State->state==PONDER){ if(board->turn==White) xboard_send(XBoard,"0-1 {polyglot : engine moves while pondering}\n"); else xboard_send(XBoard,"1-0 {polyglot : engine moves while pondering}\n"); } // resign? if (option_get_bool("Resign") && Uci->root_move_nb > 1) { int best = Uci->best_score; if (option_get_bool("ScoreWhite") && colour_is_black(Uci->board->turn)) best = -best; if (best <= -abs(option_get_int("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("ResignMoves")) { my_log("POLYGLOT *** RESIGN ***\n"); //send move and resign //xboard_send(XBoard,"move %s \nresign",string); //just resign xboard_send(XBoard,"resign",string); no_mess(move); return; } } else { if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb); State->resign_nb = 0; } } no_mess(move); xboard_send(XBoard,"move %s",string); }
static void engine_step() { char string[StringSize]; int event; // parse UCI line engine_get(Engine,string,StringSize); //blocking read... event = uci_parse(Uci,string); // react to events if ((event & EVENT_READY) != 0) { #ifdef _WIN32 SetEvent(Engine_ready_ok); #endif if (!Uci->ready) { Uci->ready = true; if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1"); } if (!DelayPong && XB->ping >= 0) { xboard_send(XBoard,"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; // 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){ if(!option_get_bool("InfoStrings")) xboard_send(XBoard,"#%d %+d %.0f " S64_FORMAT " %s ",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,Uci->info_string); else xboard_send(XBoard,"%d %+d %.0f " S64_FORMAT " %s ",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,Uci->info_string); } if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){ my_log("POYGLOT draw offer/resign from engine\n"); if(uci_option_exist(Uci,"UCI_DrawOffers")){ if(event & EVENT_DRAW) xboard_send(XBoard,"offer draw"); else xboard_send(XBoard,"resign"); } } return ; }