From 2945d63eec617a4411287ceda774a1e0186fc350 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 | 3 +- book.c | 7 ++++- io.c | 7 ++++- main.c | 3 ++ proce.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ searchr.c | 32 +++++++++++++++++++ time.c | 5 ++- utility.c | 14 ++++++++ 8 files changed, 166 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f5189ed..9eed265 100644 --- a/Makefile +++ b/Makefile @@ -19,11 +19,12 @@ 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 searches. # -DNO_LOGGING suppresses dumping log files. # -DUSI enables USI mode (not implemented). +# -DXBOARD enables WinBoard/XBoard mode (implemented!). # -DINANIWA_SHIFT enables an Inaniwa strategy detection. # -DDFPN build the DFPN worker of mate-problems server. # -DDFPN_CLIENT enables the client-mode of mate-problem server. -OPT =-DNDEBUG -DMINIMUM -DHAVE_SSE4 -msse4.1 -DDFPN -DTLP -DDFPN_CLIENT -DINANIWA_SHIFT -DMNJ_LAN -DCSA_LAN +OPT =-DNDEBUG -DMINIMUM -DHAVE_SSE4 -msse4.1 -DDFPN -DTLP -DDFPN_CLIENT -DINANIWA_SHIFT -DMNJ_LAN -DCSA_LAN -DXBOARD help: @echo "try targets as:" diff --git a/book.c b/book.c index 9a732b8..55e6d37 100644 --- a/book.c +++ b/book.c @@ -140,7 +140,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 c0595f1..75f12bb 100644 --- a/io.c +++ b/io.c @@ -233,7 +233,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 1591760..89c0316 100644 --- a/main.c +++ b/main.c @@ -18,6 +18,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 2578634..6538fb9 100644 --- a/proce.c +++ b/proce.c @@ -122,6 +122,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 CONV proce_cui( tree_t * restrict ptree ) { @@ -131,6 +217,16 @@ static int CONV 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); } @@ -699,6 +795,9 @@ cmd_usrmove( tree_t * restrict ptree, const char *str_move, char **lasts ) game_status &= ~flag_pondering; game_status |= flag_thinking; +#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 3afd2aa..216967d 100644 --- a/searchr.c +++ b/searchr.c @@ -24,6 +24,10 @@ static int CONV next_root_move( tree_t * restrict ptree ); static int CONV next_root_move( tree_t * restrict ptree, int turn ); #endif +#ifdef XBOARD +extern char xboard_mode; +#endif + static int CONV search_wrapper( tree_t * restrict ptree, int alpha, int beta, int turn, int depth, int ply, unsigned int state_node ) @@ -351,6 +355,9 @@ out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time ) if ( ptree->pv[0].length ) { +#ifdef XBOARD + if(xboard_mode) Out("%2d %6d %6d %8d ", iteration_depth, value, time/10, 1); else +#endif if ( root_move_list[root_index].status & flag_first ) { Out( " %2d %6s %7.2f ", iteration_depth, str, dvalue ); @@ -361,6 +368,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) % 5 ) ) @@ -407,6 +425,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) % 5 ) ) @@ -546,6 +575,9 @@ next_root_move( tree_t * restrict ptree, int turn ) root_index = i; #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 fbeb04a..8e2f7c0 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 198aa90..2d6d8ec 100644 --- a/utility.c +++ b/utility.c @@ -586,6 +586,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