Commit | Line | Data |
---|---|---|
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 | #include "gnugo.h" | |
25 | ||
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | #include <ctype.h> | |
30 | ||
31 | #include "interface.h" | |
32 | #include "sgftree.h" | |
33 | #include "gg_utils.h" | |
34 | #include "liberty.h" | |
35 | ||
36 | static void replay_node(SGFNode *node, int color_to_test, float *replay_score, | |
37 | float *total_score); | |
38 | ||
39 | ||
40 | /* --------------------------------------------------------------*/ | |
41 | /* replay a game */ | |
42 | /* --------------------------------------------------------------*/ | |
43 | ||
44 | void | |
45 | play_replay(SGFTree *tree, int color_to_replay) | |
46 | { | |
47 | char *tmpc = NULL; | |
48 | float replay_score = 0.0; | |
49 | float total_score = 0.0; | |
50 | ||
51 | SGFNode *node = tree->root; | |
52 | ||
53 | /* Board size and komi are already set up correctly since the game | |
54 | * has already been loaded before this function is called. Now we | |
55 | * only have to clear the board before starting over. | |
56 | */ | |
57 | clear_board(); | |
58 | ||
59 | if (!quiet) { | |
60 | printf("Board Size: %d\n", board_size); | |
61 | if (sgfGetCharProperty(node, "HA", &tmpc)) | |
62 | printf("Handicap: %s\n", tmpc); | |
63 | printf("Komi: %.1f\n", komi); | |
64 | if (sgfGetCharProperty(node, "RU", &tmpc)) | |
65 | printf("Ruleset: %s\n", tmpc); | |
66 | if (sgfGetCharProperty(node, "GN", &tmpc)) | |
67 | printf("Game Name: %s\n", tmpc); | |
68 | if (sgfGetCharProperty(node, "DT", &tmpc)) | |
69 | printf("Game Date: %s\n", tmpc); | |
70 | if (sgfGetCharProperty(node, "GC", &tmpc)) | |
71 | printf("Game Comment: %s\n", tmpc); | |
72 | if (sgfGetCharProperty(node, "US", &tmpc)) | |
73 | printf("Game User: %s\n", tmpc); | |
74 | if (sgfGetCharProperty(node, "PB", &tmpc)) | |
75 | printf("Black Player: %s\n", tmpc); | |
76 | if (sgfGetCharProperty(node, "PW", &tmpc)) | |
77 | printf("White Player: %s\n", tmpc); | |
78 | if (sgfGetCharProperty(node, "RE", &tmpc)) | |
79 | printf("Result: %s\n", tmpc); | |
80 | } | |
81 | ||
82 | /* | |
83 | * Now actually run through the file. This is the interesting part. | |
84 | * We need to traverse the SGF tree, and every time we encounter a node | |
85 | * we need to check what move GNU Go would make, and see if it is OK. | |
86 | */ | |
87 | while (node) { | |
88 | replay_node(node, color_to_replay, &replay_score, &total_score); | |
89 | sgffile_output(tree); | |
90 | node = node->child; | |
91 | } | |
92 | ||
93 | if (!quiet) | |
94 | printf("Global score: %.2f / %.2f\n", replay_score, total_score); | |
95 | ||
96 | if (showtime) { | |
97 | gprintf("SLOWEST MOVE: %d at %1m ", slowest_movenum, slowest_move); | |
98 | fprintf(stderr, "(%.2f seconds)\n", slowest_time); | |
99 | fprintf(stderr, "AVERAGE TIME: %.2f seconds per move\n", | |
100 | total_time / movenum); | |
101 | fprintf(stderr, "TOTAL TIME: %.2f seconds\n", | |
102 | total_time); | |
103 | } | |
104 | } | |
105 | ||
106 | ||
107 | #define BUFSIZE 128 | |
108 | ||
109 | /* | |
110 | * Handle this node. | |
111 | */ | |
112 | ||
113 | static void | |
114 | replay_node(SGFNode *node, int color_to_replay, float *replay_score, | |
115 | float *total_score) | |
116 | { | |
117 | SGFProperty *sgf_prop; /* iterate over properties of the node */ | |
118 | SGFProperty *move_prop = NULL; /* remember if we see a move property */ | |
119 | int color; /* color of move to be made at this node. */ | |
120 | ||
121 | int old_move; /* The move played in the file. */ | |
122 | int new_move; /* The move generated by GNU Go. */ | |
123 | ||
124 | char buf[BUFSIZE]; | |
125 | ||
126 | /* Handle any AB / AW properties, and note presence | |
127 | * of move properties. | |
128 | */ | |
129 | ||
130 | for (sgf_prop = node->props; sgf_prop; sgf_prop = sgf_prop->next) { | |
131 | switch (sgf_prop->name) { | |
132 | case SGFAB: | |
133 | /* add black */ | |
134 | add_stone(get_sgfmove(sgf_prop), BLACK); | |
135 | break; | |
136 | case SGFAW: | |
137 | /* add white */ | |
138 | add_stone(get_sgfmove(sgf_prop), WHITE); | |
139 | break; | |
140 | case SGFB: | |
141 | case SGFW: | |
142 | move_prop = sgf_prop; /* remember it for later */ | |
143 | break; | |
144 | } | |
145 | } | |
146 | ||
147 | /* Only generate moves at move nodes. */ | |
148 | if (!move_prop) | |
149 | return; | |
150 | ||
151 | old_move = get_sgfmove(move_prop); | |
152 | color = (move_prop->name == SGFW) ? WHITE : BLACK; | |
153 | ||
154 | if (color == color_to_replay || color_to_replay == GRAY) { | |
155 | float new_move_value = 0.0; | |
156 | float old_move_value = 0.0; | |
157 | ||
158 | /* Get a move from the engine for color. */ | |
159 | int resign; | |
160 | new_move = genmove(color, NULL, &resign); | |
161 | ||
162 | /* Pick up the relevant values from the potential_moves[] array. */ | |
163 | if (new_move != PASS_MOVE) | |
164 | new_move_value = potential_moves[new_move]; | |
165 | if (old_move != PASS_MOVE) | |
166 | old_move_value = potential_moves[old_move]; | |
167 | ||
168 | /* Now report on how well the computer generated the move. */ | |
169 | if (new_move != old_move || !quiet) { | |
170 | mprintf("Move %d (%C): ", movenum + 1, color); | |
171 | ||
172 | if (resign) | |
173 | printf("GNU Go resigns "); | |
174 | else { | |
175 | mprintf("GNU Go plays %1m ", new_move); | |
176 | if (new_move != PASS_MOVE) | |
177 | printf("(%.2f) ", new_move_value); | |
178 | } | |
179 | ||
180 | mprintf("- Game move %1m ", old_move); | |
181 | if (new_move != PASS_MOVE && old_move_value > 0.0) | |
182 | printf("(%.2f) ", old_move_value); | |
183 | printf("\n"); | |
184 | ||
185 | *replay_score += new_move_value - old_move_value; | |
186 | *total_score += new_move_value; | |
187 | } | |
188 | ||
189 | if (new_move != old_move) { | |
190 | if (resign) | |
191 | gg_snprintf(buf, BUFSIZE, "GNU Go resigns - Game move %s (%.2f)", | |
192 | location_to_string(old_move), old_move_value); | |
193 | else { | |
194 | gg_snprintf(buf, BUFSIZE, | |
195 | "GNU Go plays %s (%.2f) - Game move %s (%.2f)", | |
196 | location_to_string(new_move), new_move_value, | |
197 | location_to_string(old_move), old_move_value); | |
198 | if (new_move != PASS_MOVE) | |
199 | sgfCircle(node, I(new_move), J(new_move)); | |
200 | } | |
201 | } | |
202 | else | |
203 | gg_snprintf(buf, BUFSIZE, "GNU Go plays the same move %s (%.2f)", | |
204 | location_to_string(new_move), new_move_value); | |
205 | ||
206 | sgfAddComment(node, buf); | |
207 | sgffile_add_debuginfo(node, 0.0); | |
208 | } | |
209 | ||
210 | /* Finally, do play the move from the file. */ | |
211 | play_move(old_move, color); | |
212 | } | |
213 | ||
214 | ||
215 | /* | |
216 | * Local Variables: | |
217 | * tab-width: 8 | |
218 | * c-basic-offset: 2 | |
219 | * End: | |
220 | */ |