Before starting to tinker, ran clang-format on files that seem like relevant starting...
[sgk-go] / interface / play_solo.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#include "gnugo.h"
25
c150f57c 26#include <math.h>
7eeb782e
AT
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
7eeb782e
AT
30
31#include "interface.h"
32
33#include "liberty.h" /* to get to the stats */
34
7eeb782e 35#include "gg_utils.h"
c150f57c
AT
36#include "random.h"
37#include "sgftree.h"
7eeb782e 38
c150f57c 39void play_solo(Gameinfo* gameinfo, int moves)
7eeb782e 40{
c150f57c
AT
41 SGFTree sgftree;
42 int passes = 0; /* num. consecutive passes */
43 float move_value;
44 double t1, t2;
45 int save_moves = moves;
7eeb782e 46
c150f57c
AT
47 struct stats_data totalstats;
48 int total_owl_count = 0;
7eeb782e 49
c150f57c 50 /* It tends not to be very imaginative in the opening,
7eeb782e
AT
51 * so we scatter a few stones randomly to start with.
52 * We add two random numbers to reduce the probability
53 * of playing stones near the edge.
54 */
7eeb782e 55
c150f57c
AT
56 int n = 6 + 2 * gg_rand() % 5;
57 int i, j;
58
59 komi = 5.5;
60
61 sgftree_clear(&sgftree);
62 sgftreeCreateHeaderNode(&sgftree, board_size, komi, handicap);
63 sgf_write_header(sgftree.root, 1, get_random_seed(), 5.5, handicap,
64 get_level(), chinese_rules);
65
66 /* Generate some random moves. */
67 if (board_size > 6) {
68 do {
69 do {
70 i = (gg_rand() % 4) + (gg_rand() % (board_size - 4));
71 j = (gg_rand() % 4) + (gg_rand() % (board_size - 4));
72 } while (!is_allowed_move(POS(i, j), gameinfo->to_move));
73
74 gnugo_play_move(POS(i, j), gameinfo->to_move);
75 sgftreeAddPlay(&sgftree, gameinfo->to_move, i, j);
76 sgftreeAddComment(&sgftree, "random move");
77 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
78 } while (--n > 0);
79 }
7eeb782e 80
c150f57c
AT
81 t1 = gg_cputime();
82 memset(&totalstats, '\0', sizeof(totalstats));
83 while (passes < 2 && --moves >= 0) {
84 int move;
85 reset_owl_node_counter();
86 move = genmove(gameinfo->to_move, &move_value, NULL);
87
88 gnugo_play_move(move, gameinfo->to_move);
89 sgffile_add_debuginfo(sgftree.lastnode, move_value);
90 sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
91 sgffile_output(&sgftree);
92 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
93
94 if (move == PASS_MOVE) {
95 passes++;
96 printf("%s(%d): Pass\n", gameinfo->to_move == BLACK ? "Black" : "White",
97 movenum);
98 } else {
99 passes = 0;
100 gprintf("%s(%d): %1m\n", gameinfo->to_move == BLACK ? "Black" : "White",
101 movenum, move);
102 }
103
104 totalstats.nodes += stats.nodes;
105 totalstats.read_result_entered += stats.read_result_entered;
106 totalstats.read_result_hits += stats.read_result_hits;
107 totalstats.trusted_read_result_hits += stats.trusted_read_result_hits;
108 total_owl_count += get_owl_node_counter();
7eeb782e 109 }
c150f57c
AT
110 t2 = gg_cputime();
111
112 /* Two passes and it's over. (EMPTY == BOTH) */
113 who_wins(EMPTY, stdout);
114
115 {
116 float score = gnugo_estimate_score(NULL, NULL);
117 sgfWriteResult(sgftree.root, score, 1);
7eeb782e 118 }
c150f57c 119 sgffile_output(&sgftree);
7eeb782e 120
c150f57c
AT
121 printf("%10d moves played in %0.3f seconds\n", save_moves - moves, t2 - t1);
122 if (save_moves != moves)
123 printf("%10.3f seconds/move\n", (t2 - t1) / (save_moves - moves));
7eeb782e 124
c150f57c
AT
125 printf("%10d nodes\n", totalstats.nodes);
126 printf("%10d read results entered\n", totalstats.read_result_entered);
127 printf("%10d read result hits\n", totalstats.read_result_hits);
128 printf("%10d trusted read result hits\n",
129 totalstats.trusted_read_result_hits);
130 printf("%10d owl nodes\n", total_owl_count);
131}
7eeb782e
AT
132
133/* ================================================================ */
134
7eeb782e
AT
135/*
136 * Load SGF file and run genmove().
137 */
138
c150f57c 139void load_and_analyze_sgf_file(Gameinfo* gameinfo)
7eeb782e 140{
c150f57c
AT
141 SGFTree sgftree;
142 int move;
143 int next;
144 float move_value;
145
146 next = gameinfo->to_move;
147 sgftree = gameinfo->game_record;
148
149 if (metamachine)
150 sgffile_begindump(&sgftree);
7eeb782e 151
c150f57c
AT
152 move = genmove(next, &move_value, NULL);
153
154 gprintf("%s move %1m\n", next == WHITE ? "white (O)" : "black (X)", move);
155
156 if (metamachine)
157 sgffile_enddump(outfilename);
158 else {
159 gnugo_play_move(move, next);
160 sgftreeAddPlay(&sgftree, next, I(move), J(move));
161 sgftreeAddComment(&sgftree, "load and analyze mode");
162 sgffile_add_debuginfo(sgftree.lastnode, move_value);
163 sgffile_output(&sgftree);
164 }
165}
7eeb782e
AT
166
167/*
168 * Load SGF file and score the game
169 * scoringmode:
170 * estimate - estimate territorial balance
171 * finish - finish the game by selfplaying and then count the score quickly
172 * aftermath - like 'finish' but also play out the aftermath in order to
173 * get an accurate score
174 */
175
c150f57c
AT
176#define ESTIMATE 0
177#define FINISH 1
7eeb782e
AT
178#define AFTERMATH 2
179
c150f57c
AT
180void load_and_score_sgf_file(SGFTree* tree, Gameinfo* gameinfo,
181 const char* scoringmode)
7eeb782e 182{
c150f57c
AT
183 int move;
184 float move_value;
185 char* tempc = NULL;
186 char text[250];
187 char winner;
188 int next;
189 int pass = 0;
190 int method;
191 float score;
192 SGFTree local_tree;
193 SGFTree* score_tree = tree;
194
195 /* Default scoring method is ESTIMATE since it's fastest. */
196 method = ESTIMATE;
197 if (strcmp(scoringmode, "finish") == 0)
198 method = FINISH;
199 else if (strcmp(scoringmode, "aftermath") == 0)
200 method = AFTERMATH;
201
202 /* For aftermath scoring we compress the previous moves to a static
7eeb782e
AT
203 * board position in the output sgf. This helps a lot when debugging
204 * scoring mistakes. We don't do this for the finish method,
205 * however, since users may be better served by having GNU Go's
206 * selfplay added to the original game record.
207 */
c150f57c
AT
208 if (method == AFTERMATH) {
209 sgftree_clear(&local_tree);
210 /* Modify komi to compensate for captured stones. We start at a
7eeb782e
AT
211 * setup position and since there is no standard sgf property to
212 * tell the number of captured stones, a modified komi is the best
213 * available solution.
214 */
c150f57c
AT
215 sgftreeCreateHeaderNode(&local_tree, board_size,
216 komi + black_captured - white_captured, handicap);
217 sgffile_printboard(&local_tree);
218 sgfAddProperty(local_tree.lastnode, "PL",
219 gameinfo->to_move == WHITE ? "W" : "B");
220 score_tree = &local_tree;
7eeb782e 221 }
c150f57c
AT
222
223 next = gameinfo->to_move;
224 reset_engine();
225
226 /* Complete the game by selfplay for the finish and aftermath methods. */
227 if (method != ESTIMATE) {
228 doing_scoring = 1;
229 while (pass < 2) {
230 move = genmove_conservative(next, &move_value);
231 if (move != PASS_MOVE) {
232 pass = 0;
233 gprintf("%d %s move %1m\n", movenum,
234 next == WHITE ? "white (O)" : "black (X)", move);
235 } else {
236 pass++;
237 gprintf("%d %s move PASS\n", movenum,
238 next == WHITE ? "white (O)" : "black (X)");
239 }
240 play_move(move, next);
241 sgffile_add_debuginfo(score_tree->lastnode, move_value);
242 sgftreeAddPlay(score_tree, next, I(move), J(move));
243 sgffile_output(score_tree);
244 next = OTHER_COLOR(next);
245 }
246 doing_scoring = 0;
247 }
248
249 /* Calculate the score. */
250 if (method == AFTERMATH)
251 score = aftermath_compute_score(next, score_tree);
252 else
253 score = gnugo_estimate_score(NULL, NULL);
254
255 if (score < 0.0) {
256 sprintf(text, "Black wins by %1.1f points\n", -score);
257 winner = 'B';
258 } else if (score > 0.0) {
259 sprintf(text, "White wins by %1.1f points\n", score);
260 winner = 'W';
261 } else {
262 sprintf(text, "Jigo\n");
263 winner = '0';
264 }
265 fputs(text, stdout);
266 sgftreeAddComment(score_tree, text);
267
268 /* For the finish and aftermath methods we compare the score with
7eeb782e
AT
269 * what's stored in the game record.
270 *
271 * FIXME: No comparison is made if the stored result was 0. Wins by
272 * time or forfeit are not handled either.
273 *
274 * FIXME: Does anybody actually care about this information? Just
275 * removing this piece of code is a tempting alternative.
276 */
c150f57c
AT
277 if (method != ESTIMATE && sgfGetCharProperty(tree->root, "RE", &tempc)) {
278 char dummy;
279 float result;
280 if (sscanf(tempc, "%1c%f", &dummy, &result) == 2) {
281 fprintf(stdout, "Result from file: %c+%1.1f\n", dummy, result);
282 fputs("GNU Go result and result from file are ", stdout);
283 if (result == fabs(score) && winner == dummy)
284 fputs("identical\n", stdout);
285 else
286 fputs("different\n", stdout);
287
288 } else {
289 if (tempc[2] == 'R') {
290 fprintf(stdout, "Result from file: Resign\n");
291 fputs("GNU Go result and result from file are ", stdout);
292 if (tempc[0] == winner)
293 fputs("identical\n", stdout);
294 else
295 fputs("different\n", stdout);
296 }
297 }
7eeb782e 298 }
7eeb782e 299
c150f57c
AT
300 if (method != ESTIMATE)
301 sgfWriteResult(score_tree->root, score, 1);
7eeb782e 302
c150f57c
AT
303 sgffile_output(score_tree);
304}
7eeb782e
AT
305
306/*
307 * Local Variables:
c150f57c
AT
308 * tab-width: 4
309 * c-basic-offset: 4
7eeb782e
AT
310 * End:
311 */