Initial commit of GNU Go v3.8.
[sgk-go] / engine / board.h
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* 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 <stdarg.h>
#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)<board_size && (j)<board_size)
#else
/*
* For the case when expr can only be slightly negative,
* if (expr < 0 || expr > 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 <valgrind/memcheck.h>
#else
#define VALGRIND_MAKE_WRITABLE(a, b)
#endif
#endif /* _BOARD_H_ */
/*
* Local Variables:
* tab-width: 8
* c-basic-offset: 2
* End:
*/