gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] sgf output - first edition


From: Paul Pogonyshev
Subject: [gnugo-devel] sgf output - first edition
Date: Sun, 1 Sep 2002 19:07:38 +0300

this patch does the following:
  - new option --output-flags <flags> (default: dv, change if
    necessary)
  - output using sgf trees with -o option, works only with play_ascii
    for now
  - lots of cleaning and minor bugfixes in play ascii

PLEASE CHECK:
  - if you are satisfied with marking dead and critical dragons (see
    sgfAddDebugInfo in sgfnode.c and output files)
  - default setting: output all debug info available - is it ok?
  - it outputs all debug information when using "save" from
    play_ascii, maybe should not
  - doesn't work good if file contains variations (e.g. undo is used).
    should it be fixed? (it works, but some debug information looks
    inconsistent)
  - if this patch conflicts with ascii_handicap_3_7.1

testing and revising are welcome since there's quite a lot of changes.

if there are no objections, i'll rewrite gmp.c and sgfdecide.c using
new output format as well.



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 15:50:04 -0000
@@ -88,10 +88,15 @@
 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);
+
+SGFNode *sgfAddDebugInfo(SGFNode *node, int value);
+
 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);
@@ -115,6 +120,7 @@
 void sgf_write_header(SGFNode *root, int overwrite, int seed, float komi,
                      int level);
 int writesgf(SGFNode *root, const char *filename);
+int outputsgf(SGFNode *root);
 
 
 /* ---------------------------------------------------------------- */
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 15:50:06 -0000
@@ -43,6 +43,9 @@
 # endif
 #endif
 
+#include "gnugo.h"
+#include "liberty.h"
+
 #include "sgftree.h"
 #include "gg_utils.h"
 
@@ -418,23 +421,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;
@@ -464,6 +465,43 @@
   return new;
 }
 
+/*
+ * Add debug information to a node if user requested it from command
+ * line.
+ */
+
+SGFNode *
+sgfAddDebugInfo(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);
+    }
+  }
+  return node;
+}
 
 SGFNode *
 sgfCreateHeaderNode(int boardsize, float komi)
@@ -556,6 +594,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 +1335,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)
@@ -1353,7 +1444,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", chinese_rules ? "Chinese" : "Japanese");
   sgfOverwriteProperty(root, "FF", "4");
   sgfOverwritePropertyFloat(root, "KM", komi);
 }
@@ -1379,6 +1470,22 @@
 
   unparse_game(outfile, root, 1);
   fclose(outfile);
+  /* remove "printed" marks so that the tree can be written multiple
+     times */
+  restore_node(root);
+  return 1;
+}
+
+
+/*
+ * Writes to output file specified with -o option
+ */
+
+int
+outputsgf(SGFNode *root)
+{
+  if (outfilename[0])
+    return writesgf(root, outfilename);
   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 15:50:07 -0000
@@ -104,7 +104,9 @@
   if (!sgfout)
     return 0;
   
-  fprintf(sgfout, ")\n");
+  /* FIXME: uncomment this if we ever return to sgffile.c
+     commented to prevent it from overwriting file outted with outputsgf */
+  /* fprintf(sgfout, ")\n"); */
   /* Don't close sgfout if it happens to be stdout. */
   if (sgfout != stdout)
     fclose(sgfout);
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 15:50:08 -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 sgffile.c becomes redundant */
+  char     outfilename[128];
   FILE      *outfile;
 } Gameinfo;
 
@@ -196,6 +197,15 @@
 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 */
+
+/* FIXME: change default flags if needed */
+#define OUTPUT_DEFAULT             OUTPUT_MARKDRAGONS | OUTPUT_MOVEVALUES
 
 /* debug flag bits */
 /* NOTE : can specify -d0x... */
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 15:50:09 -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 15:50:13 -0000
@@ -336,7 +336,8 @@
     if (ON_BOARD(str)) {
       if (dragon[str].origin == str && board[str]) {
        dragon[str].crude_status = compute_crude_status(str);
-       sgffile_dragon_status(I(str), J(str), dragon[str].crude_status);
+       /* FIXME: delete this once we get rid of sgffile.c */
+       /*sgffile_dragon_status(I(str), J(str), dragon[str].crude_status);*/
       }
     }
   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 15:50:16 -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(sgftree.root, 1, random_seed, komi, level);
+  sgfOverwritePropertyInt(sgftree.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);
+  sgfAddDebugInfo(curnode, move_val);
   curnode = sgfAddPlay(curnode, gameinfo->to_move, i, j);
+  outputsgf(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);
+  sgfAddDebugInfo(curnode, 0);
   curnode = sgfAddPlay(curnode, gameinfo->to_move, i, j);
+  outputsgf(sgftree.root);
 
   last_move_i = i;
   last_move_j = j;
@@ -528,10 +519,11 @@
 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);
+  sgfAddDebugInfo(curnode, 0);
   curnode = sgfAddPlay(curnode, gameinfo->to_move, -1, -1);
+  outputsgf(sgftree.root);
 
   gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
   if (force) {
@@ -550,7 +542,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 +567,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 +635,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 +657,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 +675,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;
          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 +790,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 +869,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 +889,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
@@ -964,7 +939,6 @@
          tmpstring[strlen(tmpstring)-1] = 0;
          sgf_write_header(sgftree.root, 1, random_seed, komi, level);
          writesgf(sgftree.root, tmpstring);
-           sgf_initialized = 0;
        }
        else
          printf("Please specify filename\n");
@@ -988,7 +962,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 15:50:19 -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 sgffile.c becomes redundant */
        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, 'd', 'v' or 'dv' (default)\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]