gnugo-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnugo-devel] sgf output, revised


From: Paul Pogonyshev
Subject: [gnugo-devel] sgf output, revised
Date: Mon, 2 Sep 2002 02:58:30 +0300

this is version 2, replaces the first one

changes:
  - sgf handling is disconnected from engine again (renamed and moved
    sgfAddDebugInfo -> sgffile_debuginfo, outputsgf -> sgffile_output)
  - default option is: no debug output
  - previously commented code is now enclosed in #if 0 ... #endif
  - write "forced" as comment when this command is used (let it be ;)
  - fixed issue with "handicap 0" command (white started playing)

Index: sgf/sgftree.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/sgf/sgftree.h,v
retrieving revision 1.8
diff -u -r1.8 sgftree.h
--- sgf/sgftree.h       4 Mar 2002 06:49:09 -0000       1.8
+++ sgf/sgftree.h       1 Sep 2002 23:52:54 -0000
@@ -88,10 +88,13 @@
 SGFNode *sgfAddStone(SGFNode *node, int color, int movex, int movey);
 SGFNode *sgfAddPlay(SGFNode *node, int who, int movex, int movey);
 SGFNode *sgfAddPlayLast(SGFNode *node, int who, int movex, int movey);
+
 int sgfPrintCharProperty(FILE *file, SGFNode *node, const char *name);
 int sgfPrintCommentProperty(FILE *file, SGFNode *node, const char *name);
 void sgfWriteResult(SGFNode *node, float score, int overwrite);
 
+SGFNode *sgfLabel(SGFNode *node, char *label, int i, int j);
+SGFNode *sgfLabelInt(SGFNode *node, int num, int i, int j);
 SGFNode *sgfCircle(SGFNode *node, int i, int j);
 SGFNode *sgfSquare(SGFNode *node, int i, int j);
 SGFNode *sgfTriangle(SGFNode *node, int i, int j);
@@ -113,7 +116,7 @@
 
 /* Write SGF tree to a file. */
 void sgf_write_header(SGFNode *root, int overwrite, int seed, float komi,
-                     int level);
+                     int level, int rules);
 int writesgf(SGFNode *root, const char *filename);
 
 
Index: sgf/sgfnode.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/sgf/sgfnode.c,v
retrieving revision 1.14
diff -u -r1.14 sgfnode.c
--- sgf/sgfnode.c       11 Apr 2002 19:52:06 -0000      1.14
+++ sgf/sgfnode.c       1 Sep 2002 23:52:59 -0000
@@ -418,23 +418,21 @@
 {
   char move[3];
   SGFNode *new;
-
+  
   /* a pass move? */
   if (movex == -1 && movey == -1)
     move[0] = 0;
   else
     sprintf(move, "%c%c", movey + 'a', movex + 'a');
 
-  if (node->child) {
-    node = sgfStartVariantFirst(node->child);
-    sgfAddProperty(node, (who == BLACK) ? "B" : "W", move);
-
-    return node;
+  if (node->child)
+    new = sgfStartVariantFirst(node->child);
+  else {
+    new = sgfNewNode();
+    node->child = new;
+    new->parent = node;
   }
-
-  new = sgfNewNode();
-  node->child = new;
-  new->parent = node;
+  
   sgfAddProperty(new, (who == BLACK) ? "B" : "W", move);
 
   return new;
@@ -556,6 +554,39 @@
 
 
 /*
+ * Place a label on the board at position (i, j).
+ */
+
+SGFNode *
+sgfLabel(SGFNode *node, char *label, int i, int j)
+{
+  /* allows 12 chars labels - more than enough */
+  char text[16];
+
+  gg_snprintf(text, 16, "%c%c:%s", j+'a', i+'a', label);
+  sgfAddProperty(node, "LB", text);
+
+  return node;
+}
+
+
+/*
+ * Place a numeric label on the board at position (i, j).
+ */
+
+SGFNode *
+sgfLabelInt(SGFNode *node, int num, int i, int j)
+{
+  char text[16];
+
+  gg_snprintf(text, 16, "%c%c:%d", j+'a', i+'a', num);
+  sgfAddProperty(node, "LB", text);
+
+  return node;
+}
+
+
+/*
  * Place a circle mark on the board at position (i, j).
  */
 
@@ -1264,6 +1295,26 @@
 }
 
 
+static void
+restore_property(SGFProperty *prop)
+{
+  if(prop) {
+    restore_property(prop->next);
+    prop->name&=~0x20;
+  }
+}
+
+
+static void
+restore_node(SGFNode *node)
+{
+  if (node) {
+    restore_property(node->props);
+    restore_node(node->child);
+    restore_node(node->next);
+  }
+}
+
 
 static void
 unparse_node(FILE *file, SGFNode *node)
@@ -1335,7 +1386,7 @@
 }
 
 void
-sgf_write_header(SGFNode *root, int overwrite, int seed, float komi, int level)
+sgf_write_header(SGFNode *root, int overwrite, int seed, float komi, int 
level, int rules)
 {
   time_t curtime = time(NULL);
   struct tm *loctime = localtime(&curtime);
@@ -1353,7 +1404,7 @@
   if (overwrite || !sgfGetIntProperty(root, "AP", &dummy))
     sgfOverwriteProperty(root, "AP", PACKAGE":"VERSION);
   if (overwrite || !sgfGetIntProperty(root, "RU", &dummy))
-    sgfOverwriteProperty(root, "RU", "Japanese");
+    sgfOverwriteProperty(root, "RU", rules ? "Chinese" : "Japanese");
   sgfOverwriteProperty(root, "FF", "4");
   sgfOverwritePropertyFloat(root, "KM", komi);
 }
@@ -1379,6 +1430,9 @@
 
   unparse_game(outfile, root, 1);
   fclose(outfile);
+  /* remove "printed" marks so that the tree can be written multiple
+     times */
+  restore_node(root);
   return 1;
 }
 
Index: engine/sgffile.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/sgffile.c,v
retrieving revision 1.16
diff -u -r1.16 sgffile.c
--- engine/sgffile.c    11 Apr 2002 19:52:05 -0000      1.16
+++ engine/sgffile.c    1 Sep 2002 23:53:00 -0000
@@ -51,6 +51,7 @@
 
 /*
  * Handling of the SGF file itself (open, close, etc).
+ * FIXME: remove this part once it isn't used anymore
  */
 
 
@@ -103,8 +104,12 @@
 {
   if (!sgfout)
     return 0;
-  
-  fprintf(sgfout, ")\n");
+
+  /* enable if we ever return to creating of sgf files on the fly */
+#if 0
+  fprintf(sgfout, ")\n"); 
+#endif
+
   /* Don't close sgfout if it happens to be stdout. */
   if (sgfout != stdout)
     fclose(sgfout);
@@ -286,6 +291,57 @@
        break;
     }
   }
+}
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * Add debug information to a node if user requested it from command
+ * line.
+ */
+
+void
+sgffile_debuginfo(SGFNode *node, int value)
+{
+  int m, n;
+  char comment[24];
+
+  if (outfilename[0]) {
+    for (m = 0; m < board_size; ++m)
+      for (n = 0; n < board_size; ++n) {
+        if (BOARD(m,n) && (output_flags & OUTPUT_MARKDRAGONS))
+          switch (dragon[POS(m, n)].crude_status) {
+            case DEAD:
+             sgfLabel(node, "X", m, n);
+             break;
+           case CRITICAL:
+             sgfLabel(node, "!", m, n);
+             break;
+          }
+       if (potential_moves[m][n] > 0.0 && (output_flags & OUTPUT_MOVEVALUES)) {
+         if (potential_moves[m][n] < 1.0)
+           sgfLabel(node, "<1", m, n);
+         else
+           sgfLabelInt(node, (int) potential_moves[m][n], m, n);
+       }
+      }
+    if (value) {
+      sprintf(comment, "Value of move: %d", value);
+      sgfAddComment(node, comment);
+    }
+  }
+}
+
+
+/*
+ * Write sgf tree to output file specified with -o option
+ */
+
+void
+sgffile_output(SGFNode *root)
+{
+  if (outfilename[0])
+    writesgf(root, outfilename);
 }
 
 
Index: engine/printutils.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/printutils.c,v
retrieving revision 1.23
diff -u -r1.23 printutils.c
--- engine/printutils.c 21 May 2002 16:40:53 -0000      1.23
+++ engine/printutils.c 1 Sep 2002 23:53:01 -0000
@@ -251,7 +251,7 @@
 
 #if 0
   if (sgf_root) {
-    sgf_write_header(sgf_root, 1, random_seed, komi, level);
+    sgf_write_header(sgf_root, 1, random_seed, komi, level, chinese_rules);
     writesgf(sgf_root, "abortgo.sgf");
   }
 #endif
Index: engine/gnugo.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/gnugo.h,v
retrieving revision 1.61
diff -u -r1.61 gnugo.h
--- engine/gnugo.h      28 Aug 2002 06:27:26 -0000      1.61
+++ engine/gnugo.h      1 Sep 2002 23:53:02 -0000
@@ -165,7 +165,8 @@
 
   int       computer_player;   /* BLACK, WHITE, or EMPTY (used as BOTH) */
 
-  char      outfilename[128];  /* Trickle file */
+  /* FIXME: remove these fields once all sgf output goes through trees */
+  char     outfilename[128];
   FILE      *outfile;
 } Gameinfo;
 
@@ -196,6 +197,14 @@
 extern int printboard;         /* print board each move */
 extern int showstatistics;     /* print statistics */
 extern int profile_patterns;   /* print statistics of pattern usage */
+extern char outfilename[128];  /* output file (-o option) */
+extern int output_flags;       /* amount of output to outfile */
+
+/* output flag bits */
+#define OUTPUT_MARKDRAGONS         0x0001  /* mark dead and critical dragons */
+#define OUTPUT_MOVEVALUES          0x0002  /* output values of all moves in 
list */
+
+#define OUTPUT_DEFAULT             0 /* no debug output  by default */
 
 /* debug flag bits */
 /* NOTE : can specify -d0x... */
@@ -468,6 +477,9 @@
 void report_pattern_profiling(void);
 
 /* sgffile.c */
+void sgffile_debuginfo(SGFNode *node, int value);
+void sgffile_output(SGFNode *root);
+
 void sgffile_move_made(int i, int j, int color, int value);
 void sgffile_put_stone(int i, int j, int color);
 
Index: engine/globals.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/globals.c,v
retrieving revision 1.26
diff -u -r1.26 globals.c
--- engine/globals.c    28 Aug 2002 06:27:26 -0000      1.26
+++ engine/globals.c    1 Sep 2002 23:53:03 -0000
@@ -118,6 +118,8 @@
 int urgent           = 0;  /* urgent move on board */
 int debug            = 0;  /* controls debug output */
 int verbose          = 0;  /* trace level */
+char outfilename[128] = "";  /* output file (-o option) */
+int output_flags     = OUTPUT_DEFAULT; /* amount of output to outfile */
 
 int disable_threat_computation = 0;
 int disable_endgame_patterns   = 0;
Index: engine/dragon.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v
retrieving revision 1.70
diff -u -r1.70 dragon.c
--- engine/dragon.c     29 Aug 2002 11:18:55 -0000      1.70
+++ engine/dragon.c     1 Sep 2002 23:53:08 -0000
@@ -336,7 +336,10 @@
     if (ON_BOARD(str)) {
       if (dragon[str].origin == str && board[str]) {
        dragon[str].crude_status = compute_crude_status(str);
+       /* FIXME: delete this once all sgf output goes through trees */
+#if 0
        sgffile_dragon_status(I(str), J(str), dragon[str].crude_status);
+#endif
       }
     }
   time_report(2, "  compute_crude_status", NO_MOVE, 1.0);
Index: interface/play_ascii.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/play_ascii.c,v
retrieving revision 1.21
diff -u -r1.21 play_ascii.c
--- interface/play_ascii.c      26 Aug 2002 13:40:26 -0000      1.21
+++ interface/play_ascii.c      1 Sep 2002 23:53:12 -0000
@@ -63,7 +63,7 @@
 static int ascii2pos(char *line, int *i, int *j);
 
 /* If sgf game info is written can't reset parameters like handicap, etc. */
-static int sgf_initialized = 0;
+static int sgf_initialized;
 
 /*
  * Create letterbar for the top and bottom of the ASCII board.
@@ -114,14 +114,6 @@
   
   memset(hspots, '.', sizeof(hspots));
 
-  /* small sizes are easier to hardwire... */
-  if (boardsize == 2 || boardsize == 4)
-    return;
-  if (boardsize == 3) {
-    /* just the middle one */
-    hspots[boardsize/2][boardsize/2] = '+';
-    return;
-  }
   if (boardsize == 5) {
     /* place the outer 4 */
     hspots[1][1] = '+';
@@ -430,11 +422,10 @@
     return;
   sgf_initialized = 1;
 
-  sgffile_write_gameinfo(ginfo, "ascii");
+  sgf_write_header(root, 1, random_seed, komi, level, chinese_rules);
+  sgfOverwritePropertyInt(root, "HA", ginfo->handicap);
   if (ginfo->handicap > 0)
     gnugo_recordboard(root);
-  else
-    ginfo->to_move = BLACK;
 }
 
 
@@ -468,10 +459,10 @@
     *passes = 0;
 
   gnugo_play_move(i, j, gameinfo->to_move);
+  sgffile_debuginfo(curnode, move_val);
   curnode = sgfAddPlay(curnode, gameinfo->to_move, i, j);
+  sgffile_output(sgftree.root);
 
-  sgffile_move_made(i, j, gameinfo->to_move, move_val);
-  
   gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
 }
 
@@ -497,11 +488,11 @@
 
   *passes = 0;
   TRACE("\nyour move: %m\n\n", i, j);
-  gnugo_play_move(i, j, gameinfo->to_move);
-  /* FIXME: This call to init_sgf should not be here. */
   init_sgf(gameinfo, sgftree.root);
-  sgffile_move_made(i, j, gameinfo->to_move, 0);
+  gnugo_play_move(i, j, gameinfo->to_move);
+  sgffile_debuginfo(curnode, 0);
   curnode = sgfAddPlay(curnode, gameinfo->to_move, i, j);
+  sgffile_output(sgftree.root);
 
   last_move_i = i;
   last_move_j = j;
@@ -513,6 +504,7 @@
   if (force) {
     gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
     gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
+    sgfAddComment(curnode, "forced");
     return;
   }
   gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
@@ -528,14 +520,16 @@
 do_pass(Gameinfo *gameinfo, int *passes, int force)
 {
   (*passes)++;
-  gnugo_play_move(-1, -1, gameinfo->to_move);
   init_sgf(gameinfo, sgftree.root);
-  sgffile_move_made(-1, -1, gameinfo->to_move, 0);
+  gnugo_play_move(-1, -1, gameinfo->to_move);
+  sgffile_debuginfo(curnode, 0);
   curnode = sgfAddPlay(curnode, gameinfo->to_move, -1, -1);
+  sgffile_output(sgftree.root);
 
   gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
   if (force) {
     gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
+    sgfAddComment(curnode, "forced");
     return;
   }
   computer_move(gameinfo, passes);
@@ -550,7 +544,7 @@
 play_ascii(SGFTree *tree, Gameinfo *gameinfo, char *filename, char *until)
 {
   int m, num;
-  int sz = 0;
+  int sz;
   float fnum;
   int passes = 0;  /* two passes and its over */
   int tmp;
@@ -575,25 +569,20 @@
     
     if (filename) {
       gameinfo_load_sgfheader(gameinfo, sgftree.root);
-      sgffile_write_gameinfo(gameinfo, "ascii");
       gameinfo->to_move = gameinfo_play_sgftree(gameinfo, sgftree.root, until);
-      sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
       sgf_initialized = 1;
       curnode = sgftreeNodeCheck(&sgftree, 0);
     }
     else {
-      if (sz)
-       sgfOverwritePropertyInt(sgftree.root, "SZ", sz);
       if (sgfGetIntProperty(sgftree.root, "SZ", &sz)) 
        gnugo_clear_board(sz);
       if (gameinfo->handicap == 0)
        gameinfo->to_move = BLACK;
       else {
        gameinfo->handicap = gnugo_placehand(gameinfo->handicap);
-       sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
        gameinfo->to_move = WHITE;
       }
-      
+      sgf_initialized = 0;
       curnode = sgftree.root;
     }
     
@@ -648,10 +637,6 @@
          gameinfo_print(gameinfo);
          break;
        case SETBOARDSIZE:
-         if (movenum > 0) {
-           printf("Boardsize can be modified on move 1 only!\n");
-           break;
-         }
          if (sgf_initialized) {
            printf("Boardsize cannot be changed after record is started!\n");
            break;
@@ -674,10 +659,6 @@
          sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
          break;
        case SETHANDICAP:
-         if (movenum > 0) {
-           printf("Handicap can be modified on move 1 only!\n");
-           break;
-         }
          if (sgf_initialized) {
            printf("Handicap cannot be changed after game is started!\n");
            break;
@@ -696,15 +677,10 @@
          /* Place stones on board but don't record sgf 
           * in case we change more info. */
          gameinfo->handicap = gnugo_placehand(num);
-         sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
          printf("\nSet handicap to %d\n", gameinfo->handicap);
-         gameinfo->to_move = WHITE;
+          gameinfo->to_move = (gameinfo->handicap ? WHITE : BLACK);
          break;
        case SETKOMI:
-         if (movenum > 0) {
-           printf("Komi can be modified on move 1 only!\n");
-           break;
-         }
          if (sgf_initialized) {
            printf("Komi cannot be modified after game record is started!\n");
            break;
@@ -816,7 +792,7 @@
        case UNDO:
        case CMD_BACK:
          if (gnugo_undo_move(1)) {
-           sgffile_write_comment("undo");
+           sgfAddComment(curnode, "undone");
            curnode = curnode->parent;
            gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
          }
@@ -895,9 +871,9 @@
          if (tmpstring) {
            /* discard newline */
            tmpstring[strlen(tmpstring)-1] = 0;
-           sgf_write_header(sgftree.root, 1, random_seed, komi, level);
+           /* make sure we are saving proper handicap */
+           init_sgf(gameinfo, sgftree.root);
            writesgf(sgftree.root, tmpstring);
-           sgf_initialized = 0;
            printf("You may resume the game");
            printf(" with -l %s --mode ascii\n", tmpstring);
            printf("or load %s\n", tmpstring);
@@ -915,9 +891,10 @@
              fprintf(stderr, "Cannot open or parse '%s'\n", tmpstring);
              break;
            }
-           sgf_initialized = 0;
-           gameinfo_play_sgftree(gameinfo, sgftree.root, NULL);
-           sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
+           /* to avoid changing handicap etc. */
+           sgf_initialized = 1;
+           gameinfo_load_sgfheader(gameinfo, sgftree.root);
+            gameinfo_play_sgftree(gameinfo, sgftree.root, NULL);
            curnode = sgftreeNodeCheck(&sgftree, 0);
          }
          else
@@ -962,9 +939,8 @@
        if (tmpstring) {
          /* discard newline */
          tmpstring[strlen(tmpstring)-1] = 0;
-         sgf_write_header(sgftree.root, 1, random_seed, komi, level);
+         init_sgf(gameinfo,sgftree.root);
          writesgf(sgftree.root, tmpstring);
-           sgf_initialized = 0;
        }
        else
          printf("Please specify filename\n");
@@ -988,7 +964,6 @@
     }
     passes = 0;
     showdead = 0;
-    sgf_initialized = 0;
     /* Play a different game next time. */
     update_random_seed();
   }
Index: interface/main.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/main.c,v
retrieving revision 1.44
diff -u -r1.44 main.c
--- interface/main.c    28 Aug 2002 06:27:26 -0000      1.44
+++ interface/main.c    1 Sep 2002 23:53:15 -0000
@@ -177,6 +177,7 @@
   {"infile",         required_argument, 0, 'l'},
   {"until",          required_argument, 0, 'L'},
   {"outfile",        required_argument, 0, 'o'},
+  {"output-flags",   optional_argument, 0, 'O'},
   {"boardsize",      required_argument, 0, OPT_BOARDSIZE},
   {"color",          required_argument, 0, OPT_COLOR},
   {"handicap",       required_argument, 0, OPT_HANDICAPSTONES},
@@ -274,6 +275,7 @@
   char *untilstring = NULL;
   char *scoringmode = NULL;
   char *outfile = NULL;
+  char *outflags = NULL;
   char *gtpfile = NULL;
   
   char *printsgffile = NULL;
@@ -348,7 +350,7 @@
   
   /* Now weed through all of the command line options. */
   while ((i = gg_getopt_long(argc, argv, 
-                            "-ab:B:d:D:EF:gh::H:K:l:L:M:m:o:p:r:fsStTvw",
+                            "-ab:B:d:D:EF:gh::H:K:l:L:M:m:o:O::p:r:fsStTvw",
                             long_options, NULL)) != EOF)
     {
       switch (i) {
@@ -382,7 +384,28 @@
        
       case 'o':
        outfile = gg_optarg;
+       strcpy(outfilename, gg_optarg);
+
+        /* FIXME: remove this line once all sgf output goes through trees */
        strcpy(gameinfo.outfilename, gg_optarg);
+
+       break;
+
+      case 'O':
+       outflags = gg_optarg;
+       output_flags = 0;
+       if (outflags)
+         while (*outflags){
+           switch (*outflags) {
+             case 'd':
+               output_flags |= OUTPUT_MARKDRAGONS;
+               break;
+             case 'v':
+               output_flags |= OUTPUT_MOVEVALUES;
+               break;
+           }
+           outflags++;
+         }
        break;
        
       case OPT_QUIET:
@@ -1339,6 +1362,10 @@
    -b, --benchmark num           benchmarking mode - can be used with -l\n\
    -S, --statistics              print statistics (for debugging purposes)\n\n\
    -t, --trace                   verbose tracing\n\
+   -O, --output-flags <flags>    optional output (use with -o)\n\
+                    d: mark dead and critical dragons\n\
+                    v: show values of considered moves\n\
+                    specify either no flags (default), 'd', 'v' or 'dv'\n\
    --showtime                    print timing diagnostic\n\
    --replay <color>              replay game. Use with -o.\n\
    --showscore                   print estimated score\n\





reply via email to

[Prev in Thread] Current Thread [Next in Thread]