valid_escape_route(): Use immediate_liberty_count()
[pachi.git] / board.c
blob0ad23a0126c85e6a6cb607cb9ba12ab7a5b08ebf
1 #include <alloca.h>
2 #include <assert.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include "board.h"
8 #include "debug.h"
9 #include "random.h"
11 int board_group_capture(struct board *board, int group);
13 bool random_pass = false;
16 #if 0
17 #define profiling_noinline __attribute__((noinline))
18 #else
19 #define profiling_noinline
20 #endif
22 #define gi_granularity 4
23 #define gi_allocsize(gids) ((1 << gi_granularity) + ((gids) >> gi_granularity) * (1 << gi_granularity))
26 static void
27 board_setup(struct board *b)
29 memset(b, 0, sizeof(*b));
31 struct move m = { pass, S_NONE };
32 b->last_move = b->ko = m;
35 struct board *
36 board_init(void)
38 struct board *b = malloc(sizeof(struct board));
39 board_setup(b);
40 return b;
43 struct board *
44 board_copy(struct board *b2, struct board *b1)
46 memcpy(b2, b1, sizeof(struct board));
48 int bsize = b2->size2 * sizeof(*b2->b);
49 int gsize = b2->size2 * sizeof(*b2->g);
50 int fsize = b2->size2 * sizeof(*b2->f);
51 int nsize = b2->size2 * sizeof(*b2->n);
52 int psize = b2->size2 * sizeof(*b2->p);
53 int hsize = b2->size2 * 2 * sizeof(*b2->h);
54 int gisize = b2->size2 * sizeof(*b2->gi);
55 void *x = malloc(bsize + gsize + fsize + psize + nsize + hsize + gisize);
56 memcpy(x, b1->b, bsize + gsize + fsize + psize + nsize + hsize + gisize);
57 b2->b = x; x += bsize;
58 b2->g = x; x += gsize;
59 b2->f = x; x += fsize;
60 b2->p = x; x += psize;
61 b2->n = x; x += nsize;
62 b2->h = x; x += hsize;
63 b2->gi = x; x += gisize;
65 return b2;
68 void
69 board_done_noalloc(struct board *board)
71 if (board->b) free(board->b);
74 void
75 board_done(struct board *board)
77 board_done_noalloc(board);
78 free(board);
81 void
82 board_resize(struct board *board, int size)
84 board->size = size + 2 /* S_OFFBOARD margin */;
85 board->size2 = board->size * board->size;
86 if (board->b)
87 free(board->b);
89 int bsize = board->size2 * sizeof(*board->b);
90 int gsize = board->size2 * sizeof(*board->g);
91 int fsize = board->size2 * sizeof(*board->f);
92 int nsize = board->size2 * sizeof(*board->n);
93 int psize = board->size2 * sizeof(*board->p);
94 int hsize = board->size2 * 2 * sizeof(*board->h);
95 int gisize = board->size2 * sizeof(*board->gi);
96 void *x = malloc(bsize + gsize + fsize + psize + nsize + hsize + gisize);
97 memset(x, 0, bsize + gsize + fsize + psize + nsize + hsize + gisize);
98 board->b = x; x += bsize;
99 board->g = x; x += gsize;
100 board->f = x; x += fsize;
101 board->p = x; x += psize;
102 board->n = x; x += nsize;
103 board->h = x; x += hsize;
104 board->gi = x; x += gisize;
107 void
108 board_clear(struct board *board)
110 int size = board->size;
112 board_done_noalloc(board);
113 board_setup(board);
114 board_resize(board, size - 2 /* S_OFFBOARD margin */);
116 /* Draw the offboard margin */
117 int top_row = board->size2 - board->size;
118 int i;
119 for (i = 0; i < board->size; i++)
120 board->b[i] = board->b[top_row + i] = S_OFFBOARD;
121 for (i = 0; i <= top_row; i += board->size)
122 board->b[i] = board->b[board->size - 1 + i] = S_OFFBOARD;
124 foreach_point(board) {
125 coord_t coord = c;
126 if (board_at(board, coord) == S_OFFBOARD)
127 continue;
128 foreach_neighbor(board, c, {
129 inc_neighbor_count_at(board, coord, board_at(board, c));
130 } );
131 } foreach_point_end;
133 /* First, pass is always a free position. */
134 board->f[board->flen++] = coord_raw(pass);
135 /* All positions are free! Except the margin. */
136 for (i = board->size; i < (board->size - 1) * board->size; i++)
137 if (i % board->size != 0 && i % board->size != board->size - 1)
138 board->f[board->flen++] = i;
140 /* Initialize zobrist hashtable. */
141 foreach_point(board) {
142 int max = (sizeof(hash_t) << history_hash_bits);
143 /* fast_random() is 16-bit only */
144 board->h[coord_raw(c) * 2] = ((hash_t) fast_random(max))
145 | ((hash_t) fast_random(max) << 16)
146 | ((hash_t) fast_random(max) << 32)
147 | ((hash_t) fast_random(max) << 48);
148 if (!board->h[coord_raw(c) * 2])
149 /* Would be kinda "oops". */
150 board->h[coord_raw(c) * 2] = 1;
151 /* And once again for white */
152 board->h[coord_raw(c) * 2 + 1] = ((hash_t) fast_random(max))
153 | ((hash_t) fast_random(max) << 16)
154 | ((hash_t) fast_random(max) << 32)
155 | ((hash_t) fast_random(max) << 48);
156 if (!board->h[coord_raw(c) * 2 + 1])
157 board->h[coord_raw(c) * 2 + 1] = 1;
158 } foreach_point_end;
162 void
163 board_print(struct board *board, FILE *f)
165 fprintf(f, "Move: % 3d Komi: %2.1f Captures B: %d W: %d\n ",
166 board->moves, board->komi,
167 board->captures[S_BLACK], board->captures[S_WHITE]);
168 int x, y;
169 char asdf[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ";
170 for (x = 1; x < board->size - 1; x++)
171 fprintf(f, "%c ", asdf[x - 1]);
172 fprintf(f, "\n +-");
173 for (x = 1; x < board->size - 1; x++)
174 fprintf(f, "--");
175 fprintf(f, "+\n");
176 for (y = board->size - 2; y >= 1; y--) {
177 fprintf(f, "%2d | ", y);
178 for (x = 1; x < board->size - 1; x++) {
179 if (coord_x(board->last_move.coord, board) == x && coord_y(board->last_move.coord, board) == y)
180 fprintf(f, "%c)", stone2char(board_atxy(board, x, y)));
181 else
182 fprintf(f, "%c ", stone2char(board_atxy(board, x, y)));
184 if (DEBUGL(6)) {
185 fprintf(f, "| ");
186 for (x = 1; x < board->size - 1; x++) {
187 fprintf(f, "%d ", group_atxy(board, x, y));
190 fprintf(f, "|\n");
192 fprintf(f, " +-");
193 for (x = 1; x < board->size - 1; x++)
194 fprintf(f, "--");
195 fprintf(f, "+\n\n");
199 /* Update board hash with given coordinate. */
200 static void profiling_noinline
201 board_hash_update(struct board *board, coord_t coord, enum stone color)
203 board->hash ^= board->h[(color == S_BLACK ? board->size2 : 0) + coord_raw(coord)];
204 if (DEBUGL(8))
205 fprintf(stderr, "board_hash_update(%d,%d,%d) ^ %llx -> %llx\n", color, coord_x(coord, board), coord_y(coord, board), board->h[color * coord_raw(coord)], board->hash);
208 /* Commit current board hash to history. */
209 static void profiling_noinline
210 board_hash_commit(struct board *board)
212 if (DEBUGL(8))
213 fprintf(stderr, "board_hash_commit %llx\n", board->hash);
214 if (likely(board->history_hash[board->hash & history_hash_mask]) == 0) {
215 board->history_hash[board->hash & history_hash_mask] = board->hash;
216 } else {
217 hash_t i = board->hash;
218 while (board->history_hash[i & history_hash_mask]) {
219 if (board->history_hash[i & history_hash_mask] == board->hash) {
220 if (DEBUGL(5))
221 fprintf(stderr, "SUPERKO VIOLATION noted at %d,%d\n",
222 coord_x(board->last_move.coord, board), coord_y(board->last_move.coord, board));
223 board->superko_violation = true;
224 return;
226 i++;
228 board->history_hash[i & history_hash_mask] = board->hash;
233 void
234 board_handicap_stone(struct board *board, int x, int y, FILE *f)
236 struct move m;
237 m.color = S_BLACK;
238 coord_xy(m.coord, x, y, board);
240 board_play(board, &m);
242 char *str = coord2str(m.coord, board);
243 if (DEBUGL(1))
244 fprintf(stderr, "choosing handicap %s (%d,%d)\n", str, x, y);
245 fprintf(f, "%s ", str);
246 free(str);
249 void
250 board_handicap(struct board *board, int stones, FILE *f)
252 int margin = 3 + (board->size >= 13);
253 int min = margin;
254 int mid = board->size / 2;
255 int max = board->size - 1 - margin;
256 const int places[][2] = {
257 { min, min }, { max, max }, { max, min }, { min, max },
258 { min, mid }, { max, mid },
259 { mid, min }, { mid, max },
260 { mid, mid },
263 board->handicap = stones;
265 if (stones == 5 || stones == 7) {
266 board_handicap_stone(board, mid, mid, f);
267 stones--;
270 int i;
271 for (i = 0; i < stones; i++)
272 board_handicap_stone(board, places[i][0], places[i][1], f);
276 static void
277 board_group_addlib(struct board *board, group_t group, coord_t coord)
279 if (DEBUGL(7)) {
280 fprintf(stderr, "Group %d[%s]: Adding liberty %s\n",
281 group, coord2sstr(group, board), coord2sstr(coord, board));
284 struct group *gi = &board_group_info(board, group);
285 if (gi->libs < GROUP_KEEP_LIBS) {
286 for (int i = 0; i < gi->libs; i++)
287 if (gi->lib[i] == coord)
288 return;
289 gi->lib[gi->libs++] = coord;
293 static void
294 board_group_rmlib(struct board *board, group_t group, coord_t coord)
296 if (DEBUGL(7)) {
297 fprintf(stderr, "Group %d[%s]: Removing liberty %s\n",
298 group, coord2sstr(group, board), coord2sstr(coord, board));
301 struct group *gi = &board_group_info(board, group);
302 for (int i = 0; i < gi->libs; i++) {
303 if (gi->lib[i] == coord) {
304 for (i++; i < gi->libs; i++)
305 gi->lib[i - 1] = gi->lib[i];
306 gi->libs--;
307 if (gi->libs < GROUP_KEEP_LIBS - 1)
308 return;
309 goto find_extra_lib;
312 /* This is ok even if gi->libs < GROUP_KEEP_LIBS since we
313 * can call this multiple times per coord. */
314 return;
316 /* Add extra liberty from the board to our liberty list. */
317 find_extra_lib:;
318 bool watermark[board->size2];
319 memset(watermark, 0, sizeof(watermark));
321 foreach_in_group(board, group) {
322 coord_t coord = c;
323 foreach_neighbor(board, coord, {
324 if (likely(watermark[coord_raw(c)]))
325 continue;
326 watermark[coord_raw(c)] = true;
327 if (board_at(board, c) == S_NONE) {
328 bool next = false;
329 for (int i = 0; i < GROUP_KEEP_LIBS - 1; i++) {
330 if (gi->lib[i] == c) {
331 next = true;
332 break;
335 if (!next) {
336 gi->lib[gi->libs++] = c;
337 return;
340 } );
341 } foreach_in_group_end;
345 /* This is a low-level routine that doesn't maintain consistency
346 * of all the board data structures. Use board_group_capture() from
347 * your code. */
348 static void
349 board_remove_stone(struct board *board, coord_t c)
351 enum stone color = board_at(board, c);
352 board_at(board, c) = S_NONE;
353 group_at(board, c) = 0;
354 board_hash_update(board, c, color);
356 /* Increase liberties of surrounding groups */
357 coord_t coord = c;
358 foreach_neighbor(board, coord, {
359 dec_neighbor_count_at(board, c, color);
360 board_group_addlib(board, group_at(board, c), coord);
363 if (DEBUGL(6))
364 fprintf(stderr, "pushing free move [%d]: %d,%d\n", board->flen, coord_x(c, board), coord_y(c, board));
365 board->f[board->flen++] = coord_raw(c);
369 static void profiling_noinline
370 add_to_group(struct board *board, int gid, coord_t prevstone, coord_t coord)
372 foreach_neighbor(board, coord, {
373 if (board_at(board, c) == S_NONE)
374 board_group_addlib(board, gid, c);
377 group_at(board, coord) = gid;
378 groupnext_at(board, coord) = groupnext_at(board, prevstone);
379 groupnext_at(board, prevstone) = coord_raw(coord);
381 if (DEBUGL(8))
382 fprintf(stderr, "add_to_group: added (%d,%d ->) %d,%d (-> %d,%d) to group %d\n",
383 coord_x(prevstone, board), coord_y(prevstone, board),
384 coord_x(coord, board), coord_y(coord, board),
385 groupnext_at(board, coord) % board->size, groupnext_at(board, coord) / board->size,
386 gid);
389 static void profiling_noinline
390 merge_groups(struct board *board, group_t group_to, group_t group_from)
392 if (DEBUGL(7))
393 fprintf(stderr, "board_play_raw: merging groups %d -> %d\n",
394 group_from, group_to);
396 coord_t last_in_group;
397 foreach_in_group(board, group_from) {
398 last_in_group = c;
399 group_at(board, c) = group_to;
400 } foreach_in_group_end;
401 groupnext_at(board, last_in_group) = groupnext_at(board, group_to);
402 groupnext_at(board, group_to) = group_from;
404 struct group *gi_from = &board_group_info(board, group_from);
405 struct group *gi_to = &board_group_info(board, group_to);
406 if (gi_to->libs < GROUP_KEEP_LIBS) {
407 for (int i = 0; i < gi_from->libs; i++) {
408 for (int j = 0; j < gi_to->libs; j++)
409 if (gi_to->lib[j] == gi_from->lib[i])
410 goto next_from_lib;
411 gi_to->lib[gi_to->libs++] = gi_from->lib[i];
412 if (gi_to->libs >= GROUP_KEEP_LIBS)
413 break;
414 next_from_lib:;
418 if (DEBUGL(7))
419 fprintf(stderr, "board_play_raw: merged group: %d\n",
420 group_to);
423 static group_t profiling_noinline
424 new_group(struct board *board, coord_t coord)
426 group_t gid = coord_raw(coord);
427 foreach_neighbor(board, coord, {
428 if (board_at(board, c) == S_NONE)
429 board_group_addlib(board, gid, c);
433 group_at(board, coord) = gid;
434 groupnext_at(board, coord) = 0;
436 if (DEBUGL(8))
437 fprintf(stderr, "new_group: added %d,%d to group %d\n",
438 coord_x(coord, board), coord_y(coord, board),
439 gid);
441 return gid;
444 /* We played on a place with at least one liberty. We will become a member of
445 * some group for sure. */
446 static int profiling_noinline
447 board_play_outside(struct board *board, struct move *m, int f)
449 coord_t coord = m->coord;
450 enum stone color = m->color;
451 enum stone other_color = stone_other(color);
452 int gid = 0;
454 board->f[f] = board->f[--board->flen];
455 if (DEBUGL(6))
456 fprintf(stderr, "popping free move [%d->%d]: %d\n", board->flen, f, board->f[f]);
457 board_at(board, coord) = color;
459 foreach_neighbor(board, coord, {
460 enum stone ncolor = board_at(board, c);
461 group_t ngroup = group_at(board, c);
463 inc_neighbor_count_at(board, c, color);
465 if (!ngroup)
466 continue;
468 board_group_rmlib(board, ngroup, coord);
469 if (DEBUGL(7))
470 fprintf(stderr, "board_play_raw: reducing libs for group %d\n",
471 ngroup);
473 if (ncolor == color && ngroup != gid) {
474 if (gid <= 0) {
475 gid = ngroup;
476 add_to_group(board, gid, c, coord);
477 } else {
478 merge_groups(board, gid, ngroup);
480 } else if (ncolor == other_color) {
481 if (DEBUGL(8)) {
482 struct group *gi = &board_group_info(board, ngroup);
483 fprintf(stderr, "testing captured group %d[%s]: ", ngroup, coord2sstr(ngroup, board));
484 for (int i = 0; i < gi->libs; i++)
485 fprintf(stderr, "%s ", coord2sstr(gi->lib[i], board));
486 fprintf(stderr, "\n");
488 if (unlikely(board_group_captured(board, ngroup)))
489 board_group_capture(board, ngroup);
493 if (unlikely(gid <= 0))
494 gid = new_group(board, coord);
496 board->last_move = *m;
497 board->moves++;
498 board_hash_update(board, coord, color);
499 struct move ko = { pass, S_NONE };
500 board->ko = ko;
502 return gid;
505 /* We played in an eye-like shape. Either we capture at least one of the eye
506 * sides in the process of playing, or return -1. */
507 static int profiling_noinline
508 board_play_in_eye(struct board *board, struct move *m, int f)
510 coord_t coord = m->coord;
511 enum stone color = m->color;
512 /* Check ko: Capture at a position of ko capture one move ago */
513 if (unlikely(color == board->ko.color && coord_eq(coord, board->ko.coord))) {
514 if (DEBUGL(5))
515 fprintf(stderr, "board_check: ko at %d,%d color %d\n", coord_x(coord, board), coord_y(coord, board), color);
516 return -1;
517 } else if (DEBUGL(6)) {
518 fprintf(stderr, "board_check: no ko at %d,%d,%d - ko is %d,%d,%d\n",
519 color, coord_x(coord, board), coord_y(coord, board),
520 board->ko.color, coord_x(board->ko.coord, board), coord_y(board->ko.coord, board));
523 struct move ko = { pass, S_NONE };
525 board->f[f] = board->f[--board->flen];
526 if (DEBUGL(6))
527 fprintf(stderr, "popping free move [%d->%d]: %d\n", board->flen, f, board->f[f]);
529 int captured_groups = 0;
531 foreach_neighbor(board, coord, {
532 group_t group = group_at(board, c);
533 if (!group)
534 continue;
536 board_group_rmlib(board, group, coord);
537 if (DEBUGL(7))
538 fprintf(stderr, "board_play_raw: reducing libs for group %d\n",
539 group);
541 if (unlikely(board_group_captured(board, group))) {
542 captured_groups++;
543 if (board_group_capture(board, group) == 1) {
544 /* If we captured multiple groups at once,
545 * we can't be fighting ko so we don't need
546 * to check for that. */
547 ko.color = stone_other(color);
548 ko.coord = c;
549 if (DEBUGL(5))
550 fprintf(stderr, "guarding ko at %d,%d,%d\n", ko.color, coord_x(ko.coord, board), coord_y(ko.coord, board));
555 if (likely(captured_groups == 0)) {
556 if (DEBUGL(5)) {
557 if (DEBUGL(6))
558 board_print(board, stderr);
559 fprintf(stderr, "board_check: one-stone suicide\n");
562 foreach_neighbor(board, coord, {
563 board_group_addlib(board, group_at(board, c), coord);
564 if (DEBUGL(7))
565 fprintf(stderr, "board_play_raw: restoring libs for group %d\n",
566 group_at(board, c));
569 coord_t c = coord;
570 if (DEBUGL(6))
571 fprintf(stderr, "pushing free move [%d]: %d,%d\n", board->flen, coord_x(c, board), coord_y(c, board));
572 board->f[board->flen++] = coord_raw(c);
573 return -1;
576 foreach_neighbor(board, coord, {
577 inc_neighbor_count_at(board, c, color);
580 board_at(board, coord) = color;
582 board->last_move = *m;
583 board->moves++;
584 board_hash_update(board, coord, color);
585 board_hash_commit(board);
586 board->ko = ko;
588 return new_group(board, coord);
591 static int __attribute__((flatten))
592 board_play_f(struct board *board, struct move *m, int f)
594 if (DEBUGL(7)) {
595 fprintf(stderr, "board_play(): ---- Playing %d,%d\n", coord_x(m->coord, board), coord_y(m->coord, board));
597 if (likely(!board_is_eyelike(board, &m->coord, stone_other(m->color)))) {
598 /* NOT playing in an eye. Thus this move has to succeed. (This
599 * is thanks to New Zealand rules. Otherwise, multi-stone
600 * suicide might fail.) */
601 int gid = board_play_outside(board, m, f);
602 if (unlikely(board_group_captured(board, gid))) {
603 board_group_capture(board, gid);
605 board_hash_commit(board);
606 return 0;
607 } else {
608 return board_play_in_eye(board, m, f);
613 board_play(struct board *board, struct move *m)
615 if (unlikely(is_pass(m->coord) || is_resign(m->coord)))
616 return 0;
618 int f;
619 for (f = 0; f < board->flen; f++)
620 if (board->f[f] == coord_raw(m->coord))
621 return board_play_f(board, m, f);
623 if (DEBUGL(7))
624 fprintf(stderr, "board_check: stone exists\n");
625 return -1;
629 static inline bool
630 board_try_random_move(struct board *b, enum stone color, coord_t *coord, int f)
632 coord_raw(*coord) = b->f[f];
633 if (is_pass(*coord))
634 return random_pass;
635 struct move m = { *coord, color };
636 if (DEBUGL(6))
637 fprintf(stderr, "trying random move %d: %d,%d\n", f, coord_x(*coord, b), coord_y(*coord, b));
638 return (!board_is_one_point_eye(b, coord, color) /* bad idea to play into one, usually */
639 && board_play_f(b, &m, f) >= 0);
642 void
643 board_play_random(struct board *b, enum stone color, coord_t *coord)
645 int base = fast_random(b->flen);
646 coord_pos(*coord, base, b);
647 if (likely(board_try_random_move(b, color, coord, base)))
648 return;
650 int f;
651 for (f = base + 1; f < b->flen; f++)
652 if (board_try_random_move(b, color, coord, f))
653 return;
654 for (f = 0; f < base; f++)
655 if (board_try_random_move(b, color, coord, f))
656 return;
658 *coord = pass;
662 bool
663 board_is_eyelike(struct board *board, coord_t *coord, enum stone eye_color)
665 return (neighbor_count_at(board, *coord, eye_color) + neighbor_count_at(board, *coord, S_OFFBOARD)) == 4;
668 bool
669 board_is_one_point_eye(struct board *board, coord_t *coord, enum stone eye_color)
671 enum stone color_diag_libs[S_MAX] = {0, 0, 0, 0};
673 if (likely(neighbor_count_at(board, *coord, eye_color) + neighbor_count_at(board, *coord, S_OFFBOARD) < 4)) {
674 return false;
677 /* XXX: We attempt false eye detection but we will yield false
678 * positives in case of http://senseis.xmp.net/?TwoHeadedDragon :-( */
680 foreach_diag_neighbor(board, *coord) {
681 color_diag_libs[(enum stone) board_at(board, c)]++;
682 } foreach_diag_neighbor_end;
683 color_diag_libs[stone_other(eye_color)] += !!color_diag_libs[S_OFFBOARD];
684 return likely(color_diag_libs[stone_other(eye_color)] < 2);
687 enum stone
688 board_get_one_point_eye(struct board *board, coord_t *coord)
690 if (board_is_one_point_eye(board, coord, S_WHITE))
691 return S_WHITE;
692 else if (board_is_one_point_eye(board, coord, S_BLACK))
693 return S_BLACK;
694 else
695 return S_NONE;
699 int profiling_noinline
700 board_group_capture(struct board *board, int group)
702 int stones = 0;
704 foreach_in_group(board, group) {
705 board->captures[stone_other(board_at(board, c))]++;
706 board_remove_stone(board, c);
707 stones++;
708 } foreach_in_group_end;
710 return stones;
713 bool
714 board_group_in_atari(struct board *board, group_t group, coord_t *lastlib)
716 if (board_group_info(board, group).libs != 1)
717 return false;
718 *lastlib = board_group_info(board, group).lib[0];
719 return true;
722 bool
723 board_group_can_atari(struct board *board, group_t group, coord_t lastlib[2])
725 if (board_group_info(board, group).libs != 2)
726 return false;
727 lastlib[0] = board_group_info(board, group).lib[0];
728 lastlib[1] = board_group_info(board, group).lib[1];
729 return true;
733 /* Chinese counting */
734 float
735 board_official_score(struct board *board)
737 int scores[S_MAX];
738 memset(scores, 0, sizeof(scores));
740 enum { GC_DUNNO, GC_ALIVE, GC_DEAD } gcache[board->size * board->size + 1];
741 memset(gcache, 0, sizeof(gcache));
743 foreach_point(board) {
744 enum stone color = board_at(board, c);
745 group_t g = group_at(board, c);
746 if (g > 0) {
747 /* There is a complication: There can be some dead
748 * stones that could not have been removed because
749 * they are in enemy territory and we can't suicide.
750 * At least we know they are in atari. */
751 if (gcache[g] == GC_DUNNO) {
752 coord_t x;
753 gcache[g] = board_group_in_atari(board, g, &x) == 1 ? GC_DEAD : GC_ALIVE;
755 if (gcache[g] == GC_ALIVE)
756 scores[color]++;
757 else
758 scores[stone_other(color)]++;
759 /* XXX: But we still miss the one empty opponent's point. */
761 } else if (color == S_NONE) {
762 /* TODO: Count multi-point eyes */
763 color = board_get_one_point_eye(board, &c);
764 scores[color]++;
766 } foreach_point_end;
768 return board->komi + scores[S_WHITE] - scores[S_BLACK];
771 float
772 board_fast_score(struct board *board)
774 int scores[S_MAX];
775 memset(scores, 0, sizeof(scores));
777 foreach_point(board) {
778 enum stone color = board_at(board, c);
779 if (color == S_NONE)
780 color = board_get_one_point_eye(board, &c);
781 scores[color]++;
782 // fprintf(stderr, "%d, %d ++%d = %d\n", coord_x(c, board), coord_y(c, board), color, scores[color]);
783 } foreach_point_end;
785 return board->komi + board->handicap + scores[S_WHITE] - scores[S_BLACK];