From a443e15a4089569770ff5bf4ed543c2c6199a900 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Wed, 20 Oct 2010 20:25:57 +0200 Subject: [PATCH] Add XBoard protocol drivers So far only those commands needed for playing games from the initial position. Commands like 'memory', 'post', 'nopost', 'analyze' do not work yet. Neither does pondering, as Bonanza's board is not valid when a move comes in during pondering, so the wrong piece type is appended to the move to convert t to CSA format. --- Makefile | 2 +- book.c | 7 ++++- io.c | 7 ++++- main.c | 3 ++ proce.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ searchr.c | 32 +++++++++++++++++++ time.c | 5 ++- utility.c | 14 ++++++++ 8 files changed, 165 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 856e931..ddc50f0 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ OBJS =data.o main.o io.o proce.o utility.o ini.o attack.o book.o makemove.o \ # -DMNJ_LAN enables a client-mode of cluster computing. # -DNO_LOGGING suppresses dumping log files. -OPT =-DNDEBUG -DMINIMUM -DTLP -DCSA_LAN -DMNJ_LAN +OPT =-DNDEBUG -DMINIMUM -DTLP -DCSA_LAN -DMNJ_LAN -DXBOARD help: @echo "try targets as:" diff --git a/book.c b/book.c index e8336e6..f1db145 100644 --- a/book.c +++ b/book.c @@ -138,7 +138,12 @@ book_probe( tree_t * restrict ptree ) /* show results */ if ( ! ( game_status & ( flag_pondering | flag_puzzling ) ) ) { - Out( " move freq\n" ); +#ifdef XBOARD +# define SIGN "#" +#else +# define SIGN +#endif + Out( SIGN " move freq\n" ); OutCsaShogi( "info" ); for ( i = 0; i < moves; i++ ) { diff --git a/io.c b/io.c index 14f841e..a310a17 100644 --- a/io.c +++ b/io.c @@ -223,7 +223,12 @@ show_prompt( void ) else { Out( "Black Suspend> " ); } } else if ( root_turn ) { Out( "White %d> ", record_game.moves+1 ); } - else { Out( "Black %d> ", record_game.moves+1 ); } +#ifdef XBOARD +# define SIGN "#" +#else +# define SIGN +#endif + else { Out( SIGN "Black %d> ", record_game.moves+1 ); } } diff --git a/main.c b/main.c index f84ad15..5615bae 100644 --- a/main.c +++ b/main.c @@ -51,6 +51,9 @@ main() int iret; tree_t * restrict ptree; +#ifdef XBOARD + Out("feature done=0\n"); +#endif #if defined(TLP) ptree = tlp_atree_work; #else diff --git a/proce.c b/proce.c index bb41877..94db5d0 100644 --- a/proce.c +++ b/proce.c @@ -90,6 +90,92 @@ procedure( tree_t * restrict ptree ) return proce_cui( ptree ); } +#ifdef XBOARD +#define IF(X) else if(!strcmp(command, X)) + +int myTime, hisTime, movesPerSession, inc, plyNr; +char xboard_mode; + +static void +SetTimes(void) +{ // set white and black times from own and opponent time. + int moves; + if(movesPerSession <= 0) moves = 35; else { + moves = - plyNr/2; + while(moves <= 0) moves += movesPerSession; + } + time_limit = (myTime-inc-30)/(moves+2) + inc; + time_max_limit = 3*time_limit; + if(time_max_limit > myTime - 30)time_max_limit = myTime - 30; // keep 0.3 sec margin, as Bonanza reads the clock infrequently + time_limit *= 10; // msec + time_max_limit *= 10; +Out("# moves=%d, time=%d inc=%d t=%d, max=%d\n", moves, myTime, inc, time_limit, time_max_limit); +} + +static int +proce_xboard(char *line, const char *command, tree_t * restrict ptree) +{ // [HGM] added to make Bonanza.exe a native WinBoard engine + int value = -100000; + static char forceMode = 0; + sscanf(line + strlen(command) + 1, "%d", &value); +Out("# command = '%s'\n", line); + if(0) ; + IF("protover") { Out("feature variants=\"shogi\" usermove=1 myname=\"Bonanza " BNZ_VER + "\" memory=1 smp=1 debug=1 colors=0 setboard=1 ping=1 done=1\n"); } + IF("new") { forceMode = plyNr = 0; SetTimes(); return 0; } + IF("easy") { strcpy(line, "ponder off"); return 0; } + IF("hard") { strcpy(line, "ponder on"); return 0; } + IF("post") { ; } + IF("nopost") { ; } + IF("time") { sscanf(line+5, "%d", &myTime); } + IF("otim") { sscanf(line+5, "%d", &hisTime); } + IF("force") { forceMode = 1; } + IF("go") { forceMode = 0; SetTimes(); plyNr++; strcpy(line, "move"); return 0; } + IF("memory") { ; } + IF("cores") { sprintf(line, "tlp num %d", value); return 0; } + IF("sd") { sprintf(line, "limit depth %d", value); return 0; } + IF("st") { ; } + IF("quit") { return 0; } + IF("analyze") { ; } + IF("exit") { ; } + IF("variant") { /* ignore, since it must be Shogi */; } + IF("setboard") { ; } + IF("option") { ; } + IF("level") { int min, sec; float fsec=0.; + if(sscanf(line+6, "%d %d:%d %f", &movesPerSession, &min, &sec, &fsec) != 4) + sscanf(line+6, "%d %d %f", &movesPerSession, &min, &fsec); + min = 60*min + sec; myTime = hisTime = 100*min; inc = 100 * fsec; + } + IF("usermove") { char fromX=line[9], fromY=line[10], toX=line[11], toY=line[12], promo=line[13]; + int from; +{int i,j;for(i=0;i<81;i+=9){printf("# ");for(j=0;j<9;j++)printf(" %3d", BOARD[i+j]);printf("\n");}} + if(forceMode) strcpy(line, "move "), line += 5; else plyNr++, SetTimes(); + if(fromY == '@') { // drop + if(fromX >= 'a') fromX += 'A' - 'a'; + switch(fromX) { // encode piece + case 'P': fromX = pawn; break; + case 'L': fromX = lance; break; + case 'N': fromX = knight; break; + case 'S': fromX = silver; break; + case 'G': fromX = gold; break; + case 'B': fromX = bishop; break; + case 'R': fromX = rook; break; + } + sprintf(line, "00%c%c%s", 'a'+'9'-toX, '1'+'9'-toY, astr_table_piece[(int)fromX]); + } else { + from = ('9' - fromY)*9 + (fromX - 'a'); +Out("# from=%d\n",from); + sprintf(line, "%c%c%c%c%s", 'a'+'9'-fromX, '1'+'9'-fromY, 'a'+'9'-toX, '1'+'9'-toY, + astr_table_piece[abs(BOARD[from]) + (promo == '+' ? promote : 0)]); + } + plyNr++; return 0; + } + IF("undo") { ; } + IF("remove") { ; } + IF("ping") { Out("pong %d\n", value); } + return 1; +} +#endif static int proce_cui( tree_t * restrict ptree ) @@ -100,6 +186,16 @@ proce_cui( tree_t * restrict ptree ) token = strtok_r( str_cmdline, str_delimiters, &last ); if ( token == NULL || *token == '#' ) { return 1; } +#ifdef XBOARD + { + if(xboard_mode) { + if( proce_xboard(str_cmdline, token, ptree) ) return 1; // command already processed + Out("# translated command '%s'\n", str_cmdline); // command translated for processing by Bonanza + token = strtok_r( str_cmdline, str_delimiters, &last ); // redo parsing + } else + if ( ! strcmp( token, "xboard" ) ) { xboard_mode = 1; game_status |= flag_noprompt; return 1; } + } +#endif if ( is_move( token ) ) { return cmd_usrmove( ptree, token, &last ); } if ( ! strcmp( token, "s" ) ) { return cmd_move_now(); } if ( ! strcmp( token, "beep" ) ) { return cmd_beep( &last); } @@ -402,6 +498,9 @@ cmd_usrmove( tree_t * restrict ptree, const char *str_move, char **lasts ) game_status &= ~flag_pondering; game_status |= flag_thinking; n_nobook_move += 1; +#ifdef XBOARD + if(!xboard_mode) +#endif set_search_limit_time( root_turn ); OutCsaShogi( "info ponder end\n" ); diff --git a/searchr.c b/searchr.c index a3aba06..5484e16 100644 --- a/searchr.c +++ b/searchr.c @@ -24,6 +24,10 @@ static int next_root_move( tree_t * restrict ptree ); static int next_root_move( tree_t * restrict ptree, int turn ); #endif +#ifdef XBOARD +extern char xboard_mode; +#endif + int searchr( tree_t * restrict ptree, int alpha, int beta, int turn, int depth ) { @@ -242,6 +246,9 @@ out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time ) if ( ptree->pv[0].length ) { int i = find_root_move( ptree->pv[0].a[1] ); +#ifdef XBOARD + if(xboard_mode) Out("%2d %6d %6d %8d ", iteration_depth, value, time/10, 1); else +#endif if ( root_move_list[i].status & flag_first ) { Out( " %2d %6s %7.2f ", iteration_depth, str, dvalue ); @@ -252,6 +259,17 @@ out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time ) for ( ply = 1; ply <= ptree->pv[0].length; ply++ ) { +#ifdef XBOARD + if(xboard_mode && is_out) { // print PV move in WB format + int move = ptree->pv[0].a[ply], from = I2From(move), to = I2To(move); + char inPromoZone = tt > 0 ? from >= 6*9 || to >= 6*9 : to < 3*9|| from < 3*9; + if(from >= nsquare) + Out(" %c@%c%c", "PLNSGBR"[From2Drop(from)-1], 'a'+to%9, '9'-to/9); + else + Out(" %c%c%c%c%s", 'a'+from%9, '9'-from/9, 'a'+to%9, '9'-to/9, + inPromoZone ? I2IsPromote(move) ? "+" : "=" : ""); + } else +#endif if ( is_out ) { if ( ply > 1 && ! ( (ply-1) % 4 ) ) @@ -287,6 +305,17 @@ out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time ) for ( i = 1; i < ply; i++ ) if ( ptree->pv[0].a[i] == ptree->pv[0].a[ply] ) { goto rep_esc; } +#ifdef XBOARD + if(xboard_mode && is_out) { // print PV move in WB format + int move = ptree->pv[0].a[ply], from = I2From(move), to = I2To(move); + char inPromoZone = tt > 0 ? from >= 6*9 || to >= 6*9 : to < 3*9|| from < 3*9; + if(from >= nsquare) + Out(" %c@%c%c", "PLNSGBR"[From2Drop(from)-1], 'a'+to%9, '9'-to/9); + else + Out(" %c%c%c%c%s", 'a'+from%9, '9'-from/9, 'a'+to%9, '9'-to/9, + inPromoZone ? I2IsPromote(move) ? "+" : "=" : ""); + } else +#endif if ( is_out ) { if ( ply > 1 && ! ( (ply-1) % 4 ) ) @@ -401,6 +430,9 @@ next_root_move( tree_t * restrict ptree, int turn ) ptree->current_move[1] = root_move_list[i].move; #if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) ) +#ifdef XBOARD + if(!xboard_mode) +#endif if ( iteration_depth > 5 ) { const char *str_move; diff --git a/time.c b/time.c index 203c3bf..56a0ded 100644 --- a/time.c +++ b/time.c @@ -39,7 +39,10 @@ set_search_limit_time( int turn ) */ { unsigned int u0, u1; - +#ifdef XBOARD + extern char xboard_mode; + if(xboard_mode) return; +#endif /* no time-control */ if ( sec_limit_up == UINT_MAX || ( game_status & flag_pondering ) ) { diff --git a/utility.c b/utility.c index 75b1b9a..91f4876 100644 --- a/utility.c +++ b/utility.c @@ -591,6 +591,20 @@ com_turn_start( tree_t * restrict ptree, int flag ) } OutCsaShogi( "info tt %03u:%02u\n", sec_total / 60U, sec_total % 60U ); +#ifdef XBOARD + { extern char xboard_mode; + if(xboard_mode) { // print move in WB format and defuse next line + if(str_move[0] < '0' || str_move[0] > '9') Out("\n%s\n# ", str_move); // only resign? + else if(str_move[0] == '0') + Out("\nmove %c@%c%c\n# ", // drop + "PLNSGBR"[(move>>7&127)-nsquare], + '9'+'a'-str_move[2], '1'+'9'-str_move[3]); + else Out("\n#t=%d tm=%d\nmove %c%c%c%c%s\n# ", time_limit, time_max_limit, + '9'+'a'-str_move[0], '1'+'9'-str_move[1], + '9'+'a'-str_move[2], '1'+'9'-str_move[3], (move & FLAG_PROMO ? "+" : "=")); + } + } +#endif Out( "%s '(%d%s) %03u:%02u/%03u:%02u elapsed: b%u, w%u\n", str_move, value, ( last_pv.type == pv_fail_high ) ? "!" : "", -- 1.7.0.4