/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* 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. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <readline/history.h>
#include <readline/readline.h>
#define DEBUG_COMMANDS "\
capture <pos> try to capture indicated group\n\
dead Toggle display of dead stones\n\
defend <pos> try to defend indicated group\n\
listdragons print dragon info \n\
showdragons display dragons\n\
showterri display territory\n\
/* some options for the ascii interface */
static int opt_showboard
= 1;
static int resignation_allowed
;
/* Unreasonable score used to detect missing information. */
/* Keep track of the score estimated before the last computer move. */
static int current_score_estimate
= NO_SCORE
;
static void do_play_ascii(Gameinfo
* gameinfo
);
static int ascii_endgame(Gameinfo
* gameinfo
, int reason
);
static void ascii_count(Gameinfo
* gameinfo
);
static void showcapture(char* line
);
static void showdefense(char* line
);
static void ascii_goto(Gameinfo
* gameinfo
, char* line
);
static void ascii_free_handicap(Gameinfo
* gameinfo
, char* handicap_string
);
/* If sgf game info is written can't reset parameters like handicap, etc. */
static int sgf_initialized
;
* Create letterbar for the top and bottom of the ASCII board.
make_letterbar(int boardsize
, char* letterbar
)
for (i
= 0; i
< boardsize
; i
++) {
if (i
+ letteroffset
>= 'I')
strcat(letterbar
, spaces
);
sprintf(letter
, "%c", i
+ letteroffset
);
strcat(letterbar
, letter
);
/* This array contains +'s and -'s for the empty board positions.
* hspot_size contains the board size that the grid has been
static char hspots
[MAX_BOARD
][MAX_BOARD
];
* Mark the handicap spots on the board.
set_handicap_spots(int boardsize
)
if (hspot_size
== boardsize
)
memset(hspots
, '.', sizeof(hspots
));
hspots
[boardsize
- 2][1] = '+';
hspots
[1][boardsize
- 2] = '+';
hspots
[boardsize
- 2][boardsize
- 2] = '+';
hspots
[boardsize
/ 2][boardsize
/ 2] = '+';
/* If the board size is even, no center handicap spots. */
if (boardsize
> 2 && boardsize
< 12) {
/* Place the outer 4 only. */
hspots
[boardsize
- 3][2] = '+';
hspots
[2][boardsize
- 3] = '+';
hspots
[boardsize
- 3][boardsize
- 3] = '+';
/* Place the outer 4 only. */
hspots
[boardsize
- 4][3] = '+';
hspots
[3][boardsize
- 4] = '+';
hspots
[boardsize
- 4][boardsize
- 4] = '+';
if (boardsize
> 2 && boardsize
< 12) {
/* Place the outer 4... */
hspots
[boardsize
- 3][2] = '+';
hspots
[2][boardsize
- 3] = '+';
hspots
[boardsize
- 3][boardsize
- 3] = '+';
/* ...and the middle one. */
hspots
[boardsize
/ 2][boardsize
/ 2] = '+';
} else if (boardsize
> 12) {
/* Place the outer 4... */
hspots
[boardsize
- 4][3] = '+';
hspots
[3][boardsize
- 4] = '+';
hspots
[boardsize
- 4][boardsize
- 4] = '+';
/* ...and the inner 4... */
hspots
[3][boardsize
/ 2] = '+';
hspots
[boardsize
/ 2][3] = '+';
hspots
[boardsize
/ 2][boardsize
- 4] = '+';
hspots
[boardsize
- 4][boardsize
/ 2] = '+';
/* ...and the middle one. */
hspots
[boardsize
/ 2][boardsize
/ 2] = '+';
* Display the board position when playing in ASCII.
int last_move
= get_last_move();
make_letterbar(board_size
, letterbar
);
set_handicap_spots(board_size
);
printf(" White (O) has captured %d pieces\n", black_captured
);
printf(" Black (X) has captured %d pieces\n", white_captured
);
if (current_score_estimate
== NO_SCORE
)
printf(" No score estimate is available yet.\n");
else if (current_score_estimate
< 0)
printf(" Estimated score: Black is ahead by %d\n",
-current_score_estimate
);
else if (current_score_estimate
> 0)
printf(" Estimated score: White is ahead by %d\n",
printf(" Estimated score: Even!\n");
if (get_last_player() != EMPTY
) {
gfprintf(stdout
, " Last move: %s %1m",
get_last_player() == WHITE
? "White" : "Black",
for (i
= 0; i
< board_size
; i
++) {
printf(" %2d", board_size
- i
);
for (j
= 0; j
< board_size
; j
++) {
if (POS(i
, j
) == last_move
)
dead
= (dragon_status(POS(i
, j
)) == DEAD
) && showdead
;
switch (BOARD(i
, j
) + pos_is_move
+ last_pos_was_move
) {
printf(" %c", hspots
[i
][j
]);
printf(" %c", dead
? 'x' : 'X');
printf(" %c", dead
? 'o' : 'O');
printf("%c", hspots
[i
][j
]);
printf("%c", dead
? 'x' : 'X');
printf("%c", dead
? 'o' : 'O');
fprintf(stderr
, "Illegal board value %d\n", (int)BOARD(i
, j
));
if (last_pos_was_move
== 0) {
printf(" %2d", board_size
- i
);
printf(" %1d", board_size
- i
);
printf("%2d", board_size
- i
);
printf("%1d", board_size
- i
);
printf("%s\n\n", letterbar
);
} /* end ascii_showboard */
printf(" back Take back your last move\n");
printf(" boardsize Set boardsize (on move 1 only)\n");
printf(" comment Write a comment to outputfile\n");
printf(" depth <num> Set depth for reading\n");
printf(" display Display game board\n");
printf(" exit Exit GNU Go\n");
printf(" force <move> Force a move for current color\n");
printf(" forward Go to next node in game tree\n");
printf(" goto <movenum> Go to movenum in game tree\n");
printf(" level <amount> Playing level (default = 10)\n");
printf(" handicap <num> Set fixed handicap (on move 1 only)\n");
printf(" freehandicap <num> Place free handicap (on move 1 only)\n");
printf(" Omit <num> to place handicap yourself\n");
printf(" help Display this help menu\n");
printf(" helpdebug Display debug help menu\n");
printf(" info Display program settings\n");
printf(" komi Set komi (on move 1 only)\n");
printf(" last Goto last node in game tree\n");
printf(" pass Pass on your move\n");
printf(" play <num> Play <num> moves\n");
printf(" playblack Play as Black (switch if White)\n");
printf(" playwhite Play as White (switch if Black)\n");
printf(" quit Exit GNU Go\n");
printf(" resign Resign the current game\n");
printf(" save <file> Save the current game\n");
printf(" load <file> Load a game from file\n");
printf(" score Toggle display of score On/Off\n");
printf(" showboard Toggle display of board On/Off\n");
printf(" switch Switch the color you are playing\n");
printf(" undo Take the last move back (same as back)\n");
printf(" <move> A move of the format <letter><number>");
enum commands
{ INVALID
= -1,
* Check if we have a valid command.
get_command(char* command
)
/* Check to see if a move was input. */
if (!((sscanf(command
, "%c%d", &c
, &d
) != 2)
|| ((c
= toupper((int)c
)) < 'A')
|| ((c
= toupper((int)c
)) > 'Z')
/* Kill leading spaces. */
while (command
[0] == ' ')
if (!strncmp(command
, "playblack", 9))
if (!strncmp(command
, "playwhite", 9))
if (!strncmp(command
, "showboard", 9))
if (!strncmp(command
, "showdragons", 9))
if (!strncmp(command
, "listdragons", 9))
if (!strncmp(command
, "boardsize", 9))
if (!strncmp(command
, "freehandicap", 9))
if (!strncmp(command
, "handicap", 5))
if (!strncmp(command
, "display", 7))
if (!strncmp(command
, "helpdebug", 7))
if (!strncmp(command
, "resign", 6))
if (!strncmp(command
, "showmoyo", 6))
if (!strncmp(command
, "showterri", 6))
if (!strncmp(command
, "showarea", 6))
if (!strncmp(command
, "depth", 5))
if (!strncmp(command
, "switch", 5))
if (!strncmp(command
, "komi", 4))
if (!strncmp(command
, "play", 4))
if (!strncmp(command
, "info", 4))
if (!strncmp(command
, "force", 4))
if (!strncmp(command
, "level", 5))
if (!strncmp(command
, "pass", 4))
if (!strncmp(command
, "save", 3))
if (!strncmp(command
, "load", 3))
if (!strncmp(command
, "end", 3))
if (!strncmp(command
, "move", 3))
if (!strncmp(command
, "undo", 3))
if (!strncmp(command
, "comment", 3))
if (!strncmp(command
, "score", 3))
if (!strncmp(command
, "dead", 3))
if (!strncmp(command
, "capture", 3))
if (!strncmp(command
, "defend", 3))
if (!strncmp(command
, "exit", 4))
if (!strncmp(command
, "quit", 4))
if (!strncmp(command
, "help", 1))
if (!strncmp(command
, "back", 2))
if (!strncmp(command
, "forward", 2))
if (!strncmp(command
, "last", 2))
if (!strncmp(command
, "goto", 2))
if (!strncmp(command
, "game", 2))
if (!strncmp(command
, "count", 3))
if (!strncmp(command
, "continue", 4))
/* No valid command was found. */
init_sgf(Gameinfo
* ginfo
)
sgf_write_header(sgftree
.root
, 1, get_random_seed(), komi
,
ginfo
->handicap
, get_level(), chinese_rules
);
sgffile_recordboard(sgftree
.root
);
* Generate the computer move.
computer_move(Gameinfo
* gameinfo
, int* passes
)
int resignation_declined
= 0;
float upper_bound
, lower_bound
;
/* Generate computer move. */
adjust_level_offset(gameinfo
->to_move
);
move
= genmove(gameinfo
->to_move
, &move_value
, &resign
);
if (resignation_allowed
&& resign
) {
int state
= ascii_endgame(gameinfo
, 2);
/* The opponent declined resignation. Remember not to resign again. */
resignation_declined
= 1;
gnugo_estimate_score(&upper_bound
, &lower_bound
);
current_score_estimate
= (int)((lower_bound
+ upper_bound
) / 2.0);
mprintf("%s(%d): %1m\n", color_to_string(gameinfo
->to_move
),
gnugo_play_move(move
, gameinfo
->to_move
);
sgffile_add_debuginfo(sgftree
.lastnode
, move_value
);
sgftreeAddPlay(&sgftree
, gameinfo
->to_move
, I(move
), J(move
));
if (resignation_declined
)
sgftreeAddComment(&sgftree
, "GNU Go resignation was declined");
sgffile_output(&sgftree
);
gameinfo
->to_move
= OTHER_COLOR(gameinfo
->to_move
);
do_move(Gameinfo
* gameinfo
, char* command
, int* passes
, int force
)
int move
= string_to_location(board_size
, command
);
printf("\nInvalid move: %s\n", command
);
if (!is_allowed_move(move
, gameinfo
->to_move
)) {
printf("\nIllegal move: %s", command
);
TRACE("\nyour move: %1m\n\n", move
);
gnugo_play_move(move
, gameinfo
->to_move
);
sgffile_add_debuginfo(sgftree
.lastnode
, 0.0);
sgftreeAddPlay(&sgftree
, gameinfo
->to_move
, I(move
), J(move
));
sgffile_output(&sgftree
);
printf("GNU Go is thinking...\n");
gameinfo
->computer_player
= OTHER_COLOR(gameinfo
->computer_player
);
gameinfo
->to_move
= OTHER_COLOR(gameinfo
->to_move
);
sgftreeAddComment(&sgftree
, "forced");
gameinfo
->to_move
= OTHER_COLOR(gameinfo
->to_move
);
return computer_move(gameinfo
, passes
);
do_pass(Gameinfo
* gameinfo
, int* passes
, int force
)
gnugo_play_move(PASS_MOVE
, gameinfo
->to_move
);
sgffile_add_debuginfo(sgftree
.lastnode
, 0.0);
sgftreeAddPlay(&sgftree
, gameinfo
->to_move
, -1, -1);
sgffile_output(&sgftree
);
gameinfo
->to_move
= OTHER_COLOR(gameinfo
->to_move
);
gameinfo
->computer_player
= OTHER_COLOR(gameinfo
->computer_player
);
sgftreeAddComment(&sgftree
, "forced");
return computer_move(gameinfo
, passes
);
* Play a game against an ascii client.
void play_ascii(SGFTree
* tree
, Gameinfo
* gameinfo
, char* filename
, char* until
)
setvbuf(stdout
, (char*)NULL
, _IONBF
, 0); /* No buffering. */
/* No need to check for failure here since that was already done
* when it was loaded in main().
* FIXME: Why do we load the game again?
gameinfo_play_sgftree(gameinfo
, &sgftree
, until
);
if (sgfGetIntProperty(sgftree
.root
, "SZ", &sz
))
if (gameinfo
->handicap
== 0)
gameinfo
->to_move
= BLACK
;
gameinfo
->handicap
= place_fixed_handicap(gameinfo
->handicap
);
gameinfo
->to_move
= WHITE
;
printf("\nThanks! for playing GNU Go.\n\n");
/* main() frees the tree and we might have changed it. */
void do_play_ascii(Gameinfo
* gameinfo
)
int passes
= 0; /* two passes and its over */
if (have_time_settings())
/* No score is estimated yet. */
current_score_estimate
= NO_SCORE
;
/* Allow resignation at interface level (the engine may still be not
printf("\nBeginning ASCII mode game.\n\n");
gameinfo_print(gameinfo
);
/* Does the computer play first? If so, make a move. */
if (gameinfo
->computer_player
== gameinfo
->to_move
)
state
= computer_move(gameinfo
, &passes
);
/* main ASCII Play loop */
/* Display game board. */
mprintf("%s(%d): ", color_to_string(gameinfo
->to_move
), movenum
+ 1);
/* Read a line of input. */
if (!fgets(line
, 80, stdin
))
snprintf(line
, 79, "%s(%d): ",
color_to_string(gameinfo
->to_move
), movenum
+ 1);
if (!(line_ptr
= readline(line
)))
&& (command
= strtok(line_ptr
, ";"), line_ptr
= 0, command
)) {
/* Get the command or move. */
switch (get_command(command
)) {
state
= ascii_endgame(gameinfo
, 1);
opt_showboard
= !opt_showboard
;
gameinfo_print(gameinfo
);
printf("Boardsize cannot be changed after record is started!\n");
if (sscanf(command
, "%d", &num
) != 1) {
printf("\nInvalid command syntax!\n");
if (!check_boardsize(num
, stdout
))
/* In case max handicap changes on smaller board. */
gameinfo
->handicap
= place_fixed_handicap(gameinfo
->handicap
);
sgfOverwritePropertyInt(sgftree
.root
, "SZ", board_size
);
sgfOverwritePropertyInt(sgftree
.root
, "HA", gameinfo
->handicap
);
printf("Handicap cannot be changed after game is started!\n");
if (sscanf(command
, "%d", &num
) != 1) {
printf("\nInvalid command syntax!\n");
if (num
< 0 || num
> MAX_HANDICAP
) {
printf("\nInvalid handicap: %d\n", num
);
/* Place stones on board but don't record sgf
* in case we change more info. */
gameinfo
->handicap
= place_fixed_handicap(num
);
printf("\nSet handicap to %d\n", gameinfo
->handicap
);
gameinfo
->to_move
= (gameinfo
->handicap
? WHITE
: BLACK
);
printf("Handicap cannot be changed after game is started!\n");
while (*command
&& *command
!= ' ')
ascii_free_handicap(gameinfo
, command
);
printf("Komi cannot be modified after game record is started!\n");
if (sscanf(command
, "%f", &fnum
) != 1) {
printf("\nInvalid command syntax!\n");
printf("\nSet Komi to %.1f\n", komi
);
if (sscanf(command
, "%d", &num
) != 1) {
printf("\nInvalid command syntax!\n");
printf("\nSet depth to %d\n", mandated_depth
);
if (sscanf(command
, "%d", &num
) != 1) {
printf("\nInvalid command syntax!\n");
printf("\nSet level to %d\n", num
);
command
+= 6; /* skip the force part... */
switch (get_command(command
)) {
state
= do_move(gameinfo
, command
, &passes
, 1);
state
= do_pass(gameinfo
, &passes
, 1);
printf("Illegal forced move: %s %d\n", command
,
state
= do_move(gameinfo
, command
, &passes
, 0);
state
= do_pass(gameinfo
, &passes
, 0);
if (sscanf(command
, "%d", &num
) != 1) {
printf("\nInvalid command syntax!\n");
for (m
= 0; m
< num
; m
++) {
gameinfo
->computer_player
= OTHER_COLOR(gameinfo
->computer_player
);
state
= computer_move(gameinfo
, &passes
);
printf("\nInvalid number of moves specified: %d\n", num
);
if (gameinfo
->computer_player
== WHITE
)
gameinfo
->computer_player
= BLACK
;
if (gameinfo
->computer_player
== gameinfo
->to_move
)
state
= computer_move(gameinfo
, &passes
);
if (gameinfo
->computer_player
== BLACK
)
gameinfo
->computer_player
= WHITE
;
if (gameinfo
->computer_player
== gameinfo
->to_move
)
state
= computer_move(gameinfo
, &passes
);
gameinfo
->computer_player
= OTHER_COLOR(gameinfo
->computer_player
);
state
= computer_move(gameinfo
, &passes
);
sgftreeAddComment(&sgftree
, "undone");
gameinfo
->to_move
= OTHER_COLOR(gameinfo
->to_move
);
printf("\nCan't undo.\n");
if (sgftreeForward(&sgftree
))
gameinfo
->to_move
= gnugo_play_sgfnode(sgftree
.lastnode
,
printf("\nEnd of game tree.\n");
while (sgftreeForward(&sgftree
))
gameinfo
->to_move
= gnugo_play_sgfnode(sgftree
.lastnode
,
printf("\nEnter comment. Press ENTER when ready.\n");
sgftreeAddComment(&sgftree
, line
);
current_score_estimate
= NO_SCORE
;
silent_examine_position(FULL_EXAMINE_DRAGONS
);
showcapture(strtok(NULL
, " "));
showdefense(strtok(NULL
, " "));
printmoyo
= PRINTMOYO_MOYO
;
silent_examine_position(EXAMINE_DRAGONS
);
printmoyo
= PRINTMOYO_TERRITORY
;
silent_examine_position(EXAMINE_DRAGONS
);
printmoyo
= PRINTMOYO_AREA
;
silent_examine_position(EXAMINE_DRAGONS
);
silent_examine_position(EXAMINE_DRAGONS
);
ascii_goto(gameinfo
, strtok(NULL
, " "));
tmpstring
= strtok(NULL
, " ");
tmpstring
[strlen(tmpstring
) - 1] = 0;
/* make sure we are saving proper handicap */
writesgf(sgftree
.root
, tmpstring
);
printf("You may resume the game");
printf(" with -l %s --mode ascii\n", tmpstring
);
printf("or load %s\n", tmpstring
);
printf("Please specify filename\n");
tmpstring
= strtok(NULL
, " ");
tmpstring
[strlen(tmpstring
) - 1] = 0;
if (!sgftree_readfile(&sgftree
, tmpstring
)) {
fprintf(stderr
, "Cannot open or parse '%s'\n", tmpstring
);
/* to avoid changing handicap etc. */
if (gameinfo_play_sgftree(gameinfo
, &sgftree
, NULL
) == EMPTY
)
fprintf(stderr
, "Cannot load '%s'\n", tmpstring
);
sgfOverwritePropertyInt(sgftree
.root
, "HA", gameinfo
->handicap
);
printf("Please specify a filename\n");
silent_examine_position(EXAMINE_DRAGONS
);
printf("\nInvalid command: %s", command
);
state
= ascii_endgame(gameinfo
, 0);
sgffile_output(&sgftree
);
/* Play a different game next time. */
/* Free the sgf tree and prepare for a new game. */
sgfFreeNode(sgftree
.root
);
sgftreeCreateHeaderNode(&sgftree
, board_size
, komi
, gameinfo
->handicap
);
gameinfo_clear(gameinfo
);
/* Communicates with user after a game has ended. */
ascii_endgame(Gameinfo
* gameinfo
, int reason
)
if (reason
== 0) { /* Two passes, game is over. */
who_wins(gameinfo
->computer_player
, stdout
);
printf("\nIf you disagree, we may count the game together.\n");
sgftreeWriteResult(&sgftree
, (white_score
+ black_score
) / 2.0, 1);
int color
= OTHER_COLOR(gameinfo
->to_move
);
if (reason
== 1) /* Our opponent has resigned. */
printf("GNU Go wins by resignation.\n");
else /* We have resigned. */
printf("You win by resignation.\n");
printf("Result: %c+Resign\n\n", color
== WHITE
? 'W' : 'B');
sgftreeWriteResult(&sgftree
, color
== WHITE
? 1000.0 : -1000.0, 1);
printf("You may optionally save the game as an SGF file.\n\n");
printf("Type \"save <filename>\" to save,\n");
printf(" \"count\" to recount,\n");
printf(" \"continue\" to decline resignation and continue the game,\n");
printf(" \"quit\" to quit\n");
printf(" or \"game\" to play again\n");
if (!fgets(line
, 80, stdin
))
command
= strtok(line_ptr
, "");
switch (get_command(command
)) {
tmpstring
= strtok(NULL
, " ");
tmpstring
[strlen(tmpstring
) - 1] = 0;
writesgf(sgftree
.root
, tmpstring
);
printf("Please specify filename\n");
/* ascii_count() scores the game.
ascii_count(Gameinfo
* gameinfo
)
printf("\nGame over. Let's count!.\n");
printf("Dead stones are marked with small letters (x,o).\n");
printf("\nIf you don't agree, enter the location of a group\n");
printf("to toggle its state or \"done\".\n");
if (!fgets(line
, 12, stdin
))
return; /* EOF or some error */
line
[i
] = tolower((int)line
[i
]);
if (!strncmp(line
, "done", 4))
else if (!strncmp(line
, "quit", 4))
else if (!strncmp(line
, "xyzzy", 5)) {
printf("\nYou are in a debris room filled with stuff washed in from the\n");
printf("surface. A low wide passage with cobbles becomes plugged\n");
printf("with mud and debris here, but an awkward canyon leads\n");
printf("upward and west. A note on the wall says:\n");
printf(" Magic Word \"XYZZY\"\n\n");
printf("You are inside a building, a well house for a large spring.\n\n");
} else if (!strncmp(line
, "help", 4)) {
printf("\nIf there are dead stones on the board I will remove them.\n");
printf("You must tell me where they are. Type the coordinates of a\n");
printf("dead group, or type \"done\"\n");
} else if (!strncmp(line
, "undo", 4)) {
printf("UNDO not allowed anymore. The status of the stones now\n");
printf("toggles after entering the location of it.\n");
int pos
= string_to_location(board_size
, line
);
if (pos
== NO_MOVE
|| board
[pos
] == EMPTY
)
enum dragon_status status
= dragon_status(pos
);
status
= (status
== DEAD
) ? ALIVE
: DEAD
;
change_dragon_status(pos
, status
);
who_wins(gameinfo
->computer_player
, stdout
);
str
= string_to_location(board_size
, line
);
if (str
== NO_MOVE
|| board
[str
] == EMPTY
) {
printf("\ninvalid point!\n");
mprintf("\nSuccessful attack of %1m at %1m\n", str
, move
);
mprintf("\n%1m cannot be attacked\n", str
);
str
= string_to_location(board_size
, line
);
if (str
== NO_MOVE
|| board
[str
] == EMPTY
) {
printf("\ninvalid point!\n");
if (find_defense(str
, &move
))
mprintf("\nSuccessful defense of %1m at %1m\n", str
, move
);
mprintf("\n%1m cannot be defended\n", str
);
mprintf("\nThere is no need to defend %1m\n", str
);
ascii_goto(Gameinfo
* gameinfo
, char* line
)
const char* movenumber
= line
;
if (!strncmp(line
, "last", 4))
else if (!strncmp(line
, "first", 4))
printf("goto %s\n", movenumber
);
gameinfo_play_sgftree(gameinfo
, &sgftree
, movenumber
);
ascii_free_handicap(Gameinfo
* gameinfo
, char* handicap_string
)
int stones
[MAX_BOARD
* MAX_BOARD
];
if (sscanf(handicap_string
, "%d", &handi
) == 1) {
/* GNU Go is to place handicap */
if (handi
< 0 || handi
== 1) {
printf("\nInvalid command syntax!\n");
handi
= place_free_handicap(handi
);
printf("\nPlaced %d stones of free handicap.\n", handi
);
} else { /* User is to place handicap */
printf("\nType in coordinates of next handicap stone, or one of the following commands:\n");
printf(" undo take back the last stone placed\n");
printf(" clear remove all the stones placed so far\n");
printf(" done finish placing handicap\n\n");
printf("You have placed %d handicap stone(s) so far.\n\n", handi
);
if (!fgets(line
, 80, stdin
))
return; /* EOF or some error */
line
[i
] = tolower((int)line
[i
]);
if (!strncmp(line
, "undo", 4)) {
printf("\nNothing to undo.\n");
remove_stone(stones
[--handi
]);
gprintf("\nRemoved the stone at %m.\n", I(stones
[handi
]),
} else if (!strncmp(line
, "clear", 5)) {
} else if (!strncmp(line
, "done", 4)) {
if (handi
== 1) /* Don't bother with checks later */
printf("\nHandicap cannot be one stone. Either add "
"some more, or delete the only stone.\n");
int pos
= string_to_location(board_size
, line
);
printf("\nThere's already a stone there.\n");
printf("\nInvalid command: %s", line
);
gameinfo
->handicap
= handi
;
gameinfo
->to_move
= (handi
? WHITE
: BLACK
);