summaryrefslogtreecommitdiff
path: root/apps/plugins/goban/board.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/goban/board.c')
-rw-r--r--apps/plugins/goban/board.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/apps/plugins/goban/board.c b/apps/plugins/goban/board.c
new file mode 100644
index 0000000000..bc6c5347dc
--- /dev/null
+++ b/apps/plugins/goban/board.c
@@ -0,0 +1,354 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007-2009 Joshua Simmons <mud at majidejima dot com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "goban.h"
23#include "board.h"
24#include "display.h"
25#include "types.h"
26#include "game.h"
27#include "util.h"
28
29#include "plugin.h"
30
31unsigned int board_width = MAX_BOARD_SIZE;
32unsigned int board_height = MAX_BOARD_SIZE;
33
34/* Board has 'invalid' markers around each border */
35unsigned char board_data[(MAX_BOARD_SIZE + 2) * (MAX_BOARD_SIZE + 2)];
36int white_captures = 0;
37int black_captures = 0;
38
39uint8_t board_marks[(MAX_BOARD_SIZE + 2) * (MAX_BOARD_SIZE + 2)];
40uint8_t current_mark = 255;
41
42/* there can't be any changes off of the board, so no need to add the
43 borders */
44uint8_t board_changes[MAX_BOARD_SIZE * MAX_BOARD_SIZE];
45
46unsigned short ko_pos = INVALID_POS;
47
48/* forward declarations */
49static void setup_marks (void);
50static void make_mark (unsigned short pos);
51static int get_liberties_helper (unsigned short pos, unsigned char orig_color);
52static int flood_fill_helper (unsigned short pos, unsigned char orig_color,
53 unsigned char color);
54
55
56/* these aren't "board marks" in the marks on the SGF sense, they are used
57 internally to mark already visited points and the like (such as when
58 doing liberty counting for groups) */
59static void
60setup_marks (void)
61{
62 unsigned int x, y;
63
64 current_mark++;
65
66 if (current_mark == 0)
67 {
68 current_mark++;
69
70 for (y = 0; y < board_height; ++y)
71 {
72 for (x = 0; x < board_width; ++x)
73 {
74 board_marks[POS (x, y)] = 0;
75 }
76 }
77 }
78}
79
80static void
81make_mark (unsigned short pos)
82{
83 board_marks[pos] = current_mark;
84}
85
86static bool
87is_marked (unsigned short pos)
88{
89 return board_marks[pos] == current_mark;
90}
91
92void
93clear_board (void)
94{
95 unsigned int i, x, y;
96
97 /* for the borders */
98 for (i = 0; i < (2 + MAX_BOARD_SIZE) * (2 + MAX_BOARD_SIZE); ++i)
99 {
100 board_data[i] = INVALID;
101 }
102
103 /* now make the actual board part */
104 for (y = 0; y < board_height; ++y)
105 {
106 for (x = 0; x < board_width; ++x)
107 {
108 board_data[POS (x, y)] = EMPTY;
109 }
110 }
111
112 white_captures = 0;
113 black_captures = 0;
114
115 ko_pos = INVALID_POS;
116}
117
118bool
119set_size_board (int width, int height)
120{
121 if (width < MIN_BOARD_SIZE || width > MAX_BOARD_SIZE ||
122 height < MIN_BOARD_SIZE || height > MAX_BOARD_SIZE)
123 {
124 return false;
125 }
126 else
127 {
128 board_width = width;
129 board_height = height;
130 setup_display ();
131 return true;
132 }
133}
134
135unsigned char
136get_point_board (unsigned short pos)
137{
138 return board_data[pos];
139}
140
141void
142set_point_board (unsigned short pos, unsigned char color)
143{
144 board_data[pos] = color;
145}
146
147bool
148on_board (unsigned short pos)
149{
150 if (pos < POS (0, 0) ||
151 pos > POS (board_width - 1, board_height - 1) ||
152 get_point_board (pos) == INVALID)
153 {
154 return false;
155 }
156 else
157 {
158 return true;
159 }
160}
161
162int
163get_liberties_board (unsigned short pos)
164{
165 if (!on_board (pos) || get_point_board (pos) == EMPTY)
166 {
167 return -1;
168 }
169
170 setup_marks ();
171
172 int ret_val = 0;
173 unsigned char orig_color = get_point_board (pos);
174
175 empty_stack (&parse_stack);
176 push_pos_stack (&parse_stack, pos);
177
178 /* Since we only ever test for liberties in order to determine
179 captures and the like, there's no reason to count any liberties
180 higher than 2 (we sometimes need to know if something has 1 liberty
181 for dealing with ko) */
182 while (pop_pos_stack (&parse_stack, &pos) && ret_val < 2)
183 {
184 ret_val += get_liberties_helper (NORTH (pos), orig_color);
185 ret_val += get_liberties_helper (SOUTH (pos), orig_color);
186 ret_val += get_liberties_helper (EAST (pos), orig_color);
187 ret_val += get_liberties_helper (WEST (pos), orig_color);
188 }
189
190 /* if there's more than two liberties, the stack isn't empty, so empty
191 it */
192 empty_stack (&parse_stack);
193
194 return ret_val;
195}
196
197static int
198get_liberties_helper (unsigned short pos, unsigned char orig_color)
199{
200 if (on_board (pos) &&
201 get_point_board (pos) != OTHER (orig_color) && !is_marked (pos))
202 {
203 make_mark (pos);
204
205 if (get_point_board (pos) == EMPTY)
206 {
207 return 1;
208 }
209 else
210 {
211 push_pos_stack (&parse_stack, pos);
212 }
213 }
214
215 return 0;
216}
217
218
219int
220flood_fill_board (unsigned short pos, unsigned char color)
221{
222 if (!on_board (pos) || get_point_board (pos) == color)
223 {
224 return 0;
225 }
226
227 empty_stack (&parse_stack);
228
229 int ret_val = 0;
230
231 unsigned char orig_color = get_point_board (pos);
232
233 set_point_board (pos, color);
234 ++ret_val;
235 push_pos_stack (&parse_stack, pos);
236
237 while (pop_pos_stack (&parse_stack, &pos))
238 {
239 ret_val += flood_fill_helper (NORTH (pos), orig_color, color);
240 ret_val += flood_fill_helper (SOUTH (pos), orig_color, color);
241 ret_val += flood_fill_helper (EAST (pos), orig_color, color);
242 ret_val += flood_fill_helper (WEST (pos), orig_color, color);
243 }
244
245 return ret_val;
246}
247
248
249static int
250flood_fill_helper (unsigned short pos, unsigned char orig_color,
251 unsigned char color)
252{
253 if (on_board (pos) && get_point_board (pos) == orig_color)
254 {
255 set_point_board (pos, color);
256 push_pos_stack (&parse_stack, pos);
257 return 1;
258 }
259
260 return 0;
261}
262
263bool
264legal_move_board (unsigned short pos, unsigned char color, bool allow_suicide)
265{
266 /* you can always pass */
267 if (pos == PASS_POS)
268 {
269 return true;
270 }
271
272 if (!on_board (pos) || (color != BLACK && color != WHITE))
273 {
274 return false;
275 }
276
277 if (pos == ko_pos && color == current_player)
278 {
279 return false;
280 }
281
282 if (get_point_board (pos) != EMPTY)
283 {
284 return false;
285 }
286
287 /* don't need to save the current state, because it's always empty
288 since we tested for that above */
289 set_point_board (pos, color);
290
291 /* if we have liberties, it can't be illegal */
292 if (get_liberties_board (pos) > 0 ||
293 /* if we can capture something, it can't be illegal */
294 (get_point_board (NORTH (pos)) == OTHER (color) &&
295 !get_liberties_board (NORTH (pos))) ||
296 (get_point_board (SOUTH (pos)) == OTHER (color) &&
297 !get_liberties_board (SOUTH (pos))) ||
298 (get_point_board (EAST (pos)) == OTHER (color) &&
299 !get_liberties_board (EAST (pos))) ||
300 (get_point_board (WEST (pos)) == OTHER (color) &&
301 !get_liberties_board (WEST (pos))) ||
302 /* if we're allowed to suicide, only multi-stone suicide is legal
303 (no ruleset allows single-stone suicide that I know of) */
304 (allow_suicide && (get_point_board (NORTH (pos)) == color ||
305 get_point_board (SOUTH (pos)) == color ||
306 get_point_board (EAST (pos)) == color ||
307 get_point_board (WEST (pos)) == color)))
308 {
309 /* undo our previous set */
310 set_point_board (pos, EMPTY);
311 return true;
312 }
313 else
314 {
315 /* undo our previous set */
316 set_point_board (pos, EMPTY);
317 return false;
318 }
319}
320
321
322unsigned short
323WRAP (unsigned short pos)
324{
325 int x, y;
326 if (on_board (pos))
327 {
328 return pos;
329 }
330 else
331 {
332 x = I (pos);
333 y = J (pos);
334
335 if (x < 0)
336 {
337 x = board_width - 1;
338 }
339 else if ((unsigned int) x >= board_width)
340 {
341 x = 0;
342 }
343
344 if (y < 0)
345 {
346 y = board_height - 1;
347 }
348 else if ((unsigned int) y >= board_height)
349 {
350 y = 0;
351 }
352 return POS (x, y);
353 }
354}