/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
* http://www.gnu.org/software/gnugo/ for more information. *
* Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
* 2008 and 2009 by the Free Software Foundation. *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation - version 3 or *
* (at your option) any later version. *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License in file COPYING for more details. *
* You should have received a copy of the GNU General Public *
* License along with this program; if not, write to the Free *
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02111, USA. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
* Initialize the gnugo engine. This needs to be called
init_gnugo(float memory
, unsigned int seed
)
/* We need a fixed seed when initializing the Zobrist hashing to get
* FIXME: Test the quality of the seed.
set_random_seed(HASH_RANDOM_SEED
);
reading_cache_init(memory
* 1024 * 1024);
choose_mc_patterns(NULL
);
clear_accuratelib_cache();
/* ---------------------------------------------------------------- */
/* Check whether we can accept a certain boardsize. Set out to NULL to
* suppress informative messages. Return 1 for an acceptable
* boardsize, 0 otherwise.
int check_boardsize(int boardsize
, FILE *out
)
int max_board
= MAX_BOARD
;
if (use_monte_carlo_genmove
&& max_board
> 9)
if (boardsize
< MIN_BOARD
|| boardsize
> max_board
) {
fprintf(out
, "Unsupported board size: %d. ", boardsize
);
if (boardsize
< MIN_BOARD
)
fprintf(out
, "Min size is %d.\n", MIN_BOARD
);
fprintf(out
, "Max size is %d", max_board
);
if (max_board
< MAX_BOARD
)
fprintf(out
, " (%d without --monte-carlo)", MAX_BOARD
);
fprintf(out
, "Try `gnugo --help' for more information.\n");
gnugo_clear_board(int boardsize
)
if (metamachine
&& oracle_exists
)
oracle_clear_board(boardsize
);
/* Play a move and start the clock */
gnugo_play_move(int move
, int color
)
oracle_play_move(move
, color
);
clock_push_button(color
);
* Perform the moves and place the stones from the SGF node on the
* board. Return the color of the player whose turn it is to move.
gnugo_play_sgfnode(SGFNode
*node
, int to_move
)
for (prop
= node
->props
; prop
; prop
= prop
->next
) {
add_stone(get_sgfmove(prop
), BLACK
);
add_stone(get_sgfmove(prop
), WHITE
);
/* Player property - who is next to move? */
if (prop
->value
[0] == 'w' || prop
->value
[0] == 'W')
to_move
= (prop
->name
== SGFW
) ? WHITE
: BLACK
;
gnugo_play_move(get_sgfmove(prop
), to_move
);
to_move
= OTHER_COLOR(to_move
);
/* Interface to place_fixed_handicap. Sets up handicap stones and
gnugo_sethand(int desired_handicap
, SGFNode
*node
)
place_fixed_handicap(desired_handicap
);
sgffile_recordboard(node
);
/* Put upper and lower score estimates into *upper, *lower and
* return the average. A positive score favors white. In computing
* the upper bound, CRITICAL dragons are awarded to white; in
* computing the lower bound, they are awarded to black.
gnugo_estimate_score(float *upper
, float *lower
)
silent_examine_position(EXAMINE_DRAGONS
);
return ((white_score
+ black_score
) / 2.0);
/* ================================================================ */
/* ================================================================ */
* Initialize the structure.
gameinfo_clear(Gameinfo
*gameinfo
)
gnugo_clear_board(board_size
);
gameinfo
->to_move
= BLACK
;
sgftree_clear(&gameinfo
->game_record
);
/* Info relevant to the computer player. */
gameinfo
->computer_player
= WHITE
; /* Make an assumption. */
gameinfo_print(Gameinfo
*gameinfo
)
printf("Board Size: %d\n", board_size
);
printf("Handicap %d\n", gameinfo
->handicap
);
printf("Komi: %.1f\n", komi
);
printf("Move Number: %d\n", movenum
);
printf("To Move: %s\n", color_to_string(gameinfo
->to_move
));
printf("Computer player: ");
if (gameinfo
->computer_player
== WHITE
)
else if (gameinfo
->computer_player
== BLACK
)
else if (gameinfo
->computer_player
== EMPTY
)
* Play the moves in an SGF tree. Walk the main variation, actioning
* the properties into the playing board.
* Returns the color of the next move to be made. The returned color
* being EMPTY signals a failure to load the file.
* Untilstr is an optional string of the form either 'L12' or '120'
* which tells it to stop playing at that move or move-number.
* When debugging, this is the location of the move being examined.
gameinfo_play_sgftree_rot(Gameinfo
*gameinfo
, SGFTree
*tree
,
const char *untilstr
, int orientation
)
int untilmove
= -1; /* Neither a valid move nor pass. */
if (!sgfGetIntProperty(tree
->root
, "SZ", &bs
))
if (!check_boardsize(bs
, stderr
))
if (sgfGetIntProperty(tree
->root
, "HA", &handicap
) && handicap
> 1)
gameinfo
->handicap
= handicap
;
if (handicap
> bs
* bs
- 1 || handicap
< 0) {
gprintf(" Handicap HA[%d] is unreasonable.\n Modify SGF file.\n",
if (!sgfGetFloatProperty(tree
->root
, "KM", &komi
)) {
if (gameinfo
->handicap
== 0)
/* Now we can safely parse the until string (which depends on board size). */
if (*untilstr
> '0' && *untilstr
<= '9') {
DEBUG(DEBUG_LOADSGF
, "Loading until move %d\n", until
);
untilmove
= string_to_location(board_size
, untilstr
);
DEBUG(DEBUG_LOADSGF
, "Loading until move at %1m\n", untilmove
);
/* Finally, we iterate over all the properties of all the
* nodes, actioning them. We follow only the 'child' pointers,
* as we have no interest in variations.
* The sgf routines map AB[aa][bb][cc] into AB[aa]AB[bb]AB[cc]
for (tree
->lastnode
= NULL
; sgftreeForward(tree
);) {
for (prop
= tree
->lastnode
->props
; prop
; prop
= prop
->next
) {
DEBUG(DEBUG_LOADSGF
, "%c%c[%s]\n",
prop
->name
& 0xff, (prop
->name
>> 8), prop
->value
);
/* Generally the last move is unknown when the AB or AW
* properties are encountered. These are used to set up
* a board position (diagram) or to place handicap stones
* without reference to the order in which the stones are
move
= rotate1(get_sgfmove(prop
), orientation
);
if (board
[move
] != EMPTY
)
gprintf("Illegal SGF! attempt to add a stone at occupied point %1m\n",
add_stone(move
, prop
->name
== SGFAB
? BLACK
: WHITE
);
/* Due to a bad comment in the SGF FF3 definition (in the
* "Alphabetical list of properties" section) some
* applications encode the colors with 1 for black and 2 for
if (prop
->value
[0] == 'w'
|| prop
->value
[0] == '2')
/* following really should not be needed for proper sgf file */
if (stones_on_board(GRAY
) == 0 && next
== WHITE
) {
place_fixed_handicap(gameinfo
->handicap
);
sgfOverwritePropertyInt(tree
->root
, "HA", handicap
);
next
= prop
->name
== SGFW
? WHITE
: BLACK
;
/* following really should not be needed for proper sgf file */
if (stones_on_board(GRAY
) == 0 && next
== WHITE
) {
place_fixed_handicap(gameinfo
->handicap
);
sgfOverwritePropertyInt(tree
->root
, "HA", handicap
);
move
= get_sgfmove(prop
);
if (move
== untilmove
|| movenum
== until
- 1) {
gameinfo
->to_move
= next
;
/* go back so that variant will be added to the proper node */
move
= rotate1(move
, orientation
);
if (move
== PASS_MOVE
|| board
[move
] == EMPTY
) {
gnugo_play_move(move
, next
);
next
= OTHER_COLOR(next
);
gprintf("WARNING: Move off board or on occupied position found in sgf-file.\n");
gprintf("Move at %1m ignored, trying to proceed.\n", move
);
gameinfo
->to_move
= next
;
/* The IL property is not a standard SGF property but
* is used by GNU Go to mark illegal moves. If a move
* is found marked with the IL property which is a ko
* capture then that ko capture is deemed illegal and
* (board_ko_i, board_ko_j) is set to the location of
move
= rotate1(get_sgfmove(prop
), orientation
);
if (ON_BOARD(NORTH(move
)))
move_color
= OTHER_COLOR(board
[NORTH(move
)]);
move_color
= OTHER_COLOR(board
[SOUTH(move
)]);
if (is_ko(move
, move_color
, NULL
))
gameinfo
->to_move
= next
;
/* Same as previous function, using standard orientation */
gameinfo_play_sgftree(Gameinfo
*gameinfo
, SGFTree
*tree
, const char *untilstr
)
return gameinfo_play_sgftree_rot(gameinfo
, tree
, untilstr
, 0);