Updated README: Equal sign not required with `--mode` flag.
[sgk-go] / engine / sgffile.c
CommitLineData
7eeb782e
AT
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
3 * http://www.gnu.org/software/gnugo/ for more information. *
4 * *
5 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
6 * 2008 and 2009 by the Free Software Foundation. *
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation - version 3 or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License in file COPYING for more details. *
17 * *
18 * You should have received a copy of the GNU General Public *
19 * License along with this program; if not, write to the Free *
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
21 * Boston, MA 02111, USA. *
22\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
24/*
25 * sgffile.c
26 *
27 * This file used to contain functions that create an SGF file on the fly.
28 *
29 * Today it contains supporting code around the more general SGF library
30 * found in the sgf/ directory.
31 */
32
33#include "gnugo.h"
34
35#include <stdio.h>
36#include <stdarg.h>
37#include <stdlib.h>
38#include <string.h>
39
40#include "liberty.h"
41#include "sgftree.h"
42#include "gg_utils.h"
43
44/*
45 * Add debug information to a node if user requested it from command
46 * line.
47 */
48
49void
50sgffile_add_debuginfo(SGFNode *node, float value)
51{
52 int pos;
53 char comment[24];
54
55 if (!outfilename[0])
56 return;
57
58 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
59 if (!ON_BOARD(pos))
60 continue;
61
62 if (IS_STONE(board[pos]) && (output_flags & OUTPUT_MARKDRAGONS)) {
63 if (dragon[pos].crude_status == DEAD)
64 sgfLabel(node, "X", I(pos), J(pos));
65 else if (dragon[pos].crude_status == CRITICAL)
66 sgfLabel(node, "!", I(pos), J(pos));
67 }
68
69 if (potential_moves[pos] > 0.0 && (output_flags & OUTPUT_MOVEVALUES)) {
70 if (potential_moves[pos] < 1.0)
71 sgfLabel(node, "<1", I(pos), J(pos));
72 else
73 sgfLabelInt(node, (int) potential_moves[pos], I(pos), J(pos));
74 }
75 }
76
77 if (value > 0.0 && (output_flags & OUTPUT_MOVEVALUES)) {
78 sprintf(comment, "Value of move: %.2f", value);
79 sgfAddComment(node, comment);
80 }
81}
82
83
84/*
85 * Write sgf tree to output file specified with -o option.
86 * This can safely be done multiple times.
87 */
88
89void
90sgffile_output(SGFTree *tree)
91{
92 if (outfilename[0])
93 writesgf(tree->root, outfilename);
94}
95
96
97/* ================================================================
98 * Dumping of information about a position into an sgftree.
99 * Used by sgffile_decideposition, etc.
100 * ================================================================ */
101
102
103/*
104 * sgffile_begindump begins storing all moves considered by
105 * trymove and tryko in an sgf tree in memory.
106 *
107 * The caller only has to provide an own SGFTree pointer if he wants
108 * to do something more with the tree than writing it to file as done
109 * by sgffile_enddump().
110 */
111
112void
113sgffile_begindump(SGFTree *tree)
114{
115 static SGFTree local_tree;
116 gg_assert(sgf_dumptree == NULL);
117
118 if (tree == NULL)
119 sgf_dumptree = &local_tree;
120 else
121 sgf_dumptree = tree;
122
123 sgftree_clear(sgf_dumptree);
124 sgftreeCreateHeaderNode(sgf_dumptree, board_size, komi, handicap);
125 sgffile_printboard(sgf_dumptree);
126}
127
128
129/*
130 * sgffile_enddump ends the dump and writes the sgf tree to file.
131 */
132
133void
134sgffile_enddump(const char *filename)
135{
136 /* Check if we have a valid filename and a tree. */
137 if (filename && *filename && sgf_dumptree) {
138 if (writesgf(sgf_dumptree->root, filename)) {
139 /* Only delete the tree if writesgf() succeeds. If it doesn't, one
140 * will most likely wish to save into another (writable) file.
141 */
142 sgfFreeNode(sgf_dumptree->root);
143 sgf_dumptree = NULL;
144 }
145 }
146}
147
148
149/*
150 * sgffile_printsgf creates an sgf of the current board position
151 * (without any move history). It also adds information about who is
152 * to play and marks illegal moves with the private sgf property IL.
153 */
154
155void
156sgffile_printsgf(int color_to_play, const char *filename)
157{
158 SGFTree sgftree;
159 int m, n;
160 char pos[3];
161 char str[128];
162 float relative_komi;
163
164 relative_komi = komi + black_captured - white_captured;
165
166 sgftree_clear(&sgftree);
167 sgftreeCreateHeaderNode(&sgftree, board_size, relative_komi, handicap);
168 sgf_write_header(sgftree.root, 1, get_random_seed(), relative_komi,
169 handicap, get_level(), chinese_rules);
170 gg_snprintf(str, 128, "GNU Go %s load and print", gg_version());
171 sgfOverwriteProperty(sgftree.root, "GN", str);
172
173 sgffile_printboard(&sgftree);
174
175 if (color_to_play != EMPTY) {
176 sgfAddProperty(sgftree.lastnode, "PL",
177 (color_to_play == WHITE ? "W" : "B"));
178
179 for (m = 0; m < board_size; ++m)
180 for (n = 0; n < board_size; ++n)
181 if (BOARD(m, n) == EMPTY && !is_legal(POS(m, n), color_to_play)) {
182 gg_snprintf(pos, 3, "%c%c", 'a' + n, 'a' + m);
183 sgfAddProperty(sgftree.lastnode, "IL", pos);
184 }
185 }
186
187 writesgf(sgftree.root, filename);
188}
189
190
191/*
192 * sgffile_printboard adds the current board position to the tree.
193 */
194
195void
196sgffile_printboard(SGFTree *tree)
197{
198 int i, j;
199 SGFNode *node;
200
201 gg_assert(tree);
202 node = tree->lastnode;
203
204 /* Write the white stones to the file. */
205 for (i = 0; i < board_size; i++) {
206 for (j = 0; j < board_size; j++) {
207 if (BOARD(i, j) == WHITE)
208 sgfAddStone(node, WHITE, i, j);
209 }
210 }
211
212 /* Write the black stones to the file. */
213 for (i = 0; i < board_size; i++) {
214 for (j = 0; j < board_size; j++) {
215 if (BOARD(i, j) == BLACK)
216 sgfAddStone(node, BLACK, i, j);
217 }
218 }
219
220 sgftreeSetLastNode(tree, node);
221}
222
223
224void
225sgffile_recordboard(SGFNode *node)
226{
227 int i, j;
228
229 if (node)
230 for (i = 0; i < board_size; i++)
231 for (j = 0; j < board_size; j++)
232 if (BOARD(i, j) == BLACK)
233 sgfAddStone(node, BLACK, i, j);
234}
235
236
237int
238get_sgfmove(SGFProperty *property)
239{
240 return POS(get_moveX(property, board_size), get_moveY(property, board_size));
241}
242
243
244/*
245 * Local Variables:
246 * tab-width: 8
247 * c-basic-offset: 2
248 * End:
249 */