427 lines
15 KiB
Plaintext
427 lines
15 KiB
Plaintext
If you want to write your own interface to GNU Go, or if you want to
|
|
create a go application using the GNU Go engine, this chapter is of
|
|
interest to you.
|
|
|
|
First an overview: GNU Go consists of two parts: the GNU Go @i{engine}
|
|
and a program (user interface) which uses this engine. These are linked
|
|
together into one binary. The current program implements the following
|
|
user modes:
|
|
|
|
@itemize @bullet
|
|
@item An interactive board playable on ASCII terminals
|
|
@item solo play - GNU Go plays against itself
|
|
@item replay - a mode which lets the user investigate moves in an existing
|
|
SGF file.
|
|
@item GMP - Go Modem Protocol, a protocol for automatic play between two
|
|
computers.
|
|
@item GTP - Go Text Protocol, a more general go protocol, @pxref{GTP}.
|
|
@end itemize
|
|
@cindex API
|
|
|
|
The GNU Go engine can be used in other applications. For example, supplied
|
|
with GNU Go is another program using the engine, called @file{debugboard},
|
|
in the directory @file{interface/debugboard/}. The program debugboard lets the
|
|
user load SGF files and can then interactively look at different properties of
|
|
the position such as group status and eye status.
|
|
|
|
The purpose of this Chapter is to show how to interface your own
|
|
program such as @code{debugboard} with the GNU Go engine.
|
|
|
|
Figure 1 describes the structure of a program using the GNU Go
|
|
engine.
|
|
|
|
@example
|
|
@group
|
|
+-----------------------------------+
|
|
| |
|
|
| Go application |
|
|
| |
|
|
+-----+----------+------+ |
|
|
| | | | |
|
|
| | Game | | |
|
|
| | handling | | |
|
|
| | | | |
|
|
| +----+-----+ | |
|
|
| SGF | Move | |
|
|
| handling | generation | |
|
|
| | | |
|
|
+----------+------------+-----------+
|
|
| |
|
|
| Board handling |
|
|
| |
|
|
+-----------------------------------+
|
|
|
|
Figure 1: The structure of a program using the GNU Go engine
|
|
|
|
@end group
|
|
@end example
|
|
|
|
The foundation is a library called @code{libboard.a} which provides
|
|
efficient handling of a go board with rule checks for moves, with
|
|
incremental handling of connected strings of stones and with methods to
|
|
efficiently hash go positions.
|
|
|
|
On top of this, there is a library which helps the application use
|
|
Smart Game Format (SGF) files, with complete handling of game trees in
|
|
memory and in files. This library is called @code{libsgf.a}
|
|
|
|
The main part of the code within GNU Go is the move generation
|
|
library which given a position generates a move. This part of the
|
|
engine can also be used to manipulate a go position, add or remove
|
|
stones, do tactical and strategic reading and to query the engine for
|
|
legal moves. These functions are collected into @code{libengine.a}.
|
|
|
|
The game handling code helps the application programmer keep tracks
|
|
of the moves in a game. Games can be saved to
|
|
SGF files and then later be read back again. These are also within
|
|
@code{libengine.a}.
|
|
|
|
The responsibility of the application is to provide the user with a
|
|
user interface, graphical or not, and let the user interact with the
|
|
engine.
|
|
|
|
@menu
|
|
* Getting Started:: How to use the engine in your program
|
|
* Basic Data Structures:: Basic Data Structures in the Engine
|
|
* The Board State:: The board_state `struct'
|
|
* Positional Functions:: Functions which manipulate a Position
|
|
@end menu
|
|
|
|
@node Getting Started
|
|
|
|
@section How to use the engine in your own program: getting started
|
|
|
|
To use the GNU Go engine in your own program you must include
|
|
the file @file{gnugo.h}. This file describes the whole public API. There is
|
|
another file, @file{liberty.h}, which describes the internal interface within
|
|
the engine. If you want to make a new module within the engine, e.g. for
|
|
suggesting moves you will have to include this file also. In this section we
|
|
will only describe the public interface.
|
|
|
|
@findex init_gnugo
|
|
Before you do anything else, you have to call the function
|
|
@code{init_gnugo()}. This function initializes everything within the engine.
|
|
It takes one parameter: the number of megabytes the engine can use for
|
|
the internal hash table. In addition to this the engine will use a few
|
|
megabytes for other purposes such as data describing groups (liberties,
|
|
life status, etc), eyes and so on.
|
|
|
|
@node Basic Data Structures
|
|
@section Basic Data Structures in the Engine
|
|
@cindex data structures
|
|
@cindex position struct
|
|
|
|
|
|
There are some basic definitions in gnugo.h which are used
|
|
everywhere. The most important of these are the numeric declarations of
|
|
colors. Each intersection on the board is represented by one of these:
|
|
|
|
@example
|
|
@group
|
|
|
|
color value
|
|
EMPTY 0
|
|
WHITE 1
|
|
BLACK 2
|
|
|
|
@end group
|
|
@end example
|
|
|
|
There is a macro, @code{OTHER_COLOR(color)} which can be used to get the
|
|
other color than the parameter. This macro can only be used on @code{WHITE}
|
|
or @code{BLACK}, but not on @code{EMPTY}.
|
|
@findex OTHER_COLOR
|
|
|
|
GNU Go uses two different representations of the board, for
|
|
most purposes a one-dimensional one, but for a few purposes a
|
|
two dimensional one (@pxref{Libboard}). The one-dimensional
|
|
board was introduced before GNU Go 3.2, while the two-dimensional
|
|
board dates back to the ancestral program written by Man Lung Li
|
|
before 1995. The API still uses the two-dimensional board, so
|
|
the API functions have not changed much since GNU Go 3.0.
|
|
|
|
@node The Board State
|
|
|
|
@section The board_state struct
|
|
@cindex board_state
|
|
|
|
A basic data structure in the engine is the @code{board_state} struct.
|
|
This structure is internal to the engine and is defined in @file{liberty.h}.
|
|
|
|
@example
|
|
@group
|
|
|
|
typedef unsigned char Intersection;
|
|
|
|
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];
|
|
int move_history_pointer;
|
|
|
|
float komi;
|
|
int move_number;
|
|
@};
|
|
|
|
@end group
|
|
@end example
|
|
|
|
Here @code{Intersection} stores @code{EMPTY}, @code{WHITE} or
|
|
@code{BLACK}. It is currently defined as an @code{unsigned char} to make
|
|
it reasonably efficient in both storage and access time. The board state
|
|
contains an array of @code{Intersection}'s representing the board.
|
|
The move history is contained in the struct. Also contained in
|
|
the struct is the location of a ko (@code{EMPTY}) if the last
|
|
move was not a ko capture, the komi, the number of captures, and
|
|
corresponding data for the initial position at the beginning
|
|
of the move history.
|
|
|
|
@node Positional Functions
|
|
|
|
@section Functions which manipulate a Position
|
|
|
|
All the functions in the engine that manipulate Positions have names
|
|
prefixed by @code{gnugo_}. These functions still use the two-dimensional
|
|
representation of the board (@pxref{The Board Array}). Here is a complete
|
|
list, as prototyped in @file{gnugo.h}:
|
|
|
|
@itemize
|
|
@item @code{void init_gnugo(float memory)}
|
|
@findex init_gnugo
|
|
@quotation
|
|
Initialize the gnugo engine. This needs to be called
|
|
once only.
|
|
@end quotation
|
|
@item @code{void gnugo_clear_board(int boardsize)}
|
|
@findex gnugo_clear_board
|
|
@quotation
|
|
Clear the board.
|
|
@end quotation
|
|
@item @code{void gnugo_set_komi(float new_komi)}
|
|
@findex gnugo_set_komi
|
|
@quotation
|
|
Set the komi.
|
|
@end quotation
|
|
@item @code{void gnugo_add_stone(int i, int j, int color)}
|
|
@findex gnugo_add_stone
|
|
@quotation
|
|
Place a stone on the board
|
|
@end quotation
|
|
@item @code{void gnugo_remove_stone(int i, int j)}
|
|
@findex gnugo_remove_stone
|
|
@quotation
|
|
Remove a stone from the board
|
|
@end quotation
|
|
@item @code{int gnugo_is_pass(int i, int j)}
|
|
@findex gnugo_is_pass
|
|
@quotation
|
|
Return true if (i,j) is PASS_MOVE
|
|
@end quotation
|
|
@item @code{void gnugo_play_move(int i, int j, int color)}
|
|
@findex gnugo_play_move
|
|
@quotation
|
|
Play a move and start the clock
|
|
@end quotation
|
|
@item @code{int gnugo_undo_move(int n)}
|
|
@findex gnugo_undo_move
|
|
@quotation
|
|
Undo n permanent moves. Returns 1 if successful and 0 if it fails.
|
|
If n moves cannot be undone, no move is undone.
|
|
@end quotation
|
|
@item @code{int gnugo_play_sgfnode(SGFNode *node, int to_move)}
|
|
@findex gnugo_play_sgfnode
|
|
@quotation
|
|
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.
|
|
@end quotation
|
|
@item @code{int gnugo_play_sgftree(SGFNode *root, int *until, SGFNode **curnode)}
|
|
@findex gnugo_play_sgftree
|
|
@quotation
|
|
Play the moves in ROOT UNTIL movenumber is reached. Return the color of the
|
|
player whose turn it is to move.
|
|
@end quotation
|
|
@item @code{int gnugo_is_legal(int i, int j, int color)}
|
|
@findex gnugo_is_legal
|
|
@quotation
|
|
Interface to @code{is_legal()}.
|
|
@end quotation
|
|
@item @code{int gnugo_is_suicide(int i, int j, int color)}
|
|
@findex gnugo_is_suicide
|
|
@quotation
|
|
Interface to @code{is_suicide()}.
|
|
@end quotation
|
|
@item @code{int gnugo_placehand(int handicap)}
|
|
@findex gnugo_placehand
|
|
@quotation
|
|
Interface to placehand. Sets up handicap pieces and
|
|
returns the number of placed handicap stones.
|
|
@end quotation
|
|
@item @code{void gnugo_recordboard(SGFNode *root)}
|
|
@findex gnugo_recordboard
|
|
@quotation
|
|
Interface to @code{sgffile_recordboard()}
|
|
@end quotation
|
|
@item @code{int gnugo_sethand(int handicap, SGFNode *node)}
|
|
@findex gnugo_sethand
|
|
@quotation
|
|
Interface to placehand. Sets up handicap stones and
|
|
returns the number of placed handicap stones, updating the sgf file
|
|
@end quotation
|
|
@item @code{float gnugo_genmove(int *i, int *j, int color, int *resign)}
|
|
@findex gnugo_genmove
|
|
@quotation
|
|
Interface to @code{genmove()}.
|
|
@end quotation
|
|
@item @code{int gnugo_attack(int m, int n, int *i, int *j)}
|
|
@findex gnugo_attack
|
|
@quotation
|
|
Interface to @code{attack()}.
|
|
@end quotation
|
|
@item @code{int gnugo_find_defense(int m, int n, int *i, int *j)}
|
|
@findex gnugo_find_defense
|
|
@quotation
|
|
Interface to @code{find_defense()}.
|
|
@end quotation
|
|
@item @code{void gnugo_who_wins(int color, FILE *outfile)}
|
|
@findex gnugo_who_wins
|
|
@quotation
|
|
Interface to @code{who_wins()}.
|
|
@end quotation
|
|
@item @code{float gnugo_estimate_score(float *upper, float *lower)}
|
|
@findex gnugo_estimate_score
|
|
@quotation
|
|
Put upper and lower score estimates into @code{*upper}, @code{*lower} and
|
|
return the average. A positive score favors white. In computing
|
|
the upper bound, @code{CRITICAL} dragons are awarded to white; in
|
|
computing the lower bound, they are awarded to black.
|
|
@end quotation
|
|
@item @code{void gnugo_examine_position(int color, int how_much)}
|
|
@findex gnugo_examine_position
|
|
@quotation
|
|
Interface to @code{examine_position}.
|
|
@end quotation
|
|
@item @code{int gnugo_get_komi()}
|
|
@findex gnugo_get_komi
|
|
@quotation
|
|
Report the komi.
|
|
@end quotation
|
|
@item @code{void gnugo_get_board(int b[MAX_BOARD][MAX_BOARD])}
|
|
@findex gnugo_get_board
|
|
@quotation
|
|
Place the board into the @samp{b} array.
|
|
@end quotation
|
|
@item @code{int gnugo_get_boardsize()}
|
|
@findex gnugo_get_boardsize
|
|
@quotation
|
|
Report the board size.
|
|
@end quotation
|
|
@item @code{int gnugo_get_move_number()}
|
|
@findex gnugo_get_move_number
|
|
@quotation
|
|
Report the move number.
|
|
@end quotation
|
|
@end itemize
|
|
|
|
@section Game handling
|
|
|
|
The functions (in @pxref{Positional Functions}) are all that are needed to
|
|
create a fully functional go program. But to make the life easier for the
|
|
programmer, there is a small set of functions specially designed for handling
|
|
ongoing games.
|
|
|
|
The data structure describing an ongoing game is the @code{Gameinfo}. It
|
|
is defined as follows:
|
|
|
|
@example
|
|
@group
|
|
|
|
typedef struct @{
|
|
int handicap;
|
|
|
|
int to_move; /* whose move it currently is */
|
|
SGFTree game_record; /* Game record in sgf format. */
|
|
|
|
int computer_player; /* BLACK, WHITE, or EMPTY (used as BOTH) */
|
|
|
|
char outfilename[128]; /* Trickle file */
|
|
FILE *outfile;
|
|
@} Gameinfo;
|
|
|
|
@end group
|
|
@end example
|
|
|
|
The meaning of @code{handicap} should be obvious. @code{to_move} is the
|
|
color of the side whose turn it is to move.
|
|
|
|
The SGF tree @code{game_record} is used to store all the moves in the entire
|
|
game, including a header node which contains, among other things, komi
|
|
and handicap.
|
|
|
|
If one or both of the opponents is the computer, the field
|
|
@code{computer_player} is used. Otherwise it can be ignored.
|
|
|
|
GNU Go can use a trickle file to continuously save all the moves of an
|
|
ongoing game. This file can also contain information about internal
|
|
state of the engine such as move reasons for various locations or move
|
|
valuations. The name of this file should
|
|
be stored in @code{outfilename} and the file pointer to the open file is
|
|
stored in @code{outfile}. If no trickle file is used,
|
|
@code{outfilename[0]} will contain a null character and @code{outfile}
|
|
will be set to @code{NULL}.
|
|
|
|
@subsection Functions which manipulate a Gameinfo
|
|
|
|
All the functions in the engine that manipulate Gameinfos have names
|
|
prefixed by @code{gameinfo_}. Here is a complete list, as prototyped in
|
|
@file{gnugo.h}:
|
|
|
|
@itemize
|
|
@item @code{void gameinfo_clear(Gameinfo *ginfo, int boardsize, float komi)}
|
|
@findex gameinfo_clear
|
|
@quotation
|
|
Initialize the @code{Gameinfo} structure.
|
|
@end quotation
|
|
@item @code{void gameinfo_print(Gameinfo *ginfo)}
|
|
@findex gameinfo_print
|
|
@quotation
|
|
Print a gameinfo.
|
|
@end quotation
|
|
@item @code{void gameinfo_load_sgfheader(Gameinfo *gameinfo, SGFNode *head)}
|
|
@findex gameinfo_load_sgfheader
|
|
@quotation
|
|
Reads header info from sgf structure and sets the appropriate variables.
|
|
@end quotation
|
|
@item @code{void gameinfo_play_move(Gameinfo *ginfo, int i, int j, int color)}
|
|
@findex gameinfo_play_move
|
|
@quotation
|
|
Make a move in the game. Return 1 if the move was legal. In that
|
|
case the move is actually done. Otherwise return 0.
|
|
@end quotation
|
|
@item @code{int gameinfo_play_sgftree_rot(Gameinfo *gameinfo, SGFNode *head, const char *untilstr, int orientation)}
|
|
@findex gameinfo_play_sgftree_rot
|
|
@quotation
|
|
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. Head is an sgf tree. 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.
|
|
@end quotation
|
|
@item @code{int gameinfo_play_sgftree(Gameinfo *gameinfo, SGFNode *head, const char *untilstr)}
|
|
@findex gameinfo_play_sgftree
|
|
@quotation
|
|
Same as previous function, using standard orientation.
|
|
@end quotation
|
|
@end itemize
|
|
|
|
|