[Top][All Lists]
[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\
- [gnugo-devel] sgf output - first edition,
Paul Pogonyshev <=