/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * 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. * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef _BOARD_H_ #define _BOARD_H_ #include #include "config.h" #include "sgftree.h" #include "winsocket.h" /* This type is used to store each intersection on the board. * * On a 486, char is best, since the time taken to push and pop * becomes significant otherwise. On other platforms, an int may * be better, e.g. if memcpy() is particularly fast, or if * character access is very slow. */ typedef unsigned char Intersection; /* FIXME: This is very ugly but we can't include hash.h until we have * defined Intersection. And we do need to include it before using * Hash_data. */ #include "hash.h" /* local versions of absolute value, min and max */ #define gg_abs(x) ((x) < 0 ? -(x) : (x)) #define gg_min(a, b) ((a)<(b) ? (a) : (b)) #define gg_max(a, b) ((a)<(b) ? (b) : (a)) /* Avoid compiler warnings with unused parameters */ #define UNUSED(x) (void)x /* A string with n stones can have at most 2(n+1) liberties. From this * follows that an upper bound on the number of liberties of a string * on a board of size N^2 is 2/3 (N^2+1). */ #define MAXLIBS (2*(MAX_BOARD*MAX_BOARD + 1)/3) /* This is a smaller, practical number of liberties that we care to keep track of. */ #define MAX_LIBERTIES 8 /* This is an upper bound on the number of strings that can exist on * the board simultaneously. Since each string must have at least one * liberty and each empty point can provide a liberty to at most four * strings, at least one out of five board points must be empty. * * FIXME: This is not sufficiently large. Above stackp==0, the * incremental board code doesn't re-use the entries for * removed or merged strings, while new strings require new * entries. This is a problem only in very pathological cases, * and is extremely unlikely to occur in practice. * * Actually, in the not all that pathological case of a * repeated triple ko cycle, each move creates a new string and * thus makes use of one more string, which relatively quickly * will exhaust the available strings. For a safe upper bound * MAX_STRINGS should be set to * MAX_STACK + 4 * MAX_BOARD * MAX_BOARD / 5. * It's not clear that it's worth the extra memory, however. */ #define MAX_STRINGS (4 * MAX_BOARD * MAX_BOARD / 5) /* Per gf: Unconditional_life() can get very close to filling the * entire board under certain circumstances. This was discussed in * the list around August 21, 2001, in a thread with the subject * "gnugo bug logs". */ #define MAXSTACK MAX_BOARD * MAX_BOARD #define MAXCHAIN 160 #define HASH_RANDOM_SEED 12345 /* ================================================================ * * One-dimensional board * * ================================================================ */ /* Board sizes */ #define MIN_BOARD 1 /* Minimum supported board size. */ #define MAX_BOARD 19 /* Maximum supported board size. */ #define MAX_HANDICAP 9 /* Maximum supported handicap. */ #define MAX_MOVE_HISTORY 500 /* Max number of moves remembered. */ #define DEFAULT_BOARD_SIZE MAX_BOARD /* Colors and komaster states. */ enum colors { EMPTY, WHITE, BLACK, GRAY, GRAY_WHITE, GRAY_BLACK, WEAK_KO, NUM_KOMASTER_STATES }; #define COLOR_NAMES \ "empty", \ "white", \ "black", \ "gray", \ "gray_white", \ "gray_black", \ "weak_ko" const char *color_to_string(int color); #define OTHER_COLOR(color) (WHITE+BLACK-(color)) #define IS_STONE(arg) ((arg) == WHITE || (arg) == BLACK) /* Note that POS(-1, -1) == 0 * DELTA() is defined so that POS(i+di, j+dj) = POS(i, j) + DELTA(di, dj). */ #define BOARDSIZE ((MAX_BOARD + 2) * (MAX_BOARD + 1) + 1) #define BOARDMIN (MAX_BOARD + 2) #define BOARDMAX (MAX_BOARD + 1) * (MAX_BOARD + 1) #define POS(i, j) ((MAX_BOARD + 2) + (i) * (MAX_BOARD + 1) + (j)) #define DELTA(di, dj) ((di) * (MAX_BOARD + 1) + (dj)) #define I(pos) ((pos) / (MAX_BOARD + 1) - 1) #define J(pos) ((pos) % (MAX_BOARD + 1) - 1) #define PASS_MOVE 0 #define NO_MOVE PASS_MOVE #define NS (MAX_BOARD + 1) #define WE 1 #define SOUTH(pos) ((pos) + NS) #define WEST(pos) ((pos) - 1) #define NORTH(pos) ((pos) - NS) #define EAST(pos) ((pos) + 1) #define SW(pos) ((pos) + NS - 1) #define NW(pos) ((pos) - NS - 1) #define NE(pos) ((pos) - NS + 1) #define SE(pos) ((pos) + NS + 1) #define SS(pos) ((pos) + 2 * NS) #define WW(pos) ((pos) - 2) #define NN(pos) ((pos) - 2 * NS) #define EE(pos) ((pos) + 2) #define DIRECT_NEIGHBORS(pos1, pos2) \ ((pos1) == SOUTH(pos2) \ || (pos1) == WEST(pos2) \ || (pos1) == NORTH(pos2) \ || (pos1) == EAST(pos2)) #define DIAGONAL_NEIGHBORS(pos1, pos2) \ ((pos1) == SW(pos2) \ || (pos1) == NW(pos2) \ || (pos1) == NE(pos2) \ || (pos1) == SE(pos2)) #define BOARD(i, j) board[POS(i, j)] #define MIRROR_MOVE(pos) POS(board_size - 1 - I(pos), board_size - 1 - J(pos)) /* ================================================================ */ /* global variables */ /* ================================================================ */ /* The board and the other parameters deciding the current position. */ extern int board_size; /* board size (usually 19) */ extern Intersection board[BOARDSIZE]; /* go board */ extern int board_ko_pos; extern int black_captured; /* num. of black stones captured */ extern int white_captured; extern Intersection initial_board[BOARDSIZE]; extern int initial_board_ko_pos; extern int initial_white_captured; extern int initial_black_captured; extern int move_history_color[MAX_MOVE_HISTORY]; extern int move_history_pos[MAX_MOVE_HISTORY]; extern Hash_data move_history_hash[MAX_MOVE_HISTORY]; extern int move_history_pointer; extern float komi; extern int handicap; /* used internally in chinese scoring */ extern int movenum; /* movenumber - used for debug output */ extern signed char shadow[BOARDMAX]; /* reading tree shadow */ enum suicide_rules { FORBIDDEN, ALLOWED, ALL_ALLOWED }; extern enum suicide_rules suicide_rule; enum ko_rules { SIMPLE, NONE, PSK, SSK }; extern enum ko_rules ko_rule; extern int stackp; /* stack pointer */ extern int count_variations; /* count (decidestring) */ extern SGFTree *sgf_dumptree; /* This struct holds the internal board state. */ struct board_state { int board_size; Intersection board[BOARDSIZE]; int board_ko_pos; int black_captured; int white_captured; Intersection initial_board[BOARDSIZE]; int initial_board_ko_pos; int initial_white_captured; int initial_black_captured; int move_history_color[MAX_MOVE_HISTORY]; int move_history_pos[MAX_MOVE_HISTORY]; Hash_data move_history_hash[MAX_MOVE_HISTORY]; int move_history_pointer; float komi; int handicap; int move_number; }; /* This is increased by one anytime a move is (permanently) played or * the board is cleared. */ extern int position_number; /* ================================================================ */ /* board.c functions */ /* ================================================================ */ /* Functions handling the permanent board state. */ void clear_board(void); int test_gray_border(void); void setup_board(Intersection new_board[MAX_BOARD][MAX_BOARD], int ko_pos, int *last, float new_komi, int w_captured, int b_captured); void add_stone(int pos, int color); void remove_stone(int pos); void play_move(int pos, int color); int undo_move(int n); void store_board(struct board_state *state); void restore_board(struct board_state *state); /* Information about the permanent board. */ int get_last_move(void); int get_last_player(void); int get_last_opponent_move(int color); int stones_on_board(int color); /* Functions handling the variable board state. */ int trymove(int pos, int color, const char *message, int str); int tryko(int pos, int color, const char *message); void popgo(void); int komaster_trymove(int pos, int color, const char *message, int str, int *is_conditional_ko, int consider_conditional_ko); int get_komaster(void); int get_kom_pos(void); int move_in_stack(int pos, int cutoff); void get_move_from_stack(int k, int *move, int *color); void dump_stack(void); void do_dump_stack(void); void reset_trymove_counter(void); int get_trymove_counter(void); /* move properties */ int is_pass(int pos); int is_legal(int pos, int color); int is_suicide(int pos, int color); int is_illegal_ko_capture(int pos, int color); int is_allowed_move(int pos, int color); int is_ko(int pos, int color, int *ko_pos); int is_ko_point(int pos); int does_capture_something(int pos, int color); int is_self_atari(int pos, int color); /* Purely geometric functions. */ int is_edge_vertex(int pos); int is_corner_vertex(int pos); int edge_distance(int pos); int square_dist(int pos1, int pos2); int rotate1(int pos, int rot); /* Basic string information. */ int find_origin(int str); int chainlinks(int str, int adj[MAXCHAIN]); int chainlinks2(int str, int adj[MAXCHAIN], int lib); int chainlinks3(int str, int adj[MAXCHAIN], int lib); int extended_chainlinks(int str, int adj[MAXCHAIN], int both_colors); int liberty_of_string(int pos, int str); int second_order_liberty_of_string(int pos, int str); int neighbor_of_string(int pos, int str); int has_neighbor(int pos, int color); int same_string(int str1, int str2); int adjacent_strings(int str1, int str2); void mark_string(int str, signed char mx[BOARDMAX], signed char mark); int are_neighbors(int pos1, int pos2); /* Count and/or find liberties at (pos). */ int countlib(int str); int findlib(int str, int maxlib, int *libs); int fastlib(int pos, int color, int ignore_captures); int approxlib(int pos, int color, int maxlib, int *libs); int accuratelib(int pos, int color, int maxlib, int *libs); int count_common_libs(int str1, int str2); int find_common_libs(int str1, int str2, int maxlib, int *libs); int have_common_lib(int str1, int str2, int *lib); /* Count the number of stones in a string. */ int countstones(int str); int findstones(int str, int maxstones, int *stones); int count_adjacent_stones(int str1, int str2, int maxstones); /* Detect a special shape. */ int send_two_return_one(int move, int color); /* Special function for reading.c */ void incremental_order_moves(int move, int color, int string, int *number_edges, int *number_same_string, int *number_own, int *number_opponent, int *captured_stones, int *threatened_stones, int *saved_stones, int *number_open); /* Board caches initialization functions. */ void clear_approxlib_cache(void); void clear_accuratelib_cache(void); /* Is this point inside the board? */ #if 0 #define ON_BOARD2(i, j) ((i)>=0 && (j)>=0 && (i) something) * is equivalent to * if ((unsigned) expr > something) * * (I think gcc knows this trick, but it does no harm to * encode it explicitly since it saves typing !) */ #define ON_BOARD2(i, j) ((unsigned) (i) < (unsigned) board_size &&\ (unsigned) (j) < (unsigned) board_size) #endif #define ASSERT_ON_BOARD2(i, j) ASSERT2(ON_BOARD2((i), (j)), (i), (j)) #define ON_BOARD1(pos) (((unsigned) (pos) < BOARDSIZE) && board[pos] != GRAY) #define ON_BOARD(pos) (board[pos] != GRAY) #define ASSERT_ON_BOARD1(pos) ASSERT1(ON_BOARD1(pos), (pos)) /* Coordinates for the eight directions, ordered * south, west, north, east, southwest, northwest, northeast, southeast. * Defined in board.c. */ extern int deltai[8]; /* = { 1, 0, -1, 0, 1, -1, -1, 1}; */ extern int deltaj[8]; /* = { 0, -1, 0, 1, -1, -1, 1, 1}; */ extern int delta[8]; /* = { NS, -1, -NS, 1, NS-1, -NS-1, -NS+1, NS+1}; */ /* ================================================================ */ /* Other functions */ /* ================================================================ */ /* SGF routines for debugging purposes in sgffile.c */ void sgffile_begindump(struct SGFTree_t *tree); void sgffile_enddump(const char *filename); /* Hashing and Caching statistics. */ struct stats_data { int nodes; /* Number of visited nodes while reading */ int read_result_entered; /* Number of read results entered. */ int read_result_hits; /* Number of hits of read results. */ int trusted_read_result_hits; /* Number of hits of read results */ /* with sufficient remaining depth. */ }; extern struct stats_data stats; /* printutils.c */ int gprintf(const char *fmt, ...); void vgprintf(FILE *outputfile, const char *fmt, va_list ap); void mprintf(const char *fmt, ...); void gfprintf(FILE *outfile, const char *fmt, ...); const char *color_to_string(int color); const char *location_to_string(int pos); void location_to_buffer(int pos, char *buf); int string_to_location(int boardsize, const char *str); int is_hoshi_point(int m, int n); void draw_letter_coordinates(FILE *outfile); void simple_showboard(FILE *outfile); void mark_goal_in_sgf(signed char goal[BOARDMAX]); /* ================================================================ */ /* assertions */ /* ================================================================ */ /* Our own abort() which prints board state on the way out. * (pos) is a "relevant" board position for info. */ void abortgo(const char *file, int line, const char *msg, int pos) #ifdef __GNUC__ __attribute__ ((noreturn)) #endif ; #ifdef GG_TURN_OFF_ASSERTS #define ASSERT2(x, i, j) #define ASSERT1(x, pos) #else /* avoid dangling else */ /* FIXME: Should probably re-write these using do {...} while (0) idiom. */ #define ASSERT2(x, i, j) if (x) ; else abortgo(__FILE__, __LINE__, #x, POS(i, j)) #define ASSERT1(x, pos) if (x) ; else abortgo(__FILE__, __LINE__, #x, pos) #endif #define gg_assert(x) ASSERT1(x, NO_MOVE) /* Are we using valgrind memory checking? */ #if USE_VALGRIND #include #else #define VALGRIND_MAKE_WRITABLE(a, b) #endif #endif /* _BOARD_H_ */ /* * Local Variables: * tab-width: 8 * c-basic-offset: 2 * End: */