Add XBoard protocol drivers
authorH.G. Muller <h.g.muller@hccnet.nl>
Wed, 20 Oct 2010 18:25:57 +0000 (20:25 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Wed, 20 Oct 2010 18:25:57 +0000 (20:25 +0200)
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
book.c
io.c
main.c
proce.c
searchr.c
time.c
utility.c

index 856e931..ddc50f0 100644 (file)
--- 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 (file)
--- 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 (file)
--- 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 (file)
--- 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 (file)
--- 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" );
index a3aba06..5484e16 100644 (file)
--- 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 (file)
--- 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 ) )
     {
index 75b1b9a..91f4876 100644 (file)
--- 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 ) ? "!" : "",