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 <stdlib.h>
27 #include <string.h>
28 
29 #include "sgftree.h"
30 #include "liberty.h"
31 #include "clock.h"
32 
33 #include "gg_utils.h"
34 
35 /*
36  * Initialize the gnugo engine. This needs to be called
37  * once only.
38  */
39 
40 void
init_gnugo(float memory,unsigned int seed)41 init_gnugo(float memory, unsigned int seed)
42 {
43   /* We need a fixed seed when initializing the Zobrist hashing to get
44    * reproducable results.
45    * FIXME: Test the quality of the seed.
46    */
47   set_random_seed(HASH_RANDOM_SEED);
48   reading_cache_init(memory * 1024 * 1024);
49   set_random_seed(seed);
50   persistent_cache_init();
51   clear_board();
52 
53   transformation_init();
54   dfa_match_init();
55   choose_mc_patterns(NULL);
56 
57   clear_approxlib_cache();
58   clear_accuratelib_cache();
59 }
60 
61 
62 /* ---------------------------------------------------------------- */
63 
64 /* Check whether we can accept a certain boardsize. Set out to NULL to
65  * suppress informative messages. Return 1 for an acceptable
66  * boardsize, 0 otherwise.
67  */
check_boardsize(int boardsize,FILE * out)68 int check_boardsize(int boardsize, FILE *out)
69 {
70   int max_board = MAX_BOARD;
71   if (use_monte_carlo_genmove && max_board > 9)
72     max_board = 9;
73 
74   if (boardsize < MIN_BOARD || boardsize > max_board) {
75     if (out) {
76       fprintf(out, "Unsupported board size: %d. ", boardsize);
77       if (boardsize < MIN_BOARD)
78 	fprintf(out, "Min size is %d.\n", MIN_BOARD);
79       else {
80 	fprintf(out, "Max size is %d", max_board);
81 	if (max_board < MAX_BOARD)
82 	  fprintf(out, " (%d without --monte-carlo)", MAX_BOARD);
83 	fprintf(out, ".\n");
84       }
85       fprintf(out, "Try `gnugo --help' for more information.\n");
86     }
87     return 0;
88   }
89 
90   return 1;
91 }
92 
93 /*
94  * Clear the board.
95  */
96 void
gnugo_clear_board(int boardsize)97 gnugo_clear_board(int boardsize)
98 {
99   board_size = boardsize;
100   clear_board();
101   init_timers();
102 #if 0
103   if (metamachine && oracle_exists)
104     oracle_clear_board(boardsize);
105 #endif
106 }
107 
108 /* Play a move and start the clock */
109 
110 void
gnugo_play_move(int move,int color)111 gnugo_play_move(int move, int color)
112 {
113 #if ORACLE
114   if (oracle_exists)
115     oracle_play_move(move, color);
116   else
117     play_move(move, color);
118 #else
119   play_move(move, color);
120 #endif
121   clock_push_button(color);
122 }
123 
124 
125 /*
126  * Perform the moves and place the stones from the SGF node on the
127  * board. Return the color of the player whose turn it is to move.
128  */
129 
130 int
gnugo_play_sgfnode(SGFNode * node,int to_move)131 gnugo_play_sgfnode(SGFNode *node, int to_move)
132 {
133   SGFProperty *prop;
134 
135   for (prop = node->props; prop; prop = prop->next) {
136     switch (prop->name) {
137     case SGFAB:
138       /* A black stone. */
139       add_stone(get_sgfmove(prop), BLACK);
140       break;
141 
142     case SGFAW:
143       /* A white stone. */
144       add_stone(get_sgfmove(prop), WHITE);
145       break;
146 
147     case SGFPL:
148       /* Player property - who is next to move? */
149       if (prop->value[0] == 'w' || prop->value[0] == 'W')
150 	to_move = WHITE;
151       else
152 	to_move = BLACK;
153       break;
154 
155     case SGFW:
156     case SGFB:
157       /* An ordinary move. */
158       to_move = (prop->name == SGFW) ? WHITE : BLACK;
159       gnugo_play_move(get_sgfmove(prop), to_move);
160       to_move = OTHER_COLOR(to_move);
161       break;
162     }
163   }
164 
165   return to_move;
166 }
167 
168 
169 /* Interface to place_fixed_handicap. Sets up handicap stones and
170  * updates the sgf file.
171  */
172 int
gnugo_sethand(int desired_handicap,SGFNode * node)173 gnugo_sethand(int desired_handicap, SGFNode *node)
174 {
175   place_fixed_handicap(desired_handicap);
176   sgffile_recordboard(node);
177   return handicap;
178 }
179 
180 
181 /* Put upper and lower score estimates into *upper, *lower and
182  * return the average. A positive score favors white. In computing
183  * the upper bound, CRITICAL dragons are awarded to white; in
184  * computing the lower bound, they are awarded to black.
185  */
186 
187 float
gnugo_estimate_score(float * upper,float * lower)188 gnugo_estimate_score(float *upper, float *lower)
189 {
190   silent_examine_position(EXAMINE_DRAGONS);
191   if (upper != NULL)
192     *upper = white_score;
193   if (lower != NULL)
194     *lower = black_score;
195   return ((white_score + black_score) / 2.0);
196 }
197 
198 
199 /* ================================================================ */
200 /*                             Gameinfo                             */
201 /* ================================================================ */
202 
203 
204 /*
205  * Initialize the structure.
206  */
207 
208 void
gameinfo_clear(Gameinfo * gameinfo)209 gameinfo_clear(Gameinfo *gameinfo)
210 {
211   gnugo_clear_board(board_size);
212   gameinfo->handicap = 0;
213   gameinfo->to_move = BLACK;
214   sgftree_clear(&gameinfo->game_record);
215 
216   /* Info relevant to the computer player. */
217   gameinfo->computer_player = WHITE; /* Make an assumption. */
218 }
219 
220 
221 /*
222  * Print a gameinfo.
223  */
224 
225 void
gameinfo_print(Gameinfo * gameinfo)226 gameinfo_print(Gameinfo *gameinfo)
227 {
228   printf("Board Size:   %d\n", board_size);
229   printf("Handicap      %d\n", gameinfo->handicap);
230   printf("Komi:         %.1f\n", komi);
231   printf("Move Number:  %d\n", movenum);
232   printf("To Move:      %s\n", color_to_string(gameinfo->to_move));
233 
234   printf("Computer player: ");
235   if (gameinfo->computer_player == WHITE)
236     printf("White\n");
237   else if (gameinfo->computer_player == BLACK)
238     printf("Black\n");
239   else if (gameinfo->computer_player == EMPTY)
240     printf("Both (solo)\n");
241   else
242     printf("Nobody\n");
243 }
244 
245 /*
246  * Play the moves in an SGF tree. Walk the main variation, actioning
247  * the properties into the playing board.
248  *
249  * Returns the color of the next move to be made. The returned color
250  * being EMPTY signals a failure to load the file.
251  *
252  * Head is an sgf tree.
253  * Untilstr is an optional string of the form either 'L12' or '120'
254  * which tells it to stop playing at that move or move-number.
255  * When debugging, this is the location of the move being examined.
256  */
257 
258 int
gameinfo_play_sgftree_rot(Gameinfo * gameinfo,SGFTree * tree,const char * untilstr,int orientation)259 gameinfo_play_sgftree_rot(Gameinfo *gameinfo, SGFTree *tree,
260 			  const char *untilstr, int orientation)
261 {
262   int bs;
263   int next = BLACK;
264   int untilmove = -1; /* Neither a valid move nor pass. */
265   int until = 9999;
266 
267   if (!sgfGetIntProperty(tree->root, "SZ", &bs))
268     bs = 19;
269 
270   if (!check_boardsize(bs, stderr))
271     return EMPTY;
272 
273   handicap = 0;
274   if (sgfGetIntProperty(tree->root, "HA", &handicap) && handicap > 1)
275     next = WHITE;
276   gameinfo->handicap = handicap;
277 
278   if (handicap > bs * bs - 1 || handicap < 0) {
279     gprintf(" Handicap HA[%d] is unreasonable.\n Modify SGF file.\n",
280 	    handicap);
281     return EMPTY;
282   }
283 
284   gnugo_clear_board(bs);
285 
286   if (!sgfGetFloatProperty(tree->root, "KM", &komi)) {
287     if (gameinfo->handicap == 0)
288       komi = 5.5;
289     else
290       komi = 0.5;
291   }
292 
293   /* Now we can safely parse the until string (which depends on board size). */
294   if (untilstr) {
295     if (*untilstr > '0' && *untilstr <= '9') {
296       until = atoi(untilstr);
297       DEBUG(DEBUG_LOADSGF, "Loading until move %d\n", until);
298     }
299     else {
300       untilmove = string_to_location(board_size, untilstr);
301       DEBUG(DEBUG_LOADSGF, "Loading until move at %1m\n", untilmove);
302     }
303   }
304 
305   /* Finally, we iterate over all the properties of all the
306    * nodes, actioning them. We follow only the 'child' pointers,
307    * as we have no interest in variations.
308    *
309    * The sgf routines map AB[aa][bb][cc] into AB[aa]AB[bb]AB[cc]
310    */
311   for (tree->lastnode = NULL; sgftreeForward(tree);) {
312     SGFProperty *prop;
313     int move;
314 
315     for (prop = tree->lastnode->props; prop; prop = prop->next) {
316       DEBUG(DEBUG_LOADSGF, "%c%c[%s]\n",
317 	    prop->name & 0xff, (prop->name >> 8), prop->value);
318       switch (prop->name) {
319       case SGFAB:
320       case SGFAW:
321 	/* Generally the last move is unknown when the AB or AW
322 	 * properties are encountered. These are used to set up
323 	 * a board position (diagram) or to place handicap stones
324 	 * without reference to the order in which the stones are
325 	 * placed on the board.
326 	 */
327 	move = rotate1(get_sgfmove(prop), orientation);
328 	if (board[move] != EMPTY)
329 	  gprintf("Illegal SGF! attempt to add a stone at occupied point %1m\n",
330 		  move);
331 	else
332 	  add_stone(move, prop->name == SGFAB ? BLACK : WHITE);
333 	break;
334 
335       case SGFPL:
336 	/* Due to a bad comment in the SGF FF3 definition (in the
337          * "Alphabetical list of properties" section) some
338          * applications encode the colors with 1 for black and 2 for
339          * white.
340 	 */
341 	if (prop->value[0] == 'w'
342 	    || prop->value[0] == 'W'
343 	    || prop->value[0] == '2')
344 	  next = WHITE;
345 	else
346 	  next = BLACK;
347 	/* following really should not be needed for proper sgf file */
348 	if (stones_on_board(GRAY) == 0 && next == WHITE) {
349 	  place_fixed_handicap(gameinfo->handicap);
350 	  sgfOverwritePropertyInt(tree->root, "HA", handicap);
351 	}
352 	break;
353 
354       case SGFW:
355       case SGFB:
356 	next = prop->name == SGFW ? WHITE : BLACK;
357 	/* following really should not be needed for proper sgf file */
358 	if (stones_on_board(GRAY) == 0 && next == WHITE) {
359 	  place_fixed_handicap(gameinfo->handicap);
360 	  sgfOverwritePropertyInt(tree->root, "HA", handicap);
361 	}
362 
363 	move = get_sgfmove(prop);
364 	if (move == untilmove || movenum == until - 1) {
365 	  gameinfo->to_move = next;
366 	  /* go back so that variant will be added to the proper node */
367 	  sgftreeBack(tree);
368 	  return next;
369 	}
370 
371 	move = rotate1(move, orientation);
372 	if (move == PASS_MOVE || board[move] == EMPTY) {
373 	  gnugo_play_move(move, next);
374 	  next = OTHER_COLOR(next);
375 	}
376 	else {
377 	  gprintf("WARNING: Move off board or on occupied position found in sgf-file.\n");
378 	  gprintf("Move at %1m ignored, trying to proceed.\n", move);
379 	  gameinfo->to_move = next;
380 	  return next;
381 	}
382 
383 	break;
384 
385       case SGFIL:
386 	/* The IL property is not a standard SGF property but
387 	 * is used by GNU Go to mark illegal moves. If a move
388 	 * is found marked with the IL property which is a ko
389 	 * capture then that ko capture is deemed illegal and
390 	 * (board_ko_i, board_ko_j) is set to the location of
391 	 * the ko.
392 	 */
393 	move = rotate1(get_sgfmove(prop), orientation);
394 
395 	if (board_size > 1)
396 	{
397 	  int move_color;
398 
399 	  if (ON_BOARD(NORTH(move)))
400 	    move_color = OTHER_COLOR(board[NORTH(move)]);
401 	  else
402 	    move_color = OTHER_COLOR(board[SOUTH(move)]);
403 	  if (is_ko(move, move_color, NULL))
404 	    board_ko_pos = move;
405 	}
406 	break;
407       }
408     }
409   }
410 
411   gameinfo->to_move = next;
412   return next;
413 }
414 
415 /* Same as previous function, using standard orientation */
416 
417 int
gameinfo_play_sgftree(Gameinfo * gameinfo,SGFTree * tree,const char * untilstr)418 gameinfo_play_sgftree(Gameinfo *gameinfo, SGFTree *tree, const char *untilstr)
419 {
420   return gameinfo_play_sgftree_rot(gameinfo, tree, untilstr, 0);
421 }
422 
423 
424 
425 /*
426  * Local Variables:
427  * tab-width: 8
428  * c-basic-offset: 2
429  * End:
430  */
431