1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2  * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see       *
3  * http://www.gnu.org/software/gnugo/ for more information.          *
4  *                                                                   *
5  * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,   *
6  * 2008 and 2009 by the Free Software Foundation.                    *
7  *                                                                   *
8  * This program is free software; you can redistribute it and/or     *
9  * modify it under the terms of the GNU General Public License as    *
10  * published by the Free Software Foundation - version 3 or          *
11  * (at your option) any later version.                               *
12  *                                                                   *
13  * This program is distributed in the hope that it will be useful,   *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *
16  * GNU General Public License in file COPYING for more details.      *
17  *                                                                   *
18  * You should have received a copy of the GNU General Public         *
19  * License along with this program; if not, write to the Free        *
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       *
21  * Boston, MA 02111, USA.                                            *
22 \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23 
24 /*-------------------------------------------------------------
25   showbord.c -- Show current go board and playing information
26 -------------------------------------------------------------*/
27 
28 /*
29  * NOTE : this is no longer intended as the main user interface
30  * as it was in GNU Go 1.2. It is now a debugging aid, showing
31  * the internal state of dragons, and things. But with
32  * color enabled, it should be easy enough to see the state
33  * of play at a glance.
34  *
35  * Note : the dragons must have been calculated before this is called
36  */
37 
38 #include "gnugo.h"
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include "liberty.h"
45 #include "gg_utils.h"
46 
47 
48 /*
49  * Stuff to enumerate the dragons
50  */
51 
52 /* Element at origin of each worm stores allocated worm number. */
53 static unsigned char dragon_num[BOARDMAX];
54 
55 static int next_white;		/* next worm number to allocate */
56 static int next_black;
57 
58 /* linux console :
59  *  0=black
60  *  1=red             [critical]
61  *  2=green           [alive]
62  *  3=yellow/brown    [unknown]
63  *  4=blue
64  *  5=magenta
65  *  6=cyan            [dead]
66  *  7=white           [unchecked]
67  */
68 
69 /* Both black and white are common background colors and should be
70  * avoided.
71  */
72 static const int colors[3][5] = {
73   {0, 0, 0, 0, 0}, /*not used */
74   {6, 2, 1, 3, 5}, /* WHITE : dead, alive, critical, unknown, unchecked */
75   {6, 2, 1, 3, 5}  /* BLACK : dead, alive, critical, unknown, unchecked */
76 };
77 
78 static const int domain_colors[4] = {5, 1, 2, 3}; /* gray, black, white, both */
79 
80 
81 /* The following four functions define an API for drawing boards. The
82  * typical use would be along the following lines:
83  *
84  * start_draw_board();
85  * for (m = 0; m < board_size; m++)
86  *   for (n = 0; n < board_size; n++) {
87  *     int color = ...;
88  *     int c = ...;
89  *     draw_color_char(m, n, c, color);
90  *   }
91  * end_draw_board();
92  *
93  * Coordinate system, hoshi points, and linefeeds are written
94  * automatically by the board drawing functions. The coordinates m, n
95  * must be ordered as in the full loops above.
96  *
97  */
98 
99 /* Init color and print a line with coordinate letters above the board. */
100 void
start_draw_board()101 start_draw_board()
102 {
103   gg_init_color();
104   draw_letter_coordinates(stderr);
105 }
106 
107 /* Draw a colored character. If c has the value EMPTY, either a "." or
108  * a "+" is drawn, depending on whether it is a hoshi stone. If this
109  * is the first or last intersection on a line, the coordinate number
110  * is also drawn.
111  */
112 void
draw_color_char(int m,int n,int c,int color)113 draw_color_char(int m, int n, int c, int color)
114 {
115   /* Is this the first column? */
116   if (n == 0)
117     fprintf(stderr, "\n%2d", board_size - m);
118 
119   /* Do we see a hoshi point? */
120   if (c == EMPTY) {
121     if (is_hoshi_point(m, n))
122       c = '+';
123     else
124       c = '.';
125   }
126 
127   /* Use fprintf to draw black characters. This way they'll turn out
128    * white on terminals with black background.
129    */
130   if (color == GG_COLOR_BLACK)
131     fprintf(stderr, " %c", c);
132   else
133     write_color_char(color, c);
134 
135   /* Is this the last column? */
136   if (n == board_size - 1)
137     fprintf(stderr, " %-2d", board_size - m);
138 }
139 
140 /* Draw a black character as specified above. */
141 void
draw_char(int m,int n,int c)142 draw_char(int m, int n, int c)
143 {
144   draw_color_char(m, n, c, GG_COLOR_BLACK);
145 }
146 
147 /* Print a line with coordinate letters under the board. */
148 void
end_draw_board()149 end_draw_board()
150 {
151   fprintf(stderr, "\n");
152   draw_letter_coordinates(stderr);
153   fprintf(stderr, "\n");
154 }
155 
156 
157 /*
158  * Write one stone. Use 'empty' if the board is empty ('-' or '+')
159  * We use capital letters A,B,... for black, lower case a,b,... for white.
160  * This allows us to indicate up to 26 dragons uniquely, and more with
161  * low risk of ambiguity.
162  */
163 
164 /* The variable xo=1 if running gnugo -T, 2 if running gnugo -E, or
165  * 3 if displaying owl_status.
166  */
167 
168 static void
showchar(int i,int j,int empty,int xo)169 showchar(int i, int j, int empty, int xo)
170 {
171   struct dragon_data *d;  /* dragon data at (i, j) */
172   struct dragon_data2 *d2;
173   int x;
174   ASSERT_ON_BOARD2(i, j);
175   x = BOARD(i, j);
176   d = &(dragon[POS(i, j)]);
177   d2 = &(dragon2[d->id]);
178 
179   if (x == EMPTY) {
180     if (xo != 2)
181       fprintf(stderr, " %c", empty);
182     else {
183       int empty_color;
184       char empty_char;
185 
186       if (black_eye[POS(i, j)].color == BLACK) {
187 	if (white_eye[POS(i, j)].color == WHITE)
188 	  empty_color = domain_colors[3];
189 	else
190 	  empty_color = domain_colors[1];
191 
192 	if (black_eye[POS(i, j)].marginal)
193 	  empty_char = '!';
194 	else
195 	  empty_char = 'x';
196       }
197       else if (white_eye[POS(i, j)].color == WHITE) {
198 	empty_color = domain_colors[2];
199 	if (white_eye[POS(i, j)].marginal)
200 	  empty_char = '!';
201 	else
202 	  empty_char = 'o';
203       }
204       else {
205 	empty_color = domain_colors[0];
206 	empty_char = '.';
207       }
208 
209       write_color_char(empty_color, empty_char);
210     }
211   }
212   else {
213     int w;
214 
215     if (xo == 0 || ! ON_BOARD1(d->origin)) {
216       fprintf(stderr, " %c", BOARD(i, j) == BLACK ? 'X' : 'O');
217       return;
218     }
219 
220     /* Figure out ascii character for this dragon. This is the
221      * dragon number allocated to the origin of this worm. */
222 
223     w = dragon_num[d->origin];
224     if (!w) {
225       /* Not yet allocated - allocate next one. */
226       /* Count upwards for black, downwards for white to reduce confusion. */
227       if (BOARD(i, j) == BLACK)
228 	w = dragon_num[d->origin] = next_black++;
229       else
230 	w = dragon_num[d->origin] = next_white--;
231     }
232 
233     w = w%26 + (BOARD(i, j) == BLACK ? 'A' : 'a');
234 
235     /* Now draw it. */
236     if (xo == 1)
237       write_color_char(colors[BOARD(i, j)][d->crude_status], w);
238     else if (xo == 2) {
239       if (BOARD(i, j) == BLACK)
240 	write_color_char(domain_colors[1], 'X');
241       else
242 	write_color_char(domain_colors[2], 'O');
243     }
244     else if (xo == 3)
245       write_color_char(colors[BOARD(i, j)][d2->owl_status], w);
246     else if (xo == 4)
247       write_color_char(colors[BOARD(i, j)][d->status], w);
248   }
249 }
250 
251 
252 
253 
254 /*
255  * Show go board.
256  *
257  * xo=0:      black and white XO board for ascii game
258  * xo=1:      colored dragon display
259  * xo=2:      colored eye display
260  * xo=3:      colored owl display
261  * xo=4:      colored matcher status display
262  *
263  */
264 
265 void
showboard(int xo)266 showboard(int xo)
267 {
268   int i, j, ii;
269   gg_init_color();
270 
271   /* Set all dragon numbers to 0. */
272   memset(dragon_num, 0, sizeof(dragon_num));
273 
274   next_white = (259 - 26);
275   next_black = 26;
276 
277   start_draw_board();
278 
279   for (i = 0; i < board_size; i++) {
280     ii = board_size - i;
281     fprintf(stderr, "\n%2d", ii);
282 
283     for (j = 0; j < board_size; j++)
284       showchar(i, j, is_hoshi_point(i, j) ? '+' : '.', xo);
285 
286     fprintf(stderr, " %d", ii);
287 
288     if (xo == 0 && ((board_size < 10 && i == board_size-2)
289 		    || (board_size >= 10 && i == 8)))
290       fprintf(stderr, "     WHITE (O) has captured %d stones", black_captured);
291 
292     if (xo == 0 && ((board_size < 10 && i == board_size-1)
293 		    || (board_size >= 10 && i == 9)))
294       fprintf(stderr, "     BLACK (X) has captured %d stones", white_captured);
295 
296     if (xo == 3) {
297       if (i == board_size-5)
298 	write_color_string(GG_COLOR_GREEN, "    green=alive");
299       if (i == board_size-4)
300 	write_color_string(GG_COLOR_CYAN, "    cyan=dead");
301       if (i == board_size-3)
302 	write_color_string(GG_COLOR_RED, "    red=critical");
303       if (i == board_size-2)
304 	write_color_string(GG_COLOR_YELLOW, "    yellow=unknown");
305       if (i == board_size-1)
306 	write_color_string(GG_COLOR_MAGENTA, "    magenta=unchecked");
307     }
308   }
309 
310   end_draw_board();
311 }
312 
313 
314 /* Some print utility function that don't really have a better place
315  * in the engine code than here.
316  */
317 
318 static const char *status_names[] = {
319   DRAGON_STATUS_NAMES
320 };
321 
322 /* Convert a status value to a string. */
323 const char *
status_to_string(enum dragon_status status)324 status_to_string(enum dragon_status status)
325 {
326   return status_names[(int) status];
327 }
328 
329 
330 /* Convert a read result to a string */
331 const char *
result_to_string(int result)332 result_to_string(int result)
333 {
334   switch (result) {
335   case 0:             return "0";
336   case KO_B:          return "KO_B";
337   case LOSS:          return "LOSS";
338   case GAIN:          return "GAIN";
339   case KO_A:          return "KO_A";
340   case WIN:           return "WIN";
341 
342   default:            return "ERROR";
343   }
344 }
345 
346 
347 #ifndef HAVE_VARIADIC_DEFINE
348 
349 /* See gnugo.h for related TRACE family macro definitions */
350 
351 /* Always returns 1 to allow use in short-circuit logical expressions. */
352 int
DEBUG_func(int flag,const char * fmt,...)353 DEBUG_func(int flag, const char *fmt, ...)
354 {
355   if (debug & flag) {
356     va_list ap;
357     va_start(ap, fmt);
358     vgprintf(stderr, fmt, ap);
359     va_end(ap);
360   }
361 
362   return 1;
363 }
364 
365 #endif /*HAVE_VARIADIC_DEFINE*/
366 
367 
368 
369 /*
370  * Local Variables:
371  * tab-width: 8
372  * c-basic-offset: 2
373  * End:
374  */
375