375 lines
9.7 KiB
C
375 lines
9.7 KiB
C
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
||
|
* 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. *
|
||
|
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
/*-------------------------------------------------------------
|
||
|
showbord.c -- Show current go board and playing information
|
||
|
-------------------------------------------------------------*/
|
||
|
|
||
|
/*
|
||
|
* NOTE : this is no longer intended as the main user interface
|
||
|
* as it was in GNU Go 1.2. It is now a debugging aid, showing
|
||
|
* the internal state of dragons, and things. But with
|
||
|
* color enabled, it should be easy enough to see the state
|
||
|
* of play at a glance.
|
||
|
*
|
||
|
* Note : the dragons must have been calculated before this is called
|
||
|
*/
|
||
|
|
||
|
#include "gnugo.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "liberty.h"
|
||
|
#include "gg_utils.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Stuff to enumerate the dragons
|
||
|
*/
|
||
|
|
||
|
/* Element at origin of each worm stores allocated worm number. */
|
||
|
static unsigned char dragon_num[BOARDMAX];
|
||
|
|
||
|
static int next_white; /* next worm number to allocate */
|
||
|
static int next_black;
|
||
|
|
||
|
/* linux console :
|
||
|
* 0=black
|
||
|
* 1=red [critical]
|
||
|
* 2=green [alive]
|
||
|
* 3=yellow/brown [unknown]
|
||
|
* 4=blue
|
||
|
* 5=magenta
|
||
|
* 6=cyan [dead]
|
||
|
* 7=white [unchecked]
|
||
|
*/
|
||
|
|
||
|
/* Both black and white are common background colors and should be
|
||
|
* avoided.
|
||
|
*/
|
||
|
static const int colors[3][5] = {
|
||
|
{0, 0, 0, 0, 0}, /*not used */
|
||
|
{6, 2, 1, 3, 5}, /* WHITE : dead, alive, critical, unknown, unchecked */
|
||
|
{6, 2, 1, 3, 5} /* BLACK : dead, alive, critical, unknown, unchecked */
|
||
|
};
|
||
|
|
||
|
static const int domain_colors[4] = {5, 1, 2, 3}; /* gray, black, white, both */
|
||
|
|
||
|
|
||
|
/* The following four functions define an API for drawing boards. The
|
||
|
* typical use would be along the following lines:
|
||
|
*
|
||
|
* start_draw_board();
|
||
|
* for (m = 0; m < board_size; m++)
|
||
|
* for (n = 0; n < board_size; n++) {
|
||
|
* int color = ...;
|
||
|
* int c = ...;
|
||
|
* draw_color_char(m, n, c, color);
|
||
|
* }
|
||
|
* end_draw_board();
|
||
|
*
|
||
|
* Coordinate system, hoshi points, and linefeeds are written
|
||
|
* automatically by the board drawing functions. The coordinates m, n
|
||
|
* must be ordered as in the full loops above.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/* Init color and print a line with coordinate letters above the board. */
|
||
|
void
|
||
|
start_draw_board()
|
||
|
{
|
||
|
gg_init_color();
|
||
|
draw_letter_coordinates(stderr);
|
||
|
}
|
||
|
|
||
|
/* Draw a colored character. If c has the value EMPTY, either a "." or
|
||
|
* a "+" is drawn, depending on whether it is a hoshi stone. If this
|
||
|
* is the first or last intersection on a line, the coordinate number
|
||
|
* is also drawn.
|
||
|
*/
|
||
|
void
|
||
|
draw_color_char(int m, int n, int c, int color)
|
||
|
{
|
||
|
/* Is this the first column? */
|
||
|
if (n == 0)
|
||
|
fprintf(stderr, "\n%2d", board_size - m);
|
||
|
|
||
|
/* Do we see a hoshi point? */
|
||
|
if (c == EMPTY) {
|
||
|
if (is_hoshi_point(m, n))
|
||
|
c = '+';
|
||
|
else
|
||
|
c = '.';
|
||
|
}
|
||
|
|
||
|
/* Use fprintf to draw black characters. This way they'll turn out
|
||
|
* white on terminals with black background.
|
||
|
*/
|
||
|
if (color == GG_COLOR_BLACK)
|
||
|
fprintf(stderr, " %c", c);
|
||
|
else
|
||
|
write_color_char(color, c);
|
||
|
|
||
|
/* Is this the last column? */
|
||
|
if (n == board_size - 1)
|
||
|
fprintf(stderr, " %-2d", board_size - m);
|
||
|
}
|
||
|
|
||
|
/* Draw a black character as specified above. */
|
||
|
void
|
||
|
draw_char(int m, int n, int c)
|
||
|
{
|
||
|
draw_color_char(m, n, c, GG_COLOR_BLACK);
|
||
|
}
|
||
|
|
||
|
/* Print a line with coordinate letters under the board. */
|
||
|
void
|
||
|
end_draw_board()
|
||
|
{
|
||
|
fprintf(stderr, "\n");
|
||
|
draw_letter_coordinates(stderr);
|
||
|
fprintf(stderr, "\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Write one stone. Use 'empty' if the board is empty ('-' or '+')
|
||
|
* We use capital letters A,B,... for black, lower case a,b,... for white.
|
||
|
* This allows us to indicate up to 26 dragons uniquely, and more with
|
||
|
* low risk of ambiguity.
|
||
|
*/
|
||
|
|
||
|
/* The variable xo=1 if running gnugo -T, 2 if running gnugo -E, or
|
||
|
* 3 if displaying owl_status.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
showchar(int i, int j, int empty, int xo)
|
||
|
{
|
||
|
struct dragon_data *d; /* dragon data at (i, j) */
|
||
|
struct dragon_data2 *d2;
|
||
|
int x;
|
||
|
ASSERT_ON_BOARD2(i, j);
|
||
|
x = BOARD(i, j);
|
||
|
d = &(dragon[POS(i, j)]);
|
||
|
d2 = &(dragon2[d->id]);
|
||
|
|
||
|
if (x == EMPTY) {
|
||
|
if (xo != 2)
|
||
|
fprintf(stderr, " %c", empty);
|
||
|
else {
|
||
|
int empty_color;
|
||
|
char empty_char;
|
||
|
|
||
|
if (black_eye[POS(i, j)].color == BLACK) {
|
||
|
if (white_eye[POS(i, j)].color == WHITE)
|
||
|
empty_color = domain_colors[3];
|
||
|
else
|
||
|
empty_color = domain_colors[1];
|
||
|
|
||
|
if (black_eye[POS(i, j)].marginal)
|
||
|
empty_char = '!';
|
||
|
else
|
||
|
empty_char = 'x';
|
||
|
}
|
||
|
else if (white_eye[POS(i, j)].color == WHITE) {
|
||
|
empty_color = domain_colors[2];
|
||
|
if (white_eye[POS(i, j)].marginal)
|
||
|
empty_char = '!';
|
||
|
else
|
||
|
empty_char = 'o';
|
||
|
}
|
||
|
else {
|
||
|
empty_color = domain_colors[0];
|
||
|
empty_char = '.';
|
||
|
}
|
||
|
|
||
|
write_color_char(empty_color, empty_char);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
int w;
|
||
|
|
||
|
if (xo == 0 || ! ON_BOARD1(d->origin)) {
|
||
|
fprintf(stderr, " %c", BOARD(i, j) == BLACK ? 'X' : 'O');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Figure out ascii character for this dragon. This is the
|
||
|
* dragon number allocated to the origin of this worm. */
|
||
|
|
||
|
w = dragon_num[d->origin];
|
||
|
if (!w) {
|
||
|
/* Not yet allocated - allocate next one. */
|
||
|
/* Count upwards for black, downwards for white to reduce confusion. */
|
||
|
if (BOARD(i, j) == BLACK)
|
||
|
w = dragon_num[d->origin] = next_black++;
|
||
|
else
|
||
|
w = dragon_num[d->origin] = next_white--;
|
||
|
}
|
||
|
|
||
|
w = w%26 + (BOARD(i, j) == BLACK ? 'A' : 'a');
|
||
|
|
||
|
/* Now draw it. */
|
||
|
if (xo == 1)
|
||
|
write_color_char(colors[BOARD(i, j)][d->crude_status], w);
|
||
|
else if (xo == 2) {
|
||
|
if (BOARD(i, j) == BLACK)
|
||
|
write_color_char(domain_colors[1], 'X');
|
||
|
else
|
||
|
write_color_char(domain_colors[2], 'O');
|
||
|
}
|
||
|
else if (xo == 3)
|
||
|
write_color_char(colors[BOARD(i, j)][d2->owl_status], w);
|
||
|
else if (xo == 4)
|
||
|
write_color_char(colors[BOARD(i, j)][d->status], w);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Show go board.
|
||
|
*
|
||
|
* xo=0: black and white XO board for ascii game
|
||
|
* xo=1: colored dragon display
|
||
|
* xo=2: colored eye display
|
||
|
* xo=3: colored owl display
|
||
|
* xo=4: colored matcher status display
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
showboard(int xo)
|
||
|
{
|
||
|
int i, j, ii;
|
||
|
gg_init_color();
|
||
|
|
||
|
/* Set all dragon numbers to 0. */
|
||
|
memset(dragon_num, 0, sizeof(dragon_num));
|
||
|
|
||
|
next_white = (259 - 26);
|
||
|
next_black = 26;
|
||
|
|
||
|
start_draw_board();
|
||
|
|
||
|
for (i = 0; i < board_size; i++) {
|
||
|
ii = board_size - i;
|
||
|
fprintf(stderr, "\n%2d", ii);
|
||
|
|
||
|
for (j = 0; j < board_size; j++)
|
||
|
showchar(i, j, is_hoshi_point(i, j) ? '+' : '.', xo);
|
||
|
|
||
|
fprintf(stderr, " %d", ii);
|
||
|
|
||
|
if (xo == 0 && ((board_size < 10 && i == board_size-2)
|
||
|
|| (board_size >= 10 && i == 8)))
|
||
|
fprintf(stderr, " WHITE (O) has captured %d stones", black_captured);
|
||
|
|
||
|
if (xo == 0 && ((board_size < 10 && i == board_size-1)
|
||
|
|| (board_size >= 10 && i == 9)))
|
||
|
fprintf(stderr, " BLACK (X) has captured %d stones", white_captured);
|
||
|
|
||
|
if (xo == 3) {
|
||
|
if (i == board_size-5)
|
||
|
write_color_string(GG_COLOR_GREEN, " green=alive");
|
||
|
if (i == board_size-4)
|
||
|
write_color_string(GG_COLOR_CYAN, " cyan=dead");
|
||
|
if (i == board_size-3)
|
||
|
write_color_string(GG_COLOR_RED, " red=critical");
|
||
|
if (i == board_size-2)
|
||
|
write_color_string(GG_COLOR_YELLOW, " yellow=unknown");
|
||
|
if (i == board_size-1)
|
||
|
write_color_string(GG_COLOR_MAGENTA, " magenta=unchecked");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
end_draw_board();
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Some print utility function that don't really have a better place
|
||
|
* in the engine code than here.
|
||
|
*/
|
||
|
|
||
|
static const char *status_names[] = {
|
||
|
DRAGON_STATUS_NAMES
|
||
|
};
|
||
|
|
||
|
/* Convert a status value to a string. */
|
||
|
const char *
|
||
|
status_to_string(enum dragon_status status)
|
||
|
{
|
||
|
return status_names[(int) status];
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Convert a read result to a string */
|
||
|
const char *
|
||
|
result_to_string(int result)
|
||
|
{
|
||
|
switch (result) {
|
||
|
case 0: return "0";
|
||
|
case KO_B: return "KO_B";
|
||
|
case LOSS: return "LOSS";
|
||
|
case GAIN: return "GAIN";
|
||
|
case KO_A: return "KO_A";
|
||
|
case WIN: return "WIN";
|
||
|
|
||
|
default: return "ERROR";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef HAVE_VARIADIC_DEFINE
|
||
|
|
||
|
/* See gnugo.h for related TRACE family macro definitions */
|
||
|
|
||
|
/* Always returns 1 to allow use in short-circuit logical expressions. */
|
||
|
int
|
||
|
DEBUG_func(int flag, const char *fmt, ...)
|
||
|
{
|
||
|
if (debug & flag) {
|
||
|
va_list ap;
|
||
|
va_start(ap, fmt);
|
||
|
vgprintf(stderr, fmt, ap);
|
||
|
va_end(ap);
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
#endif /*HAVE_VARIADIC_DEFINE*/
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Local Variables:
|
||
|
* tab-width: 8
|
||
|
* c-basic-offset: 2
|
||
|
* End:
|
||
|
*/
|