10 is_bad_selfatari_slow(struct board
*b
, enum stone color
, coord_t to
)
12 //fprintf(stderr, "sar check %s %s\n", stone2str(color), coord2sstr(to, b));
13 /* Assess if we actually gain any liberties by this escape route.
14 * Note that this is not 100% as we cannot check whether we are
15 * connecting out or just to ourselves. */
16 int groupcts
[S_MAX
] = {};
17 group_t groupids
[S_MAX
][4] = {};
18 foreach_neighbor(b
, to
, {
19 enum stone s
= board_at(b
, c
);
20 groupids
[s
][groupcts
[s
]++] = group_at(b
, c
);
23 /* We have shortage of liberties; that's the point. */
24 assert(groupcts
[S_NONE
] <= 1);
26 /* This is set if this move puts a group out of _all_
27 * liberties; we need to watch out for snapback then. */
28 bool friend_has_no_libs
= false;
29 /* We may have one liberty, but be looking for one more.
30 * In that case, @needs_more_lib is id of group
31 * already providing one, don't consider it again. */
32 group_t needs_more_lib
= 0;
33 /* ID of the first liberty, providing it again is not
35 coord_t needs_more_lib_except
= 0;
37 /* Examine friendly groups: */
38 for (int i
= 0; i
< 4; i
++) {
39 /* We can escape by connecting to this group if it's
41 group_t g
= groupids
[color
][i
];
44 if (board_group_info(b
, g
).libs
== 1) {
46 friend_has_no_libs
= true;
47 // or we already have a friend with 1 lib
51 /* Could we self-atari the group here? */
52 if (board_group_info(b
, g
).libs
> 2)
55 /* We need to have another liberty, and
56 * it must not be the other liberty of
58 int lib2
= board_group_info(b
, g
).lib
[0];
59 if (lib2
== to
) lib2
= board_group_info(b
, g
).lib
[1];
60 /* Maybe we already looked at another
61 * group providing one liberty? */
62 if (needs_more_lib
&& needs_more_lib
!= g
63 && needs_more_lib_except
!= lib2
)
66 /* Can we get the liberty locally? */
67 /* Yes if we are route to more liberties... */
68 if (groupcts
[S_NONE
] > 1)
70 /* ...or one liberty, but not lib2. */
71 if (groupcts
[S_NONE
] > 0
72 && !coord_is_adjecent(lib2
, to
, b
))
75 /* ...ok, then we can still contribute a liberty
76 * later by capturing something. */
78 needs_more_lib_except
= lib2
;
79 friend_has_no_libs
= false;
82 //fprintf(stderr, "no friendly group\n");
84 /* We may be able to gain a liberty by capturing this group. */
85 group_t can_capture
= 0;
87 /* Examine enemy groups: */
88 for (int i
= 0; i
< 4; i
++) {
89 /* We can escape by capturing this group if it's in atari. */
90 group_t g
= groupids
[stone_other(color
)][i
];
91 if (!g
|| board_group_info(b
, g
).libs
> 1)
94 /* But we need to get to at least two liberties by this;
95 * we already have one outside liberty, or the group is
96 * more than 1 stone (in that case, capturing is always
98 if (groupcts
[S_NONE
] > 0 || !group_is_onestone(b
, g
))
100 /* ...or, it's a ko stone, */
101 if (neighbor_count_at(b
, g
, color
) + neighbor_count_at(b
, g
, S_OFFBOARD
) == 3) {
102 /* and we don't have a group to save: then, just taking
103 * single stone means snapback! */
104 if (!friend_has_no_libs
)
107 /* ...or, we already have one indirect liberty provided
108 * by another group. */
109 if (needs_more_lib
|| (can_capture
&& can_capture
!= g
))
115 //fprintf(stderr, "no cap group\n");
117 if (!needs_more_lib
&& !can_capture
&& !groupcts
[S_NONE
]) {
118 /* We have no hope for more fancy tactics - this move is simply
119 * a suicide, not even a self-atari. */
120 //fprintf(stderr, "suicide\n");
123 /* XXX: I wonder if it makes sense to continue if we actually
124 * just !needs_more_lib. */
126 /* There is another possibility - we can self-atari if it is
127 * a nakade: we put an enemy group in atari from the inside. */
128 /* This branch also allows eyes falsification:
129 * O O O . . (This is different from throw-in to false eye
130 * X X O O . checked below in that there is no X stone at the
131 * X . X O . right of the star point in this diagram.)
134 /* TODO: Allow to only nakade if the created shape is dead
135 * (http://senseis.xmp.net/?Nakade). */
137 /* This branch also covers snapback, which is kind of special
138 * nakade case. ;-) */
139 for (int i
= 0; i
< 4; i
++) {
140 group_t g
= groupids
[stone_other(color
)][i
];
141 if (!g
|| board_group_info(b
, g
).libs
!= 2)
143 /* Simple check not to re-examine the same group. */
144 if (i
> 0 && groupids
[stone_other(color
)][i
] == groupids
[stone_other(color
)][i
- 1])
147 /* We must make sure the other liberty of that group:
148 * (i) is an internal liberty
149 * (ii) filling it to capture our group will not gain
152 /* Let's look at the other liberty neighbors: */
153 int lib2
= board_group_info(b
, g
).lib
[0];
154 if (lib2
== to
) lib2
= board_group_info(b
, g
).lib
[1];
155 foreach_neighbor(b
, lib2
, {
156 /* This neighbor of course does not contribute
157 * anything to the enemy. */
158 if (board_at(b
, c
) == S_OFFBOARD
)
161 /* If the other liberty has empty neighbor,
162 * it must be the original liberty; otherwise,
163 * since the whole group has only 2 liberties,
164 * the other liberty may not be internal and
165 * we are nakade'ing eyeless group from outside,
166 * which is stupid. */
167 if (board_at(b
, c
) == S_NONE
) {
174 int g2
= group_at(b
, c
);
175 /* If the neighbor is of our color, it must
176 * be our group; if it is a different group,
177 * it must not be in atari. */
178 /* X X X X We will not allow play on 'a',
179 * X X a X because 'b' would capture two
180 * X O b X different groups, forming two
182 if (board_at(b
, c
) == color
) {
183 if (board_group_info(b
, group_at(b
, c
)).libs
> 1)
185 /* Our group == one of the groups
186 * we (@to) are connected to. */
188 for (j
= 0; j
< 4; j
++)
189 if (groupids
[color
][j
] == g2
)
196 /* The neighbor is enemy color. It's ok if
197 * it's still the same group or this is its
199 if (g
== g2
|| board_group_info(b
, g2
).libs
== 1)
201 /* Otherwise, it must have the exact same
202 * liberties as the original enemy group. */
203 if (board_group_info(b
, g2
).libs
== 2
204 && (board_group_info(b
, g2
).lib
[0] == to
205 || board_group_info(b
, g2
).lib
[1] == to
))
211 /* Now, we must distinguish between nakade and eye
212 * falsification; we must not falsify an eye by more
213 * than two stones. */
214 if (groupcts
[color
] < 1 ||
215 (groupcts
[color
] == 1 && group_is_onestone(b
, groupids
[color
][0])))
218 /* We would create more than 2-stone group; in that
219 * case, the liberty of our result must be lib2,
220 * indicating this really is a nakade. */
221 for (int j
= 0; j
< 4; j
++) {
222 group_t g2
= groupids
[color
][j
];
224 assert(board_group_info(b
, g2
).libs
<= 2);
225 if (board_group_info(b
, g2
).libs
== 2) {
226 if (board_group_info(b
, g2
).lib
[0] != lib2
227 && board_group_info(b
, g2
).lib
[1] != lib2
)
230 assert(board_group_info(b
, g2
).lib
[0] == to
);
239 //fprintf(stderr, "no nakade group\n");
241 /* We can be throwing-in to false eye:
242 * X X X O X X X O X X X X X
243 * X . * X * O . X * O O . X
244 * # # # # # # # # # # # # # */
245 /* We cannot sensibly throw-in into a corner. */
246 if (neighbor_count_at(b
, to
, S_OFFBOARD
) < 2
247 && neighbor_count_at(b
, to
, stone_other(color
))
248 + neighbor_count_at(b
, to
, S_OFFBOARD
) == 3
249 && board_is_false_eyelike(b
, &to
, stone_other(color
))) {
250 assert(groupcts
[color
] <= 1);
251 /* Single-stone throw-in may be ok... */
252 if (groupcts
[color
] == 0) {
253 /* O X . There is one problem - when it's
254 * . * X actually not a throw-in!
256 foreach_neighbor(b
, to
, {
257 if (board_at(b
, c
) == S_NONE
) {
258 /* Is the empty neighbor an escape path? */
259 /* (Note that one S_NONE neighbor is already @to.) */
260 if (neighbor_count_at(b
, c
, stone_other(color
))
261 + neighbor_count_at(b
, c
, S_OFFBOARD
) < 2)
262 goto invalid_throwin
;
268 /* Multi-stone throwin...? */
269 assert(groupcts
[color
] == 1);
270 group_t g
= groupids
[color
][0];
272 assert(board_group_info(b
, g
).libs
<= 2);
273 /* Suicide is definitely NOT ok, no matter what else
275 if (board_group_info(b
, g
).libs
== 1)
278 /* In that case, we must be connected to at most one stone,
279 * or throwin will not destroy any eyes. */
280 if (group_is_onestone(b
, g
))
285 //fprintf(stderr, "no throw-in group\n");
287 /* No way to pull out, no way to connect out. This really
288 * is a bad self-atari! */
294 board_stone_radar(struct board
*b
, coord_t coord
, int distance
)
297 coord_x(coord
, b
) - distance
,
298 coord_y(coord
, b
) - distance
,
299 coord_x(coord
, b
) + distance
,
300 coord_y(coord
, b
) + distance
302 for (int i
= 0; i
< 4; i
++)
305 else if (bounds
[i
] > board_size(b
) - 2)
306 bounds
[i
] = board_size(b
) - 2;
307 for (int x
= bounds
[0]; x
<= bounds
[2]; x
++)
308 for (int y
= bounds
[1]; y
<= bounds
[3]; y
++)
309 if (board_atxy(b
, x
, y
) != S_NONE
) {
310 /* fprintf(stderr, "radar %d,%d,%d: %d,%d (%d)\n",
311 coord_x(coord, b), coord_y(coord, b),
312 distance, x, y, board_atxy(b, x, y)); */
319 cfg_distances(struct board
*b
, coord_t start
, int *distances
, int maxdist
)
321 /* Queue for d+1 spots; no two spots of the same group
322 * should appear in the queue. */
323 #define qinc(x) (x = ((x + 1) >= board_size2(b) ? ((x) + 1 - board_size2(b)) : (x) + 1))
324 coord_t queue
[board_size2(b
)]; int qstart
= 0, qstop
= 0;
327 distances
[c
] = board_at(b
, c
) == S_OFFBOARD
? maxdist
+ 1 : -1;
330 queue
[qstop
++] = start
;
331 for (int d
= 0; d
<= maxdist
; d
++) {
332 /* Process queued moves, while setting the queue
334 int qa
= qstart
, qb
= qstop
;
336 for (int q
= qa
; q
< qb
; qinc(q
)) {
337 #define cfg_one(coord, grp) do {\
338 distances[coord] = d; \
339 foreach_neighbor (b, coord, { \
340 if (distances[c] < 0 && (!grp || group_at(b, coord) != grp)) { \
346 coord_t cq
= queue
[q
];
347 if (distances
[cq
] >= 0)
348 continue; /* We already looked here. */
349 if (board_at(b
, cq
) == S_NONE
) {
352 group_t g
= group_at(b
, cq
);
353 foreach_in_group(b
, g
) {
355 } foreach_in_group_end
;
362 if (distances
[c
] < 0)
363 distances
[c
] = maxdist
+ 1;