Updated README: Equal sign not required with `--mode` flag.
[sgk-go] / engine / worm.c
CommitLineData
7eeb782e
AT
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#include "gnugo.h"
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "liberty.h"
31#include "patterns.h"
32
33static void compute_effective_worm_sizes(void);
34static void do_compute_effective_worm_sizes(int color,
35 int (*cw)[MAX_CLOSE_WORMS],
36 int *ncw, int max_distance);
37static void compute_unconditional_status(void);
38static void find_worm_attacks_and_defenses(void);
39static void find_worm_threats(void);
40static int find_lunch(int str, int *lunch);
41static void change_tactical_point(int str, int move, int code,
42 int points[MAX_TACTICAL_POINTS],
43 int codes[MAX_TACTICAL_POINTS]);
44static void propagate_worm2(int str);
45static int genus(int str);
46static void markcomponent(int str, int pos, int mg[BOARDMAX]);
47static int examine_cavity(int pos, int *edge);
48static void cavity_recurse(int pos, int mx[BOARDMAX],
49 int *border_color, int *edge, int str);
50static void ping_cave(int str, int *result1, int *result2,
51 int *result3, int *result4);
52static void ping_recurse(int pos, int *counter,
53 int mx[BOARDMAX],
54 int mr[BOARDMAX], int color);
55static int touching(int pos, int color);
56static void find_attack_patterns(void);
57static void attack_callback(int anchor, int color,
58 struct pattern *pattern, int ll, void *data);
59static void find_defense_patterns(void);
60static void defense_callback(int anchor, int color,
61 struct pattern *pattern, int ll, void *data);
62static void build_worms(void);
63static void report_worm(int pos);
64
65/* A worm or string is a maximal connected set of stones of the same color,
66 * black or white.
67 *
68 * Cavities are sets of connected empty vertices.
69 */
70
71
72/* make_worms() finds all worms and assembles some data about them.
73 *
74 * Each worm is marked with an origin. This is an arbitrarily chosen
75 * element of the worm, in practice the algorithm puts the origin at
76 * the first element when they are given the lexicographical order,
77 * though its location is irrelevant for applications. To see if two
78 * stones lie in the same worm, compare their origins.
79 *
80 * We will use the field dragon[ii].genus to keep track of
81 * black- or white-bordered cavities (essentially eyes) which are found.
82 * so this field must be zero'd now.
83 */
84
85void
86make_worms(void)
87{
88 int pos;
89
90 /* Build the basic worm data: color, origin, size, liberties. */
91 build_worms();
92
93 /* No point continuing if the board is completely empty. */
94 if (stones_on_board(BLACK | WHITE) == 0)
95 return;
96
97 /* Compute effective sizes of all worms. */
98 compute_effective_worm_sizes();
99
100 /* Look for unconditionally alive and dead worms, and unconditional
101 * territory.
102 */
103 compute_unconditional_status();
104
105 find_worm_attacks_and_defenses();
106
107 gg_assert(stackp == 0);
108
109 /* Count liberties of different orders and initialize cutstone fields. */
110 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
111 if (IS_STONE(board[pos]) && is_worm_origin(pos, pos)) {
112 int lib1, lib2, lib3, lib4;
113
114 ping_cave(pos, &lib1, &lib2, &lib3, &lib4);
115 ASSERT1(worm[pos].liberties == lib1, pos);
116 worm[pos].liberties2 = lib2;
117 worm[pos].liberties3 = lib3;
118 worm[pos].liberties4 = lib4;
119 worm[pos].cutstone = 0;
120 worm[pos].cutstone2 = 0;
121 propagate_worm(pos);
122 }
123 }
124
125 gg_assert(stackp == 0);
126
127 /*
128 * There are two concepts of cutting stones in the worm array.
129 *
130 * worm.cutstone:
131 *
132 * A CUTTING STONE is one adjacent to two enemy strings,
133 * which do not have a liberty in common. The most common
134 * type of cutting string is in this situation.
135 *
136 * XO
137 * OX
138 *
139 * A POTENTIAL CUTTING STONE is adjacent to two enemy
140 * strings which do share a liberty. For example, X in:
141 *
142 * XO
143 * O.
144 *
145 * For cutting strings we set worm[m][n].cutstone=2. For potential
146 * cutting strings we set worm[m][n].cutstone=1. For other strings,
147 * worm[m][n].cutstone=0.
148 *
149 * worm.cutstone2:
150 *
151 * Cutting points are identified by the patterns in the
152 * connections database. Proper cuts are handled by the fact
153 * that attacking and defending moves also count as moves
154 * cutting or connecting the surrounding dragons.
155 *
156 * The cutstone field will now be set. The cutstone2 field is set
157 * later, during find_cuts(), called from make_dragons().
158 *
159 * We maintain both fields because the historically older cutstone
160 * field is needed to deal with the fact that e.g. in the position
161 *
162 *
163 * OXX.O
164 * .OOXO
165 * OXX.O
166 *
167 * the X stones are amalgamated into one dragon because neither cut
168 * works as long as the two O stones are in atari. Therefore we add
169 * one to the cutstone field for each potential cutting point,
170 * indicating that these O stones are indeed worth rescuing.
171 *
172 * For the time being we use both concepts in parallel. It's
173 * possible we also need the old concept for correct handling of lunches.
174 */
175
176 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
177 int w1 = NO_MOVE;
178 int w2 = NO_MOVE;
179 int k;
180 int pos2;
181
182 /* Only work on each worm once. This is easiest done if we only
183 * work with the origin of each worm.
184 */
185 if (!IS_STONE(board[pos]) || !is_worm_origin(pos, pos))
186 continue;
187
188 /* Try to find two adjacent worms (w1) and (w2)
189 * of opposite colour from (pos).
190 */
191 for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
192 /* Work only with the opposite color from (pos). */
193 if (board[pos2] != OTHER_COLOR(board[pos]))
194 continue;
195
196 for (k = 0; k < 4; k++) {
197 if (!ON_BOARD(pos2 + delta[k])
198 || worm[pos2 + delta[k]].origin != pos)
199 continue;
200
201 ASSERT1(board[pos2 + delta[k]] == board[pos], pos);
202
203 /* If we have not already found a worm which meets the criteria,
204 * store it into (w1), otherwise store it into (w2).
205 */
206 if (w1 == NO_MOVE)
207 w1 = worm[pos2].origin;
208 else if (!is_same_worm(pos2, w1))
209 w2 = worm[pos2].origin;
210 }
211 }
212
213 /*
214 * We now verify the definition of cutting stones. We have
215 * verified that the string at (pos) is adjacent to two enemy
216 * strings at (w1) and (w2). We need to know if these
217 * strings share a liberty.
218 */
219
220 /* Only do this if we really found something. */
221 if (w2 != NO_MOVE) {
222 worm[pos].cutstone = 2;
223 if (count_common_libs(w1, w2) > 0)
224 worm[pos].cutstone = 1;
225
226 DEBUG(DEBUG_WORMS, "Worm at %1m has w1 %1m and w2 %1m, cutstone %d\n",
227 pos, w1, w2, worm[pos].cutstone);
228 }
229 }
230
231 gg_assert(stackp == 0);
232
233 /* Set the genus of all worms. */
234 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
235 if (IS_STONE(board[pos]) && is_worm_origin(pos, pos)) {
236 worm[pos].genus = genus(pos);
237 propagate_worm(pos);
238 }
239 }
240 gg_assert(stackp == 0);
241
242 /* Now we try to improve the values of worm.attack and worm.defend.
243 * If we find that capturing the string at str also defends the
244 * string at str2, or attacks it, then we add points of attack and
245 * defense. We don't add attacking point for strings that can't be
246 * defended.
247 */
248 {
249 int color;
250 int str;
251 int moves_to_try[BOARDMAX];
252 memset(moves_to_try, 0, sizeof(moves_to_try));
253
254 /* Find which colors to try at what points. */
255 for (str = BOARDMIN; str < BOARDMAX; str++) {
256 if (IS_STONE(board[str]) && is_worm_origin(str, str)) {
257 color = board[str];
258 moves_to_try[worm[str].defense_points[0]] |= color;
259 moves_to_try[worm[str].attack_points[0]] |= OTHER_COLOR(color);
260 }
261 }
262
263 /* Loop over the board and over the colors and try the moves found
264 * in the previous loop.
265 */
266 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
267 if (!ON_BOARD(pos))
268 continue;
269
270 for (color = WHITE; color <= BLACK; color++) {
271 if (!(moves_to_try[pos] & color))
272 continue;
273
274 /* Try to play color at pos and see what it leads to. */
275 if (!trymove(pos, color, "make_worms", NO_MOVE))
276 continue;
277
278 /* We must read to the same depth that was used in the
279 * initial determination of worm.attack and worm.defend
280 * to avoid horizon effects. Since stackp has been
281 * incremented we must also increment depth values.
282 */
283
284 DEBUG(DEBUG_WORMS, "trying %1m\n", pos);
285 increase_depth_values();
286
287 /* Now we try to find a group which is saved or attacked as well
288 * by this move.
289 */
290 for (str = BOARDMIN; str < BOARDMAX; str++) {
291 if (!IS_STONE(board[str])
292 || !is_worm_origin(str, str))
293 continue;
294
295 /* If the worm is of the opposite color to the move,
296 * then we try to defend it. If there was a previous
297 * attack and defense of it, and there is no defense
298 * for the attack now...
299 */
300 if (worm[str].color == OTHER_COLOR(color)
301 && worm[str].attack_codes[0] != 0
302 && worm[str].defense_codes[0] != 0) {
303 int dcode = find_defense(str, NULL);
304 if (dcode < worm[str].defense_codes[0]) {
305 int attack_works = 1;
306
307 /* Sometimes find_defense() fails to find a
308 * defense which has been found by other means.
309 * Try if the old defense move still works.
310 *
311 * However, we first check if the _attack_ still exists,
312 * because we could, for instance, drive the worm into
313 * seki with our move.
314 */
315 if (attack(str, NULL) >= worm[str].attack_codes[0]) {
316 if (worm[str].defense_codes[0] != 0
317 && trymove(worm[str].defense_points[0],
318 OTHER_COLOR(color), "make_worms", 0)) {
319 int this_dcode = REVERSE_RESULT(attack(str, NULL));
320 if (this_dcode > dcode) {
321 dcode = this_dcode;
322 if (dcode >= worm[str].defense_codes[0])
323 attack_works = 0;
324 }
325 popgo();
326 }
327 }
328 else
329 attack_works = 0;
330
331 /* ...then add an attack point of that worm at pos. */
332 if (attack_works) {
333 DEBUG(DEBUG_WORMS,
334 "adding point of attack of %1m at %1m with code %d\n",
335 str, pos, REVERSE_RESULT(dcode));
336 change_attack(str, pos, REVERSE_RESULT(dcode));
337 }
338 }
339 }
340
341 /* If the worm is of the same color as the move we try to
342 * attack it. If there previously was an attack on it, but
343 * there is none now, then add a defense point of str at
344 * pos.
345 */
346 else if (worm[str].color == color
347 && worm[str].attack_codes[0] != 0) {
348 int acode = attack(str, NULL);
349 if (acode < worm[str].attack_codes[0]) {
350 int defense_works = 1;
351 /* Sometimes attack() fails to find an
352 * attack which has been found by other means.
353 * Try if the old attack move still works.
354 */
355 if (worm[str].attack_codes[0] != 0
356 && trymove(worm[str].attack_points[0],
357 OTHER_COLOR(color), "make_worms", 0)) {
358 int this_acode;
359 if (board[str] == EMPTY)
360 this_acode = WIN;
361 else
362 this_acode = REVERSE_RESULT(find_defense(str, NULL));
363 if (this_acode > acode) {
364 acode = this_acode;
365 if (acode >= worm[str].attack_codes[0])
366 defense_works = 0;
367 }
368 popgo();
369 }
370
371 /* ...then add an attack point of that worm at pos. */
372 if (defense_works) {
373 DEBUG(DEBUG_WORMS,
374 "adding point of defense of %1m at %1m with code %d\n",
375 str, pos, REVERSE_RESULT(acode));
376 change_defense(str, pos, REVERSE_RESULT(acode));
377 }
378 }
379 }
380 }
381 decrease_depth_values();
382 popgo();
383 }
384 }
385 }
386
387 gg_assert(stackp == 0);
388
389 /* Sometimes it happens that the tactical reading finds adjacent
390 * strings which both can be attacked but not defended. (The reason
391 * seems to be that the attacker tries harder to attack a string,
392 * than the defender tries to capture it's neighbors.) When this
393 * happens, the eyes code produces overlapping eye spaces and, still
394 * worse, all the nondefendable stones actually get amalgamated with
395 * their allies on the outside.
396 *
397 * To solve this we scan through the strings which can't be defended
398 * and check whether they have a neighbor that can be attacked. In
399 * this case we set the defense point of the former string to the
400 * attacking point of the latter.
401 *
402 * Please notice that find_defense() will still read this out
403 * incorrectly, which may lead to some confusion later.
404 */
405
406 /* First look for vertical neighbors. */
407 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
408 if (IS_STONE(board[pos])
409 && IS_STONE(board[SOUTH(pos)])
410 && !is_same_worm(pos, SOUTH(pos))) {
411 if (worm[pos].attack_codes[0] != 0
412 && worm[SOUTH(pos)].attack_codes[0] != 0) {
413 if (worm[pos].defense_codes[0] == 0
414 && does_defend(worm[SOUTH(pos)].attack_points[0], pos)) {
415 /* FIXME: need to check ko relationship here */
416 change_defense(pos, worm[SOUTH(pos)].attack_points[0], WIN);
417 }
418 if (worm[SOUTH(pos)].defense_codes[0] == 0
419 && does_defend(worm[pos].attack_points[0], SOUTH(pos))) {
420 /* FIXME: need to check ko relationship here */
421 change_defense(SOUTH(pos), worm[pos].attack_points[0], WIN);
422 }
423 }
424 }
425 }
426
427 /* Then look for horizontal neighbors. */
428 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
429 if (IS_STONE(board[pos])
430 && IS_STONE(board[EAST(pos)])
431 && !is_same_worm(pos, EAST(pos))) {
432 if (worm[pos].attack_codes[0] != 0
433 && worm[EAST(pos)].attack_codes[0] != 0) {
434 if (worm[pos].defense_codes[0] == 0
435 && does_defend(worm[EAST(pos)].attack_points[0], pos)) {
436 /* FIXME: need to check ko relationship here */
437 change_defense(pos, worm[EAST(pos)].attack_points[0], WIN);
438 }
439 if (worm[EAST(pos)].defense_codes[0] == 0
440 && does_defend(worm[pos].attack_points[0], EAST(pos))) {
441 /* FIXME: need to check ko relationship here */
442 change_defense(EAST(pos), worm[pos].attack_points[0], WIN);
443 }
444 }
445 }
446 }
447
448 gg_assert(stackp == 0);
449
450 /* Find adjacent worms that can be easily captured, aka lunches. */
451
452 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
453 int lunch;
454
455 if (!IS_STONE(board[pos]) || !is_worm_origin(pos, pos))
456 continue;
457
458 if (find_lunch(pos, &lunch)
459 && (worm[lunch].attack_codes[0] == WIN
460 || worm[lunch].attack_codes[0] == KO_A)) {
461 DEBUG(DEBUG_WORMS, "lunch found for %1m at %1m\n", pos, lunch);
462 worm[pos].lunch = lunch;
463 }
464 else
465 worm[pos].lunch = NO_MOVE;
466
467 propagate_worm(pos);
468 }
469
470 if (!disable_threat_computation)
471 find_worm_threats();
472
473 /* Identify INESSENTIAL strings.
474 *
475 * These are defined as surrounded strings which have no life
476 * potential unless part of their surrounding chain can be captured.
477 * We give a conservative definition of inessential:
478 * - the genus must be zero
479 * - there can no second order liberties
480 * - there can be no more than two edge liberties
481 * - if it is removed from the board, the remaining cavity has
482 * border color the opposite color of the string
483 * - it contains at most two edge vertices.
484 *
485 * If we get serious about identifying seki, we might want to add:
486 *
487 * - if it has fewer than 4 liberties it is tactically dead.
488 *
489 * The last condition is helpful in excluding strings which are
490 * alive in seki.
491 *
492 * An inessential string can be thought of as residing inside the
493 * opponent's eye space.
494 */
495
496 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
497 if (IS_STONE(board[pos])
498 && worm[pos].origin == pos
499 && worm[pos].genus == 0
500 && worm[pos].liberties2 == 0
501 && !worm[pos].cutstone
502 && worm[pos].lunch == NO_MOVE) {
503 int edge;
504 int border_color = examine_cavity(pos, &edge);
505 if (border_color != GRAY && edge < 3) {
506 DEBUG(DEBUG_WORMS, "Worm %1m identified as inessential.\n", pos);
507 worm[pos].inessential = 1;
508 propagate_worm(pos);
509 }
510 }
511 }
512}
513
514
515/*
516 * Clear all worms and initialize the basic data fields:
517 * color, origin, size, liberties
518 * This is a substep of make_worms().
519 */
520
521static void
522build_worms()
523{
524 int pos;
525
526 /* Set all worm data fields to 0. */
527 memset(worm, 0 , sizeof(worm));
528
529 /* Initialize the worm data for each worm. */
530 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
531 if (ON_BOARD(pos))
532 worm[pos].origin = NO_MOVE;
533
534 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
535 if (!ON_BOARD(pos) || worm[pos].origin != NO_MOVE)
536 continue;
537 worm[pos].color = board[pos];
538 worm[pos].origin = pos;
539 worm[pos].inessential = 0;
540 worm[pos].invincible = 0;
541 worm[pos].unconditional_status = UNKNOWN;
542 worm[pos].effective_size = 0.0;
543 if (IS_STONE(board[pos])) {
544 worm[pos].liberties = countlib(pos);
545 worm[pos].size = countstones(pos);
546 propagate_worm(pos);
547 }
548 }
549}
550
551
552/* Compute effective size of each worm.
553 *
554 * Effective size is the number of stones in a worm plus half the
555 * number of empty intersections that are at least as close to this
556 * worm as to any other worm. This is used to estimate the direct
557 * territorial value of capturing a worm. Intersections that are
558 * shared are counted with equal fractional values for each worm.
559 *
560 * We never count intersections further away than distance 3.
561 *
562 * This function is also used to compute arrays with information about
563 * the distances to worms of both or either color. In the latter case
564 * we count intersections up to a distance of 5.
565 */
566
567static void
568compute_effective_worm_sizes()
569{
570 do_compute_effective_worm_sizes(BLACK | WHITE, close_worms,
571 number_close_worms, 3);
572 do_compute_effective_worm_sizes(BLACK, close_black_worms,
573 number_close_black_worms, 5);
574 do_compute_effective_worm_sizes(WHITE, close_white_worms,
575 number_close_white_worms, 5);
576}
577
578static void
579do_compute_effective_worm_sizes(int color, int (*cw)[MAX_CLOSE_WORMS],
580 int *ncw, int max_distance)
581{
582 int pos;
583
584 /* Distance to closest worm, -1 means unassigned, 0 that there is
585 * a stone at the location, 1 a liberty of a stone, and so on.
586 */
587 int distance[BOARDMAX];
588 /* Pointer to the origin of the closest worms. A very large number of
589 * worms may potentially be equally close, but no more than
590 * 2*(board_size-1).
591 */
592 static int worms[BOARDMAX][2*(MAX_BOARD-1)];
593 int nworms[BOARDMAX]; /* number of equally close worms */
594 int found_one;
595 int dist; /* current distance */
596 int k, l;
597 int r;
598
599 /* Initialize arrays. */
600 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
601 if (!ON_BOARD(pos))
602 continue;
603
604 for (k = 0; k < 2*(board_size-1); k++)
605 worms[pos][k] = NO_MOVE;
606
607 nworms[pos] = 0;
608
609 if (board[pos] & color) {
610 distance[pos] = 0;
611 worms[pos][0] = worm[pos].origin;
612 nworms[pos]++;
613 }
614 else
615 distance[pos] = -1;
616 }
617
618 dist = 0;
619 found_one = 1;
620 while (found_one && dist <= max_distance) {
621 found_one = 0;
622 dist++;
623 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
624 if (!ON_BOARD(pos) || distance[pos] != -1)
625 continue; /* already claimed */
626
627 for (r = 0; r < 4; r++) {
628 int pos2 = pos + delta[r];
629
630 if (ON_BOARD(pos2) && distance[pos2] == dist - 1) {
631 found_one = 1;
632 distance[pos] = dist;
633 for (k = 0; k < nworms[pos2]; k++) {
634 int already_counted = 0;
635 for (l = 0; l < nworms[pos]; l++)
636 if (worms[pos][l] == worms[pos2][k]) {
637 already_counted = 1;
638 break;
639 }
640 if (!already_counted) {
641 ASSERT1(nworms[pos] < 2*(board_size-1), pos);
642 worms[pos][nworms[pos]] = worms[pos2][k];
643 nworms[pos]++;
644 }
645 }
646 }
647 }
648 }
649 }
650
651 /* Compute the effective sizes but only when all worms are considered. */
652 if (color == (BLACK | WHITE)) {
653 /* Distribute (fractional) contributions to the worms. */
654 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
655 if (!ON_BOARD(pos))
656 continue;
657
658 for (k = 0; k < nworms[pos]; k++) {
659 int w = worms[pos][k];
660 if (board[pos] == EMPTY)
661 worm[w].effective_size += 0.5/nworms[pos];
662 else
663 worm[w].effective_size += 1.0;
664 }
665 }
666
667 /* Propagate the effective size values all over the worms. */
668 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
669 if (IS_STONE(board[pos]) && is_worm_origin(pos, pos))
670 propagate_worm(pos);
671 }
672
673 /* Fill in the appropriate close_*_worms (cw) and
674 * number_close_*_worms (ncw) arrays.
675 */
676 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
677 if (!ON_BOARD(pos))
678 continue;
679
680 if (nworms[pos] > MAX_CLOSE_WORMS)
681 ncw[pos] = 0;
682 else
683 ncw[pos] = nworms[pos];
684
685 for (k = 0; k < ncw[pos]; k++)
686 cw[pos][k] = worms[pos][k];
687 }
688}
689
690/* Identify worms which are unconditionally uncapturable in the
691 * strongest sense, i.e. even if the opponent is allowed an arbitrary
692 * number of consecutive moves. Also identify worms which are
693 * similarly unconditionally dead and empty points which are
694 * unconditional territory for either player.
695 */
696static void
697compute_unconditional_status()
698{
699 int unconditional_territory[BOARDMAX];
700 int pos;
701 int color;
702
703 for (color = WHITE; color <= BLACK; color++) {
704 unconditional_life(unconditional_territory, color);
705 if (get_level() >= 10)
706 find_unconditionally_meaningless_moves(unconditional_territory, color);
707
708 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
709 if (!ON_BOARD(pos) || !unconditional_territory[pos])
710 continue;
711
712 if (board[pos] == color) {
713 worm[pos].unconditional_status = ALIVE;
714 if (unconditional_territory[pos] == 1)
715 worm[pos].invincible = 1;
716 }
717 else if (board[pos] == EMPTY) {
718 if (color == WHITE)
719 worm[pos].unconditional_status = WHITE_TERRITORY;
720 else
721 worm[pos].unconditional_status = BLACK_TERRITORY;
722 }
723 else
724 worm[pos].unconditional_status = DEAD;
725 }
726 }
727 gg_assert(stackp == 0);
728}
729
730/*
731 * Analyze tactical safety of each worm.
732 */
733
734static void
735find_worm_attacks_and_defenses()
736{
737 int str;
738 int k;
739 int acode, dcode;
740 int attack_point;
741 int defense_point;
742 static int libs[MAXLIBS];
743 int liberties;
744 int color;
745 int other;
746
747 /* 1. Start with finding attack points. */
748 for (str = BOARDMIN; str < BOARDMAX; str++) {
749 if (!IS_STONE(board[str]) || !is_worm_origin(str, str))
750 continue;
751
752 TRACE("considering attack of %1m\n", str);
753 /* Initialize all relevant fields at once. */
754 for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
755 worm[str].attack_codes[k] = 0;
756 worm[str].attack_points[k] = 0;
757 worm[str].defense_codes[k] = 0;
758 worm[str].defense_points[k] = 0;
759 }
760 propagate_worm(str);
761
762 acode = attack(str, &attack_point);
763 if (acode != 0) {
764 DEBUG(DEBUG_WORMS, "worm at %1m can be attacked at %1m\n",
765 str, attack_point);
766 change_attack(str, attack_point, acode);
767 }
768 }
769 gg_assert(stackp == 0);
770
771 /* 2. Use pattern matching to find a few more attacks. */
772 find_attack_patterns();
773 gg_assert(stackp == 0);
774
775 /* 3. Now find defense moves. */
776 for (str = BOARDMIN; str < BOARDMAX; str++) {
777 if (!IS_STONE(board[str]) || !is_worm_origin(str, str))
778 continue;
779
780 if (worm[str].attack_codes[0] != 0) {
781
782 TRACE("considering defense of %1m\n", str);
783 dcode = find_defense(str, &defense_point);
784 if (dcode != 0) {
785 TRACE("worm at %1m can be defended at %1m\n", str, defense_point);
786 if (defense_point != NO_MOVE)
787 change_defense(str, defense_point, dcode);
788 }
789 else {
790 /* If the point of attack is not adjacent to the worm,
791 * it is possible that this is an overlooked point of
792 * defense, so we try and see if it defends.
793 */
794 attack_point = worm[str].attack_points[0];
795 if (!liberty_of_string(attack_point, str))
796 if (trymove(attack_point, worm[str].color, "make_worms", NO_MOVE)) {
797 int acode = attack(str, NULL);
798 if (acode != WIN) {
799 change_defense(str, attack_point, REVERSE_RESULT(acode));
800 TRACE("worm at %1m can be defended at %1m with code %d\n",
801 str, attack_point, REVERSE_RESULT(acode));
802 }
803 popgo();
804 }
805 }
806 }
807 }
808 gg_assert(stackp == 0);
809
810 /* 4. Use pattern matching to find a few more defense moves. */
811 find_defense_patterns();
812 gg_assert(stackp == 0);
813
814 /*
815 * 5. Find additional attacks and defenses by testing all immediate
816 * liberties. Further attacks and defenses are found by pattern
817 * matching and by trying whether each attack or defense point
818 * attacks or defends other strings.
819 */
820 for (str = BOARDMIN; str < BOARDMAX; str++) {
821 color = board[str];
822 if (!IS_STONE(color) || !is_worm_origin(str, str))
823 continue;
824
825 other = OTHER_COLOR(color);
826
827 if (worm[str].attack_codes[0] == 0)
828 continue;
829
830 /* There is at least one attack on this group. Try the
831 * liberties.
832 */
833 liberties = findlib(str, MAXLIBS, libs);
834
835 for (k = 0; k < liberties; k++) {
836 int pos = libs[k];
837 if (!attack_move_known(pos, str)) {
838 /* Try to attack on the liberty. Don't consider
839 * send-two-return-one moves.
840 */
841 if (!send_two_return_one(pos, other)
842 && trymove(pos, other, "make_worms", str)) {
843 if (board[str] == EMPTY || attack(str, NULL)) {
844 if (board[str] == EMPTY)
845 dcode = 0;
846 else
847 dcode = find_defense(str, NULL);
848
849 if (dcode != WIN)
850 change_attack(str, pos, REVERSE_RESULT(dcode));
851 }
852 popgo();
853 }
854 }
855 /* Try to defend at the liberty. */
856 if (!defense_move_known(pos, str)) {
857 if (worm[str].defense_codes[0] != 0)
858 if (trymove(pos, color, "make_worms", NO_MOVE)) {
859 acode = attack(str, NULL);
860 if (acode != WIN)
861 change_defense(str, pos, REVERSE_RESULT(acode));
862 popgo();
863 }
864 }
865 }
866 }
867 gg_assert(stackp == 0);
868}
869
870
871/*
872 * Find moves threatening to attack or save all worms.
873 */
874
875static void
876find_worm_threats()
877{
878 int str;
879 static int libs[MAXLIBS];
880 int liberties;
881
882 int k;
883 int l;
884 int color;
885
886 for (str = BOARDMIN; str < BOARDMAX; str++) {
887 color = board[str];
888 if (!IS_STONE(color) || !is_worm_origin(str, str))
889 continue;
890
891 /* 1. Start with finding attack threats. */
892 /* Only try those worms that have no attack. */
893 if (worm[str].attack_codes[0] == 0) {
894 attack_threats(str, MAX_TACTICAL_POINTS,
895 worm[str].attack_threat_points,
896 worm[str].attack_threat_codes);
897#if 0
898 /* Threaten to attack by saving weak neighbors. */
899 num_adj = chainlinks(str, adjs);
900 for (k = 0; k < num_adj; k++) {
901 if (worm[adjs[k]].attack_codes[0] != 0
902 && worm[adjs[k]].defense_codes[0] != 0)
903 for (r = 0; r < MAX_TACTICAL_POINTS; r++) {
904 int bb;
905
906 if (worm[adjs[k]].defense_codes[r] == 0)
907 break;
908 bb = worm[adjs[k]].defense_points[r];
909 if (trymove(bb, other, "threaten attack", str,
910 EMPTY, NO_MOVE)) {
911 int acode;
912 if (board[str] == EMPTY)
913 acode = WIN;
914 else
915 acode = attack(str, NULL);
916 if (acode != 0)
917 change_attack_threat(str, bb, acode);
918 popgo();
919 }
920 }
921 }
922#endif
923 /* FIXME: Try other moves also (patterns?). */
924 }
925
926 /* 2. Continue with finding defense threats. */
927 /* Only try those worms that have an attack. */
928 if (worm[str].attack_codes[0] != 0
929 && worm[str].defense_codes[0] == 0) {
930
931 liberties = findlib(str, MAXLIBS, libs);
932
933 for (k = 0; k < liberties; k++) {
934 int aa = libs[k];
935
936 /* Try to threaten on the liberty. */
937 if (trymove(aa, color, "threaten defense", NO_MOVE)) {
938 if (attack(str, NULL) == WIN) {
939 int dcode = find_defense(str, NULL);
940 if (dcode != 0)
941 change_defense_threat(str, aa, dcode);
942 }
943 popgo();
944 }
945
946 /* Try to threaten on second order liberties. */
947 for (l = 0; l < 4; l++) {
948 int bb = libs[k] + delta[l];
949
950 if (!ON_BOARD(bb)
951 || IS_STONE(board[bb])
952 || liberty_of_string(bb, str))
953 continue;
954
955 if (trymove(bb, color, "threaten defense", str)) {
956 if (attack(str, NULL) == WIN) {
957 int dcode = find_defense(str, NULL);
958 if (dcode != 0)
959 change_defense_threat(str, bb, dcode);
960 }
961 popgo();
962 }
963 }
964 }
965
966 /* It might be interesting to look for defense threats by
967 * attacking weak neighbors, similar to threatening attack by
968 * defending a weak neighbor. However, in this case it seems
969 * probable that if there is such an attack, it's a real
970 * defense, not only a threat.
971 */
972
973 /* FIXME: Try other moves also (patterns?). */
974 }
975 }
976}
977
978
979/* find_lunch(str, &worm) looks for a worm adjoining the
980 * string at (str) which can be easily captured. Whether or not it can
981 * be defended doesn't matter.
982 *
983 * Returns the location of the string in (*lunch).
984 */
985
986static int
987find_lunch(int str, int *lunch)
988{
989 int pos;
990 int k;
991
992 ASSERT1(IS_STONE(board[str]), str);
993 ASSERT1(stackp == 0, str);
994
995 *lunch = NO_MOVE;
996 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
997 if (board[pos] != OTHER_COLOR(board[str]))
998 continue;
999 for (k = 0; k < 8; k++) {
1000 int apos = pos + delta[k];
1001 if (ON_BOARD(apos) && is_same_worm(apos, str)) {
1002 if (worm[pos].attack_codes[0] != 0 && !is_ko_point(pos)) {
1003 /*
1004 * If several adjacent lunches are found, we pick the
1005 * juiciest. First maximize cutstone, then minimize liberties.
1006 * We can only do this if the worm data is available,
1007 * i.e. if stackp==0.
1008 */
1009 if (*lunch == NO_MOVE
1010 || worm[pos].cutstone > worm[*lunch].cutstone
1011 || (worm[pos].cutstone == worm[*lunch].cutstone
1012 && worm[pos].liberties < worm[*lunch].liberties)) {
1013 *lunch = worm[pos].origin;
1014 }
1015 }
1016 break;
1017 }
1018 }
1019 }
1020
1021 if (*lunch != NO_MOVE)
1022 return 1;
1023
1024 return 0;
1025}
1026
1027
1028/*
1029 * Test whether two worms are the same. Used by autohelpers.
1030 * Before this function can be called, build_worms must have been run.
1031 */
1032
1033int
1034is_same_worm(int w1, int w2)
1035{
1036 return worm[w1].origin == worm[w2].origin;
1037}
1038
1039
1040/*
1041 * Test whether the origin of the worm at (w) is (pos).
1042 */
1043
1044int
1045is_worm_origin(int w, int pos)
1046{
1047 return worm[w].origin == pos;
1048}
1049
1050
1051/*
1052 * change_defense(str, move, dcode) is used to add and remove defense
1053 * points. It can also be used to change the defense code. The meaning
1054 * of the call is that the string (str) can be defended by (move) with
1055 * defense code (dcode). If (dcode) is zero, the move is removed from
1056 * the list of defense moves if it was previously listed.
1057 */
1058
1059void
1060change_defense(int str, int move, int dcode)
1061{
1062 str = worm[str].origin;
1063 change_tactical_point(str, move, dcode,
1064 worm[str].defense_points, worm[str].defense_codes);
1065}
1066
1067
1068/*
1069 * change_attack(str, move, acode) is used to add and remove attack
1070 * points. It can also be used to change the attack code. The meaning
1071 * of the call is that the string (str) can be attacked by (move) with
1072 * attack code (acode). If (acode) is zero, the move is removed from
1073 * the list of attack moves if it was previously listed.
1074 */
1075
1076void
1077change_attack(int str, int move, int acode)
1078{
1079 str = worm[str].origin;
1080 DEBUG(DEBUG_WORMS, "change_attack: %1m %1m %d\n", str, move, acode);
1081 change_tactical_point(str, move, acode,
1082 worm[str].attack_points, worm[str].attack_codes);
1083}
1084
1085
1086/*
1087 * change_defense_threat(str, move, dcode) is used to add and remove
1088 * defense threat points. It can also be used to change the defense
1089 * threat code. The meaning of the call is that the string (str) can
1090 * threaten to be defended by (move) with defense threat code (dcode).
1091 * If (dcode) is zero, the move is removed from the list of defense
1092 * threat moves if it was previously listed.
1093 */
1094
1095void
1096change_defense_threat(int str, int move, int dcode)
1097{
1098 str = worm[str].origin;
1099 change_tactical_point(str, move, dcode,
1100 worm[str].defense_threat_points,
1101 worm[str].defense_threat_codes);
1102}
1103
1104
1105/*
1106 * change_attack_threat(str, move, acode) is used to add and remove
1107 * attack threat points. It can also be used to change the attack
1108 * threat code. The meaning of the call is that the string (str) can
1109 * threaten to be attacked by (move) with attack threat code (acode).
1110 * If (acode) is zero, the move is removed from the list of attack
1111 * threat moves if it was previously listed.
1112 */
1113
1114void
1115change_attack_threat(int str, int move, int acode)
1116{
1117 str = worm[str].origin;
1118 change_tactical_point(str, move, acode,
1119 worm[str].attack_threat_points,
1120 worm[str].attack_threat_codes);
1121}
1122
1123
1124/* Check whether (move) is listed as an attack point for (str) and
1125 * return the attack code. If (move) is not listed, return 0.
1126 */
1127int
1128attack_move_known(int move, int str)
1129{
1130 return movelist_move_known(move, MAX_TACTICAL_POINTS,
1131 worm[str].attack_points,
1132 worm[str].attack_codes);
1133}
1134
1135/* Check whether (move) is listed as a defense point for (str) and
1136 * return the defense code. If (move) is not listed, return 0.
1137 */
1138int
1139defense_move_known(int move, int str)
1140{
1141 return movelist_move_known(move, MAX_TACTICAL_POINTS,
1142 worm[str].defense_points,
1143 worm[str].defense_codes);
1144}
1145
1146/* Check whether (move) is listed as an attack threat point for (str)
1147 * and return the attack threat code. If (move) is not listed, return
1148 * 0.
1149 */
1150int
1151attack_threat_move_known(int move, int str)
1152{
1153 return movelist_move_known(move, MAX_TACTICAL_POINTS,
1154 worm[str].attack_threat_points,
1155 worm[str].attack_threat_codes);
1156}
1157
1158/* Check whether (move) is listed as a defense threat point for (str)
1159 * and return the defense threat code. If (move) is not listed, return
1160 * 0.
1161 */
1162int
1163defense_threat_move_known(int move, int str)
1164{
1165 return movelist_move_known(move, MAX_TACTICAL_POINTS,
1166 worm[str].defense_threat_points,
1167 worm[str].defense_threat_codes);
1168}
1169
1170
1171/*
1172 * This function does the real work for change_attack(),
1173 * change_defense(), change_attack_threat(), and
1174 * change_defense_threat().
1175 */
1176
1177static void
1178change_tactical_point(int str, int move, int code,
1179 int points[MAX_TACTICAL_POINTS],
1180 int codes[MAX_TACTICAL_POINTS])
1181{
1182 ASSERT_ON_BOARD1(str);
1183 ASSERT1(str == worm[str].origin, str);
1184
1185 movelist_change_point(move, code, MAX_TACTICAL_POINTS, points, codes);
1186 propagate_worm2(str);
1187}
1188
1189
1190/*
1191 * propagate_worm() takes the worm data at one stone and copies it to
1192 * the remaining members of the worm.
1193 *
1194 * Even though we don't need to copy all the fields, it's probably
1195 * better to do a structure copy which should compile to a block copy.
1196 */
1197
1198void
1199propagate_worm(int pos)
1200{
1201 int k;
1202 int num_stones;
1203 int stones[MAX_BOARD * MAX_BOARD];
1204 gg_assert(stackp == 0);
1205 ASSERT1(IS_STONE(board[pos]), pos);
1206
1207 num_stones = findstones(pos, MAX_BOARD * MAX_BOARD, stones);
1208 for (k = 0; k < num_stones; k++)
1209 if (stones[k] != pos)
1210 worm[stones[k]] = worm[pos];
1211}
1212
1213
1214/*
1215 * propagate_worm2() is a relative to propagate_worm() which can be
1216 * used when stackp>0 but not for the initial construction of the
1217 * worms.
1218 */
1219
1220static void
1221propagate_worm2(int str)
1222{
1223 int pos;
1224 ASSERT_ON_BOARD1(str);
1225 ASSERT1(IS_STONE(worm[str].color), str);
1226
1227 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
1228 if (board[pos] == board[str] && is_same_worm(pos, str)
1229 && pos != str)
1230 worm[pos] = worm[str];
1231}
1232
1233
1234/* Report all known attack, defense, attack threat, and defense threat
1235 * moves. But limit this to the moves which can be made by (color).
1236 */
1237void
1238worm_reasons(int color)
1239{
1240 int pos;
1241 int k;
1242
1243 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1244 if (!ON_BOARD(pos) || board[pos] == EMPTY)
1245 continue;
1246
1247 if (!is_worm_origin(pos, pos))
1248 continue;
1249
1250 if (board[pos] == OTHER_COLOR(color)) {
1251 for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
1252 if (worm[pos].attack_codes[k] != 0)
1253 add_attack_move(worm[pos].attack_points[k], pos,
1254 worm[pos].attack_codes[k]);
1255 if (worm[pos].attack_threat_codes[k] != 0)
1256 add_attack_threat_move(worm[pos].attack_threat_points[k], pos,
1257 worm[pos].attack_threat_codes[k]);
1258 }
1259 }
1260
1261 if (board[pos] == color) {
1262 for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
1263 if (worm[pos].defense_codes[k] != 0)
1264 add_defense_move(worm[pos].defense_points[k], pos,
1265 worm[pos].defense_codes[k]);
1266
1267 if (worm[pos].defense_threat_codes[k] != 0)
1268 add_defense_threat_move(worm[pos].defense_threat_points[k], pos,
1269 worm[pos].defense_threat_codes[k]);
1270 }
1271 }
1272 }
1273}
1274
1275
1276/* ping_cave(str, *lib1, ...) is applied when (str) points to a string.
1277 * It computes the vector (*lib1, *lib2, *lib3, *lib4),
1278 * where *lib1 is the number of liberties of the string,
1279 * *lib2 is the number of second order liberties (empty vertices
1280 * at distance two) and so forth.
1281 *
1282 * The definition of liberties of order >1 is adapted to the problem
1283 * of detecting the shape of the surrounding cavity. In particular
1284 * we want to be able to see if a group is loosely surrounded.
1285 *
1286 * A liberty of order n is an empty space which may be connected
1287 * to the string by placing n stones of the same color on the board,
1288 * but no fewer. The path of connection may pass through an intervening group
1289 * of the same color. The stones placed at distance >1 may not touch a
1290 * group of the opposite color. At the edge, also diagonal neighbors
1291 * count as touching. The path may also not pass through a liberty at distance
1292 * 1 if that liberty is flanked by two stones of the opposing color. This
1293 * reflects the fact that the O stone is blocked from expansion to the
1294 * left by the two X stones in the following situation:
1295 *
1296 * X.
1297 * .O
1298 * X.
1299 *
1300 * On the edge, one stone is sufficient to block expansion:
1301 *
1302 * X.
1303 * .O
1304 * --
1305 */
1306
1307static void
1308ping_cave(int str, int *lib1, int *lib2, int *lib3, int *lib4)
1309{
1310 int pos;
1311 int k;
1312 int libs[MAXLIBS];
1313 int mrc[BOARDMAX];
1314 int mse[BOARDMAX];
1315 int color = board[str];
1316 int other = OTHER_COLOR(color);
1317
1318 memset(mse, 0, sizeof(mse));
1319
1320 /* Find and mark the first order liberties. */
1321 *lib1 = findlib(str, MAXLIBS, libs);
1322 for (k = 0; k < *lib1; k++)
1323 mse[libs[k]] = 1;
1324
1325 /* Reset mse at liberties which are flanked by two stones of the
1326 * opposite color, or one stone and the edge.
1327 */
1328
1329 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
1330 if (ON_BOARD(pos)
1331 && mse[pos]
1332 && ((( !ON_BOARD(SOUTH(pos)) || board[SOUTH(pos)] == other)
1333 && ( !ON_BOARD(NORTH(pos)) || board[NORTH(pos)] == other))
1334 || (( !ON_BOARD(WEST(pos)) || board[WEST(pos)] == other)
1335 && (!ON_BOARD(EAST(pos)) || board[EAST(pos)] == other))))
1336 mse[pos] = 0;
1337
1338 *lib2 = 0;
1339 memset(mrc, 0, sizeof(mrc));
1340 ping_recurse(str, lib2, mse, mrc, color);
1341
1342 *lib3 = 0;
1343 memset(mrc, 0, sizeof(mrc));
1344 ping_recurse(str, lib3, mse, mrc, color);
1345
1346 *lib4 = 0;
1347 memset(mrc, 0, sizeof(mrc));
1348 ping_recurse(str, lib4, mse, mrc, color);
1349}
1350
1351
1352/* recursive function called by ping_cave */
1353
1354static void
1355ping_recurse(int pos, int *counter,
1356 int mx[BOARDMAX], int mr[BOARDMAX],
1357 int color)
1358{
1359 int k;
1360 mr[pos] = 1;
1361
1362 for (k = 0; k < 4; k++) {
1363 int apos = pos + delta[k];
1364 if (board[apos] == EMPTY
1365 && mx[apos] == 0
1366 && mr[apos] == 0
1367 && !touching(apos, OTHER_COLOR(color))) {
1368 (*counter)++;
1369 mr[apos] = 1;
1370 mx[apos] = 1;
1371 }
1372 }
1373
1374 if (!is_ko_point(pos)) {
1375 for (k = 0; k < 4; k++) {
1376 int apos = pos + delta[k];
1377 if (ON_BOARD(apos)
1378 && mr[apos] == 0
1379 && (mx[apos] == 1
1380 || board[apos] == color))
1381 ping_recurse(apos, counter, mx, mr, color);
1382 }
1383 }
1384}
1385
1386
1387/* touching(pos, color) returns true if the vertex at (pos) is
1388 * touching any stone of (color).
1389 */
1390
1391static int
1392touching(int pos, int color)
1393{
1394 return (board[SOUTH(pos)] == color
1395 || board[WEST(pos)] == color
1396 || board[NORTH(pos)] == color
1397 || board[EAST(pos)] == color);
1398}
1399
1400
1401/* The GENUS of a string is the number of connected components of
1402 * its complement, minus one. It is an approximation to the number of
1403 * eyes of the string.
1404 */
1405
1406static int
1407genus(int str)
1408{
1409 int pos;
1410 int mg[BOARDMAX];
1411 int gen = -1;
1412
1413 memset(mg, 0, sizeof(mg));
1414 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1415 if (ON_BOARD(pos)
1416 && !mg[pos]
1417 && (board[pos] == EMPTY || !is_same_worm(pos, str))) {
1418 markcomponent(str, pos, mg);
1419 gen++;
1420 }
1421 }
1422
1423 return gen;
1424}
1425
1426
1427/* This recursive function marks the component at (pos) of
1428 * the complement of the string with origin (str)
1429 */
1430
1431static void
1432markcomponent(int str, int pos, int mg[BOARDMAX])
1433{
1434 int k;
1435 mg[pos] = 1;
1436 for (k = 0; k < 4; k++) {
1437 int apos = pos + delta[k];
1438 if (ON_BOARD(apos)
1439 && mg[apos] == 0
1440 && (board[apos] == EMPTY || !is_same_worm(apos, str)))
1441 markcomponent(str, apos, mg);
1442 }
1443}
1444
1445
1446/* examine_cavity(pos, *edge), if (pos) is EMPTY, examines the
1447 * cavity at (m, n) and returns its bordercolor,
1448 * which can be BLACK, WHITE or GRAY. The edge parameter is set to the
1449 * number of edge vertices in the cavity.
1450 *
1451 * If (pos) is nonempty, it returns the same result, imagining
1452 * that the string at (pos) is removed. The edge parameter is
1453 * set to the number of vertices where the cavity meets the
1454 * edge in a point outside the removed string.
1455 */
1456
1457static int
1458examine_cavity(int pos, int *edge)
1459{
1460 int border_color = EMPTY;
1461 int ml[BOARDMAX];
1462 int origin = NO_MOVE;
1463
1464 ASSERT_ON_BOARD1(pos);
1465 gg_assert(edge != NULL);
1466
1467 memset(ml, 0, sizeof(ml));
1468
1469 *edge = 0;
1470
1471 if (IS_STONE(board[pos]))
1472 origin = find_origin(pos);
1473
1474 cavity_recurse(pos, ml, &border_color, edge, origin);
1475
1476 if (border_color != EMPTY)
1477 return border_color;
1478
1479 /* We should have returned now, unless the board is completely empty.
1480 * Verify that this is the case and then return GRAY.
1481 *
1482 * Notice that the board appears completely empty if there's only a
1483 * single string and pos points to it.
1484 */
1485 gg_assert(border_color == EMPTY
1486 && ((pos == NO_MOVE
1487 && stones_on_board(BLACK | WHITE) == 0)
1488 || (pos != NO_MOVE
1489 && stones_on_board(BLACK | WHITE) == countstones(pos))));
1490
1491 return GRAY;
1492}
1493
1494
1495/* helper function for examine_cavity.
1496 * border_color contains information so far : transitions allowed are
1497 * EMPTY -> BLACK/WHITE
1498 * BLACK/WHITE -> BLACK | WHITE
1499 *
1500 * mx[pos] is 1 if (pos) has already been visited.
1501 *
1502 * if (str) points to the origin of a string, it will be ignored.
1503 *
1504 * On (fully-unwound) exit
1505 * *border_color should be BLACK, WHITE or BLACK | WHITE
1506 * *edge is the count of edge pieces
1507 *
1508 * *border_color should be EMPTY if and only if the board
1509 * is completely empty or only contains the ignored string.
1510 */
1511
1512static void
1513cavity_recurse(int pos, int mx[BOARDMAX],
1514 int *border_color, int *edge, int str)
1515{
1516 int k;
1517 ASSERT1(mx[pos] == 0, pos);
1518
1519 mx[pos] = 1;
1520
1521 if (is_edge_vertex(pos) && board[pos] == EMPTY)
1522 (*edge)++;
1523
1524 /* Loop over the four neighbors. */
1525 for (k = 0; k < 4; k++) {
1526 int apos = pos + delta[k];
1527 if (ON_BOARD(apos) && !mx[apos]) {
1528 int neighbor_empty = 0;
1529
1530 if (board[apos] == EMPTY)
1531 neighbor_empty = 1;
1532 else {
1533 /* Count the neighbor as empty if it is part of the (ai, aj) string. */
1534 if (str == find_origin(apos))
1535 neighbor_empty = 1;
1536 else
1537 neighbor_empty = 0;
1538 }
1539
1540 if (!neighbor_empty)
1541 *border_color |= board[apos];
1542 else
1543 cavity_recurse(apos, mx, border_color, edge, str);
1544 }
1545 }
1546}
1547
1548
1549/* Find attacking moves by pattern matching, for both colors. */
1550static void
1551find_attack_patterns(void)
1552{
1553 matchpat(attack_callback, ANCHOR_OTHER, &attpat_db, NULL, NULL);
1554}
1555
1556/* Try to attack every X string in the pattern, whether there is an attack
1557 * before or not. Only exclude already known attacking moves.
1558 */
1559static void
1560attack_callback(int anchor, int color, struct pattern *pattern, int ll,
1561 void *data)
1562{
1563 int move;
1564 int k;
1565 UNUSED(data);
1566
1567 move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
1568
1569 /* If the pattern has a constraint, call the autohelper to see
1570 * if the pattern must be rejected.
1571 */
1572 if (pattern->autohelper_flag & HAVE_CONSTRAINT) {
1573 if (!pattern->autohelper(ll, move, color, 0))
1574 return;
1575 }
1576
1577 /* If the pattern has a helper, call it to see if the pattern must
1578 * be rejected.
1579 */
1580 if (pattern->helper) {
1581 if (!pattern->helper(pattern, ll, move, color)) {
1582 DEBUG(DEBUG_WORMS,
1583 "Attack pattern %s+%d rejected by helper at %1m\n",
1584 pattern->name, ll, move);
1585 return;
1586 }
1587 }
1588
1589 /* Loop through pattern elements in search of X strings to attack. */
1590 for (k = 0; k < pattern->patlen; ++k) { /* match each point */
1591 if (pattern->patn[k].att == ATT_X) {
1592 /* transform pattern real coordinate */
1593 int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
1594
1595 int str = worm[pos].origin;
1596
1597 /* A string with 5 liberties or more is considered tactically alive. */
1598 if (countlib(str) > 4)
1599 continue;
1600
1601 if (attack_move_known(move, str))
1602 continue;
1603
1604 /* No defenses are known at this time, so defend_code is always 0. */
1605#if 0
1606 /* If the string can be attacked but not defended, ignore it. */
1607 if (worm[str].attack_codes[0] == WIN && worm[str].defense_codes[0] == 0)
1608 continue;
1609#endif
1610
1611 /* FIXME: Don't attack the same string more than once.
1612 * Play (move) and see if there is a defense.
1613 */
1614 if (trymove(move, color, "attack_callback", str)) {
1615 int dcode;
1616 if (!board[str])
1617 dcode = 0;
1618 else if (!attack(str, NULL))
1619 dcode = WIN;
1620 else
1621 dcode = find_defense(str, NULL);
1622
1623 popgo();
1624
1625 /* Do not pick up suboptimal attacks at this time. Since we
1626 * don't know whether the string can be defended it's quite
1627 * possible that it only has a ko defense and then we would
1628 * risk to find an irrelevant move to attack with ko.
1629 */
1630 if (dcode != WIN && REVERSE_RESULT(dcode) >= worm[str].attack_codes[0]) {
1631 change_attack(str, move, REVERSE_RESULT(dcode));
1632 DEBUG(DEBUG_WORMS,
1633 "Attack pattern %s+%d found attack on %1m at %1m with code %d\n",
1634 pattern->name, ll, str, move, REVERSE_RESULT(dcode));
1635 }
1636 }
1637 }
1638 }
1639}
1640
1641static void
1642find_defense_patterns(void)
1643{
1644 matchpat(defense_callback, ANCHOR_COLOR, &defpat_db, NULL, NULL);
1645}
1646
1647static void
1648defense_callback(int anchor, int color, struct pattern *pattern, int ll,
1649 void *data)
1650{
1651 int move;
1652 int k;
1653 UNUSED(data);
1654
1655 move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
1656
1657 /* If the pattern has a constraint, call the autohelper to see
1658 * if the pattern must be rejected.
1659 */
1660 if (pattern->autohelper_flag & HAVE_CONSTRAINT) {
1661 if (!pattern->autohelper(ll, move, color, 0))
1662 return;
1663 }
1664
1665 /* If the pattern has a helper, call it to see if the pattern must
1666 * be rejected.
1667 */
1668 if (pattern->helper) {
1669 if (!pattern->helper(pattern, ll, move, color)) {
1670 DEBUG(DEBUG_WORMS,
1671 "Defense pattern %s+%d rejected by helper at %1m\n",
1672 pattern->name, ll, move);
1673 return;
1674 }
1675 }
1676
1677 /* Loop through pattern elements in search for O strings to defend. */
1678 for (k = 0; k < pattern->patlen; ++k) { /* match each point */
1679 if (pattern->patn[k].att == ATT_O) {
1680 /* transform pattern real coordinate */
1681 int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
1682 int str = worm[pos].origin;
1683
1684 if (worm[str].attack_codes[0] == 0
1685 || defense_move_known(move, str))
1686 continue;
1687
1688 /* FIXME: Don't try to defend the same string more than once.
1689 * FIXME: For all attacks on this string, we should test whether
1690 * the proposed move happens to refute the attack.
1691 * Play (move) and see if there is an attack.
1692 */
1693 if (trymove(move, color, "defense_callback", str)) {
1694 int acode = attack(str, NULL);
1695
1696 popgo();
1697
1698 if (acode < worm[str].attack_codes[0]) {
1699 change_defense(str, move, REVERSE_RESULT(acode));
1700 DEBUG(DEBUG_WORMS,
1701 "Defense pattern %s+%d found defense of %1m at %1m with code %d\n",
1702 pattern->name, ll, str, move, REVERSE_RESULT(acode));
1703 }
1704 }
1705 }
1706 }
1707}
1708
1709
1710void
1711get_lively_stones(int color, signed char safe_stones[BOARDMAX])
1712{
1713 int pos;
1714 memset(safe_stones, 0, BOARDMAX * sizeof(*safe_stones));
1715 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
1716 if (IS_STONE(board[pos]) && find_origin(pos) == pos) {
1717 if ((stackp == 0 && worm[pos].attack_codes[0] == 0) || !attack(pos, NULL)
1718 || (board[pos] == color
1719 && ((stackp == 0 && worm[pos].defense_codes[0] != 0)
1720 || find_defense(pos, NULL))))
1721 mark_string(pos, safe_stones, 1);
1722 }
1723}
1724
1725
1726void
1727compute_worm_influence()
1728{
1729 signed char safe_stones[BOARDMAX];
1730
1731 get_lively_stones(BLACK, safe_stones);
1732 compute_influence(BLACK, safe_stones, NULL, &initial_black_influence,
1733 NO_MOVE, "initial black influence");
1734 get_lively_stones(WHITE, safe_stones);
1735 compute_influence(WHITE, safe_stones, NULL, &initial_white_influence,
1736 NO_MOVE, "initial white influence");
1737}
1738
1739/* ================================================================ */
1740/* Debugger functions */
1741/* ================================================================ */
1742
1743/* For use in gdb, print details of the worm at (m, n).
1744 * Add this to your .gdbinit file:
1745 *
1746 * define worm
1747 * set ascii_report_worm("$arg0")
1748 * end
1749 *
1750 * Now 'worm S8' will report the details of the S8 worm.
1751 *
1752 */
1753
1754void
1755ascii_report_worm(char *string)
1756{
1757 int pos = string_to_location(board_size, string);
1758 report_worm(pos);
1759}
1760
1761
1762static void
1763report_worm(int pos)
1764{
1765 int i;
1766
1767 if (board[pos] == EMPTY) {
1768 gprintf("There is no worm at %1m\n", pos);
1769 return;
1770 }
1771
1772 gprintf("*** worm at %1m:\n", pos);
1773 gprintf("color: %s; origin: %1m; size: %d; effective size: %f\n",
1774 (worm[pos].color == WHITE) ? "White" : "Black",
1775 worm[pos].origin, worm[pos].size, worm[pos].effective_size);
1776
1777 gprintf("liberties: %d order 2 liberties:%d order 3:%d order 4:%d\n",
1778 worm[pos].liberties,
1779 worm[pos].liberties2,
1780 worm[pos].liberties3,
1781 worm[pos].liberties4);
1782
1783 /* List all attack points. */
1784 if (worm[pos].attack_points[0] == NO_MOVE)
1785 gprintf("no attack point, ");
1786 else {
1787 gprintf("attack point(s):");
1788 i = 0;
1789 while (worm[pos].attack_points[i] != NO_MOVE) {
1790 if (i > 0)
1791 gprintf(",");
1792 gprintf(" %1m: %s", worm[pos].attack_points[i],
1793 result_to_string(worm[pos].attack_codes[i]));
1794 i++;
1795 }
1796 gprintf("\n;");
1797 }
1798
1799 /* List all defense points. */
1800 if (worm[pos].defense_points[0] == NO_MOVE)
1801 gprintf("no defense point, ");
1802 else {
1803 gprintf("defense point(s):");
1804 i = 0;
1805 while (worm[pos].defense_points[i] != NO_MOVE) {
1806 if (i > 0)
1807 gprintf(",");
1808 gprintf(" %1m: %s", worm[pos].defense_points[i],
1809 result_to_string(worm[pos].defense_codes[i]));
1810 i++;
1811 }
1812 gprintf("\n;");
1813 }
1814
1815 /* List all attack threat points. */
1816 if (worm[pos].attack_threat_points[0] == NO_MOVE)
1817 gprintf("no attack threat point, ");
1818 else {
1819 gprintf("attack threat point(s):");
1820 i = 0;
1821 while (worm[pos].attack_threat_points[i] != NO_MOVE) {
1822 if (i > 0)
1823 gprintf(",");
1824 gprintf(" %1m: %s", worm[pos].attack_threat_points[i],
1825 result_to_string(worm[pos].attack_threat_codes[i]));
1826 i++;
1827 }
1828 gprintf("\n;");
1829 }
1830
1831 /* List all defense threat points. */
1832 if (worm[pos].defense_threat_points[0] == NO_MOVE)
1833 gprintf("no defense threat point, ");
1834 else {
1835 gprintf("defense threat point(s):");
1836 i = 0;
1837 while (worm[pos].defense_threat_points[i] != NO_MOVE) {
1838 if (i > 0)
1839 gprintf(",");
1840 gprintf(" %1m: %s", worm[pos].defense_threat_points[i],
1841 result_to_string(worm[pos].defense_threat_codes[i]));
1842 i++;
1843 }
1844 gprintf("\n;");
1845 }
1846
1847 /* Report lunch if any. */
1848 if (worm[pos].lunch != NO_MOVE)
1849 gprintf("lunch at %1m\n", worm[pos].lunch);
1850
1851 gprintf("cutstone: %d, cutstone2: %d\n",
1852 worm[pos].cutstone, worm[pos].cutstone2);
1853
1854 gprintf("genus: %d, ", worm[pos].genus);
1855
1856 if (worm[pos].inessential)
1857 gprintf("inessential: YES, ");
1858 else
1859 gprintf("inessential: NO, ");
1860
1861 if (worm[pos].invincible)
1862 gprintf("invincible: YES, \n");
1863 else
1864 gprintf("invincible: NO, \n");
1865
1866 gprintf("unconditional status %s\n",
1867 status_to_string(worm[pos].unconditional_status));
1868}
1869
1870
1871/*
1872 * Local Variables:
1873 * tab-width: 8
1874 * c-basic-offset: 2
1875 * End:
1876 */