| 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 | |
| 49 | void |
| 50 | sgffile_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 | |
| 89 | void |
| 90 | sgffile_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 | |
| 112 | void |
| 113 | sgffile_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 | |
| 133 | void |
| 134 | sgffile_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 | |
| 155 | void |
| 156 | sgffile_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 | |
| 195 | void |
| 196 | sgffile_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 | |
| 224 | void |
| 225 | sgffile_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 | |
| 237 | int |
| 238 | get_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 | */ |