/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* 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. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
* This function underpins all the TRACE and DEBUG stuff.
* It accepts %c, %d, %f, %s, and %x as usual. But it
* also accepts %m, which takes TWO integers and writes a move.
* Other accepted formats are
* %C: Print a color as a string.
* Nasty bodge: %o at the start means outdent, i.e. cancel indent.
vgprintf(FILE *outputfile
, const char *fmt
, va_list ap
)
if (fmt
[0] == '%' && fmt
[1] == 'o')
fmt
+= 2; /* cancel indent */
fprintf(outputfile
, "%.*s", stackp
*2, " ");
/* rules of promotion => passed as int, not char */
fprintf(outputfile
, "%d", d
);
unsigned int d
= va_arg(ap
, unsigned int);
fprintf(outputfile
, "%x", d
);
double f
= va_arg(ap
, double); /* passed as double, not float */
fprintf(outputfile
, "%.2f", f
);
char *s
= va_arg(ap
, char *);
if (*fmt
!= 'm' && *fmt
!= 'M') {
fprintf(outputfile
, "\n\nUnknown format string '2%c'\n", *fmt
);
/* else fall through - 2 modifier on %m is default. */
fputs("PASS", outputfile
);
else if (!ON_BOARD2(m
, n
))
fprintf(outputfile
, "[%d,%d]", m
, n
);
/* Generate the move name. */
sprintf(movename
+1, "%d", board_size
- m
);
sprintf(movename
+1, "%-2d", board_size
- m
);
fputs(movename
, outputfile
);
if (*fmt
!= 'm' && *fmt
!= 'M') {
fprintf(outputfile
, "\n\nUnknown format string '1%c'\n", *fmt
);
int pos
= va_arg(ap
, int);
fputs("PASS", outputfile
);
else if (!ON_BOARD1(pos
))
fprintf(outputfile
, "[%d]", pos
);
/* Generate the move name. */
sprintf(movename
+ 1, "%d", board_size
- m
);
sprintf(movename
+ 1, "%-2d", board_size
- m
);
fputs(movename
, outputfile
);
unsigned long h
= va_arg(ap
, unsigned long);
fprintf(outputfile
, "%lx", h
);
int color
= va_arg(ap
, int);
fputs(color_to_string(color
), outputfile
);
fprintf(outputfile
, "\n\nUnknown format character '%c'\n", *fmt
);
* required wrapper around vgprintf, writes to outfile.
gfprintf(FILE *outfile
, const char *fmt
, ...)
vgprintf(outfile
, fmt
, ap
);
* required wrapper around vgprintf, writes to stderr.
* Always returns 1 to allow use in short-circuit logical expressions.
gprintf(const char *fmt
, ...)
vgprintf(stderr
, fmt
, ap
);
* required wrapper around vgprintf, in contrast to gprintf this one
mprintf(const char *fmt
, ...)
vgprintf(stdout
, fmt
, ap
);
/* This writes the move history information in sgf format to stderr.
* This is only intended as a stand-alone debug tool for use in
* abortgo(). Anywhere else you should use the normal sgf library.
int initial_colors_found
= EMPTY
;
for (pos
= BOARDMIN
; pos
< BOARDMAX
; pos
++)
initial_colors_found
|= initial_board
[pos
];
fprintf(stderr
, "(;GM[1]FF[4]SZ[%d]KM[%.1f]HA[%d]GN[GNU Go %s stepped on a bug]\n",
board_size
, komi
, handicap
, gg_version());
for (color
= WHITE
; color
<= BLACK
; color
++) {
if (initial_colors_found
& color
) {
fprintf(stderr
, "A%s", color
== WHITE
? "W" : "B");
for (k
= 0, pos
= BOARDMIN
; pos
< BOARDMAX
; pos
++) {
if (ON_BOARD(pos
) && initial_board
[pos
] == color
) {
fprintf(stderr
, "[%c%c]", 'a' + J(pos
), 'a' + I(pos
));
if (move_history_pointer
> 0) {
for (k
= 0; k
< move_history_pointer
; k
++) {
fprintf(stderr
, ";%s", move_history_color
[k
] == WHITE
? "W" : "B");
if (move_history_pos
[k
] == PASS_MOVE
)
fprintf(stderr
, "[%c%c]", 'a' + J(move_history_pos
[k
]),
'a' + I(move_history_pos
[k
]));
* A wrapper around abort() which shows the state variables at the time
* of the problem. (pos) is typically a related move, or NO_MOVE.
abortgo(const char *file
, int line
, const char *msg
, int pos
)
gprintf("%o\n\n***assertion failure:\n%s:%d - %s near %1m***\n\n",
/* Print the board at the top of the stack. */
simple_showboard(stderr
);
fprintf(stderr
, "gnugo %s (seed %d): You stepped on a bug.\n",
gg_version(), get_random_seed());
if (board_size
>= 9 && board_size
<= 19) {
Please mail this message, including the debug output above, \
abort(); /* cause core dump */
static const char *color_names
[] = {
/* Convert a color value to a string. */
color_to_string(int color
)
gg_assert(color
< NUM_KOMASTER_STATES
);
return color_names
[color
];
/* Convert a location to a string. */
location_to_string(int pos
)
static char buf
[BOARDSIZE
][5];
for (pos
= 0; pos
< BOARDSIZE
; pos
++)
location_to_buffer(pos
, buf
[pos
]);
ASSERT1(pos
>= 0 && pos
< BOARDSIZE
, pos
);
/* Convert a location to a string, writing to a buffer. */
location_to_buffer(int pos
, char *buf
)
* Convert the string str to a 1D coordinate. Return NO_MOVE if invalid
string_to_location(int boardsize
, const char *str
)
if (!isalpha((int) *str
))
n
= tolower((int) *str
) - 'a';
if (tolower((int) *str
) >= 'i')
if (n
< 0 || n
> boardsize
- 1)
if (!isdigit((int) *(str
+ 1)))
m
= boardsize
- atoi(str
+ 1);
if (m
< 0 || m
> boardsize
- 1)
/* Some simple functions to draw an ASCII board. */
/* True if the coordinate is a hoshi point. */
is_hoshi_point(int m
, int n
)
/* No hoshi points on these boards. */
if (board_size
== 2 || board_size
== 4)
/* In the middle of a 3x3 board. */
if (m
== 1 && (n
== 1 || n
== 3))
if (m
== 3 && (n
== 1 || n
== 3))
/* 3-3 points are hoshi on sizes 7--11, 4-4 on larger. */
/* Coordinate for midpoint. */
/* Normalize the coordinates by mirroring to the lower numbers. */
/* Is this a corner hoshi? */
if (m
== hoshi
&& n
== hoshi
)
/* If even sized board, only hoshi points in the corner. */
/* Less than 12 in board size only middle point. */
if (m
== middle
&& n
== middle
)
/* Is this a midpoint hoshi? */
if ((m
== hoshi
|| m
== middle
)
&& (n
== hoshi
|| n
== middle
))
/* Print a line with coordinate letters above the board. */
draw_letter_coordinates(FILE *outfile
)
for (i
= 0, ch
= 'A'; i
< board_size
; i
++, ch
++) {
fprintf(outfile
, " %c", ch
);
/* Bare bones version of showboard(0). No fancy options, no hint of
* color, and you can choose where to write it.
simple_showboard(FILE *outfile
)
draw_letter_coordinates(outfile
);
for (i
= 0; i
< board_size
; i
++) {
fprintf(outfile
, "\n%2d", board_size
- i
);
for (j
= 0; j
< board_size
; j
++) {
if (BOARD(i
, j
) == EMPTY
)
fprintf(outfile
, " %c", is_hoshi_point(i
, j
) ? '+' : '.');
fprintf(outfile
, " %c", BOARD(i
, j
) == BLACK
? 'X' : 'O');
fprintf(outfile
, " %d", board_size
- i
);
if ((board_size
< 10 && i
== board_size
-2)
|| (board_size
>= 10 && i
== 8))
fprintf(outfile
, " WHITE (O) has captured %d stones", black_captured
);
if ((board_size
< 10 && i
== board_size
-1)
|| (board_size
>= 10 && i
== 9))
fprintf(outfile
, " BLACK (X) has captured %d stones", white_captured
);
draw_letter_coordinates(outfile
);
/* Adds square marks for each goal intersecion in the current sgf_dumptree.
* This function cannot be in sgf/ as it has to understand the 1-D board.
mark_goal_in_sgf(signed char goal
[BOARDMAX
])
node
= sgftreeNodeCheck(sgf_dumptree
);
for (pos
= BOARDMIN
; pos
< BOARDMAX
; pos
++)
if (ON_BOARD(pos
) && goal
[pos
])
sgfSquare(node
, I(pos
), J(pos
));