9 #include "tactics/selfatari.h"
12 struct selfatari_state
{
14 group_t groupids
[S_MAX
][4];
16 /* This is set if this move puts a group out of _all_
17 * liberties; we need to watch out for snapback then. */
18 bool friend_has_no_libs
;
19 /* We may have one liberty, but be looking for one more.
20 * In that case, @needs_more_lib is id of group
21 * already providing one, don't consider it again. */
22 group_t needs_more_lib
;
23 /* ID of the first liberty, providing it again is not
25 coord_t needs_more_lib_except
;
29 three_liberty_suicide(struct board
*b
, group_t g
, enum stone color
, coord_t to
, struct selfatari_state
*s
)
31 /* If a group has three liberties, by playing on one of
32 * them it is possible to kill the group clumsily. Check
33 * against that condition: "After our move, the opponent
34 * can unconditionally capture the group."
38 * O O O O O O O X X O O O O O O v-v- ladder
39 * O X X X X X O . O X X X X X O . . . O O
40 * O X ! . ! X O . O X ! . ! O . O X X . O
41 * O X X X X X O # # # # # # # # O O O O O */
43 /* Extract the other two liberties. */
44 coord_t other_libs
[2];
45 bool other_libs_adj
[2];
46 for (int i
= 0, j
= 0; i
< 3; i
++) {
47 coord_t lib
= board_group_info(b
, g
).lib
[i
];
49 other_libs_adj
[j
] = coord_is_adjecent(lib
, to
, b
);
50 other_libs
[j
++] = lib
;
54 /* Make sure this move is not useful by gaining liberties,
55 * splitting the other two liberties (quite possibly splitting
56 * 3-eyespace!) or connecting to a different group. */
57 if (immediate_liberty_count(b
, to
) - (other_libs_adj
[0] || other_libs_adj
[1]) > 0)
59 assert(!(other_libs_adj
[0] && other_libs_adj
[1]));
60 if (s
->groupcts
[color
] > 1)
63 /* Playing on the third liberty might be useful if it enables
64 * capturing some group. */
65 for (int i
= 0; i
< s
->groupcts
[stone_other(color
)]; i
++)
66 if (board_group_info(b
, s
->groupids
[stone_other(color
)][i
]).libs
<= 2)
70 /* Okay. This looks like a pretty dangerous situation. The
71 * move looks useless, it definitely converts us to a 2-lib
72 * group. But we still want to play it e.g. if it takes off
73 * liberties of some unconspicous enemy group, and of course
74 * also at the game end to leave just single-point eyes. */
77 fprintf(stderr
, "3-lib danger\n");
79 /* Therefore, the final suicidal test is: (After filling this
80 * liberty,) when opponent fills liberty [0], playing liberty
81 * [1] will not help the group, or vice versa. */
82 bool other_libs_neighbors
= coord_is_adjecent(other_libs
[0], other_libs
[1], b
);
83 for (int i
= 0; i
< 2; i
++) {
84 int null_libs
= other_libs_neighbors
+ other_libs_adj
[i
];
85 if (board_is_one_point_eye(b
, other_libs
[1 - i
], color
)) {
86 /* The other liberty is an eye, happily go ahead.
87 * There are of course situations where this will
88 * take off semeai liberties, but without this check,
89 * many terminal endgame plays will be messed up. */
92 if (immediate_liberty_count(b
, other_libs
[i
]) - null_libs
> 1) {
93 /* Gains liberties. */
94 /* TODO: Check for ladder! */
98 foreach_neighbor(b
, other_libs
[i
], {
99 if (board_at(b
, c
) == color
100 && group_at(b
, c
) != g
101 && board_group_info(b
, group_at(b
, c
)).libs
> 1) {
102 /* Can connect to a friend. */
103 /* TODO: > 2? But maybe the group can capture
104 * a neighbor! But then better let it do that
109 /* If we can capture a neighbor, better do it now
110 * before wasting a liberty. So no need to check. */
111 /* Ok, the last liberty has no way to get out. */
113 fprintf(stderr
, "3-lib dangerous: %s\n", coord2sstr(other_libs
[i
], b
));
121 examine_friendly_groups(struct board
*b
, enum stone color
, coord_t to
, struct selfatari_state
*s
)
123 for (int i
= 0; i
< s
->groupcts
[color
]; i
++) {
124 /* We can escape by connecting to this group if it's
126 group_t g
= s
->groupids
[color
][i
];
128 if (board_group_info(b
, g
).libs
== 1) {
129 if (!s
->needs_more_lib
)
130 s
->friend_has_no_libs
= true;
131 // or we already have a friend with 1 lib
135 /* Could we self-atari the group here? */
136 if (board_group_info(b
, g
).libs
> 2) {
137 if (board_group_info(b
, g
).libs
== 3
138 && three_liberty_suicide(b
, g
, color
, to
, s
))
143 /* We need to have another liberty, and
144 * it must not be the other liberty of
146 int lib2
= board_group_other_lib(b
, g
, to
);
147 /* Maybe we already looked at another
148 * group providing one liberty? */
149 if (s
->needs_more_lib
&& s
->needs_more_lib
!= g
150 && s
->needs_more_lib_except
!= lib2
)
153 /* Can we get the liberty locally? */
154 /* Yes if we are route to more liberties... */
155 if (s
->groupcts
[S_NONE
] > 1)
157 /* ...or one liberty, but not lib2. */
158 if (s
->groupcts
[S_NONE
] > 0
159 && !coord_is_adjecent(lib2
, to
, b
))
162 /* ...ok, then we can still contribute a liberty
163 * later by capturing something. */
164 s
->needs_more_lib
= g
;
165 s
->needs_more_lib_except
= lib2
;
166 s
->friend_has_no_libs
= false;
173 examine_enemy_groups(struct board
*b
, enum stone color
, coord_t to
, struct selfatari_state
*s
)
175 /* We may be able to gain a liberty by capturing this group. */
176 group_t can_capture
= 0;
178 /* Examine enemy groups: */
179 for (int i
= 0; i
< s
->groupcts
[stone_other(color
)]; i
++) {
180 /* We can escape by capturing this group if it's in atari. */
181 group_t g
= s
->groupids
[stone_other(color
)][i
];
182 if (board_group_info(b
, g
).libs
> 1)
185 /* But we need to get to at least two liberties by this;
186 * we already have one outside liberty, or the group is
187 * more than 1 stone (in that case, capturing is always
189 if (s
->groupcts
[S_NONE
] > 0 || !group_is_onestone(b
, g
))
191 /* ...or, it's a ko stone, */
192 if (neighbor_count_at(b
, g
, color
) + neighbor_count_at(b
, g
, S_OFFBOARD
) == 3) {
193 /* and we don't have a group to save: then, just taking
194 * single stone means snapback! */
195 if (!s
->friend_has_no_libs
)
198 /* ...or, we already have one indirect liberty provided
199 * by another group. */
200 if (s
->needs_more_lib
|| (can_capture
&& can_capture
!= g
))
207 fprintf(stderr
, "no cap group\n");
209 if (!s
->needs_more_lib
&& !can_capture
&& !s
->groupcts
[S_NONE
]) {
210 /* We have no hope for more fancy tactics - this move is simply
211 * a suicide, not even a self-atari. */
213 fprintf(stderr
, "suicide\n");
216 /* XXX: I wonder if it makes sense to continue if we actually
217 * just !s->needs_more_lib. */
223 setup_nakade_or_snapback(struct board
*b
, enum stone color
, coord_t to
, struct selfatari_state
*s
)
225 /* There is another possibility - we can self-atari if it is
226 * a nakade: we put an enemy group in atari from the inside. */
227 /* This branch also allows eyes falsification:
228 * O O O . . (This is different from throw-in to false eye
229 * X X O O . checked below in that there is no X stone at the
230 * X . X O . right of the star point in this diagram.)
233 /* TODO: Allow to only nakade if the created shape is dead
234 * (http://senseis.xmp.net/?Nakade). */
236 /* This branch also covers snapback, which is kind of special
237 * nakade case. ;-) */
238 for (int i
= 0; i
< s
->groupcts
[stone_other(color
)]; i
++) {
239 group_t g
= s
->groupids
[stone_other(color
)][i
];
240 if (board_group_info(b
, g
).libs
!= 2)
242 /* Simple check not to re-examine the same group. */
243 if (i
> 0 && s
->groupids
[stone_other(color
)][i
] == s
->groupids
[stone_other(color
)][i
- 1])
246 /* We must make sure the other liberty of that group:
247 * (i) is an internal liberty
248 * (ii) filling it to capture our group will not gain
251 /* Let's look at neighbors of the other liberty: */
252 int lib2
= board_group_other_lib(b
, g
, to
);
253 foreach_neighbor(b
, lib2
, {
254 /* This neighbor of course does not contribute
255 * anything to the enemy. */
256 if (board_at(b
, c
) == S_OFFBOARD
)
259 /* If the other liberty has empty neighbor,
260 * it must be the original liberty; otherwise,
261 * since the whole group has only 2 liberties,
262 * the other liberty may not be internal and
263 * we are nakade'ing eyeless group from outside,
264 * which is stupid. */
265 if (board_at(b
, c
) == S_NONE
) {
272 int g2
= group_at(b
, c
);
273 /* If the neighbor is of our color, it must
274 * be also a 2-lib group. If it is more,
275 * we CERTAINLY want that liberty to be played
276 * first, what if it is an alive group? If it
277 * is in atari, we want to extend from it to
278 * prevent eye-making capture. However, if it
279 * is 2-lib, it is selfatari connecting two
280 * nakade'ing groups! */
281 /* X X X X We will not allow play on 'a',
282 * X X a X because 'b' would capture two
283 * X O b X different groups, forming two
285 if (board_at(b
, c
) == color
) {
286 if (board_group_info(b
, group_at(b
, c
)).libs
== 2)
291 /* The neighbor is enemy color. It's ok if
292 * it's still the same group or this is its
294 if (g
== g2
|| board_group_info(b
, g2
).libs
== 1)
296 /* Otherwise, it must have the exact same
297 * liberties as the original enemy group. */
298 if (board_group_info(b
, g2
).libs
== 2
299 && (board_group_info(b
, g2
).lib
[0] == to
300 || board_group_info(b
, g2
).lib
[1] == to
))
306 /* Now, we must distinguish between nakade and eye
307 * falsification; we must not falsify an eye by more
308 * than two stones. */
309 if (s
->groupcts
[color
] < 1)
310 return false; // simple throw-in
311 if (s
->groupcts
[color
] == 1 && group_is_onestone(b
, s
->groupids
[color
][0])) {
312 /* More complex throw-in - we are in one of
314 * a O O O O X b O O O X c O O O X
315 * O . X . O O X . . O . X .
316 * # # # # # # # # # # # # #
317 * b is desirable here (since maybe O has no
318 * backup two eyes); a may be desirable, but
319 * is tested next in check_throwin(). c is
320 * never desirable. */
321 group_t g2
= s
->groupids
[color
][0];
322 assert(board_group_info(b
, g2
).libs
<= 2);
323 if (board_group_info(b
, g2
).libs
== 1)
325 goto next_group
; // a or c
328 /* We would create more than 2-stone group; in that
329 * case, the liberty of our result must be lib2,
330 * indicating this really is a nakade. */
331 for (int j
= 0; j
< s
->groupcts
[color
]; j
++) {
332 group_t g2
= s
->groupids
[color
][j
];
333 assert(board_group_info(b
, g2
).libs
<= 2);
334 if (board_group_info(b
, g2
).libs
== 2) {
335 if (board_group_info(b
, g2
).lib
[0] != lib2
336 && board_group_info(b
, g2
).lib
[1] != lib2
)
339 assert(board_group_info(b
, g2
).lib
[0] == to
);
345 /* Unless we are dealing with snapback setup, we don't need to look
347 if (s
->groupcts
[color
])
355 check_throwin(struct board
*b
, enum stone color
, coord_t to
, struct selfatari_state
*s
)
357 /* We can be throwing-in to false eye:
358 * X X X O X X X O X X X X X
359 * X . * X * O . X * O O . X
360 * # # # # # # # # # # # # # */
361 /* We cannot sensibly throw-in into a corner. */
362 if (neighbor_count_at(b
, to
, S_OFFBOARD
) < 2
363 && neighbor_count_at(b
, to
, stone_other(color
))
364 + neighbor_count_at(b
, to
, S_OFFBOARD
) == 3
365 && board_is_false_eyelike(b
, to
, stone_other(color
))) {
366 assert(s
->groupcts
[color
] <= 1);
367 /* Single-stone throw-in may be ok... */
368 if (s
->groupcts
[color
] == 0) {
369 /* O X . There is one problem - when it's
370 * . * X actually not a throw-in!
372 foreach_neighbor(b
, to
, {
373 if (board_at(b
, c
) == S_NONE
) {
374 /* Is the empty neighbor an escape path? */
375 /* (Note that one S_NONE neighbor is already @to.) */
376 if (neighbor_count_at(b
, c
, stone_other(color
))
377 + neighbor_count_at(b
, c
, S_OFFBOARD
) < 2)
384 /* Multi-stone throwin...? */
385 assert(s
->groupcts
[color
] == 1);
386 group_t g
= s
->groupids
[color
][0];
388 assert(board_group_info(b
, g
).libs
<= 2);
389 /* Suicide is definitely NOT ok, no matter what else
391 if (board_group_info(b
, g
).libs
== 1)
394 /* In that case, we must be connected to at most one stone,
395 * or throwin will not destroy any eyes. */
396 if (group_is_onestone(b
, g
))
403 is_bad_selfatari_slow(struct board
*b
, enum stone color
, coord_t to
)
406 fprintf(stderr
, "sar check %s %s\n", stone2str(color
), coord2sstr(to
, b
));
407 /* Assess if we actually gain any liberties by this escape route.
408 * Note that this is not 100% as we cannot check whether we are
409 * connecting out or just to ourselves. */
411 struct selfatari_state s
;
412 memset(&s
, 0, sizeof(s
));
415 foreach_neighbor(b
, to
, {
416 enum stone color
= board_at(b
, c
);
417 s
.groupids
[color
][s
.groupcts
[color
]++] = group_at(b
, c
);
420 /* We have shortage of liberties; that's the point. */
421 assert(s
.groupcts
[S_NONE
] <= 1);
423 d
= examine_friendly_groups(b
, color
, to
, &s
);
428 fprintf(stderr
, "no friendly group\n");
430 d
= examine_enemy_groups(b
, color
, to
, &s
);
435 fprintf(stderr
, "no escape\n");
437 d
= setup_nakade_or_snapback(b
, color
, to
, &s
);
442 fprintf(stderr
, "no nakade group\n");
444 d
= check_throwin(b
, color
, to
, &s
);
449 fprintf(stderr
, "no throw-in group\n");
451 /* No way to pull out, no way to connect out. This really
452 * is a bad self-atari! */
458 selfatari_cousin(struct board
*b
, enum stone color
, coord_t coord
)
460 group_t groups
[4]; int groups_n
= 0;
461 foreach_neighbor(b
, coord
, {
462 enum stone s
= board_at(b
, c
);
463 if (s
!= color
) continue;
464 group_t g
= group_at(b
, c
);
465 if (board_group_info(b
, g
).libs
== 2)
466 groups
[groups_n
++] = g
;
471 group_t group
= groups
[fast_random(groups_n
)];
473 coord_t lib2
= board_group_other_lib(b
, group
, coord
);
474 if (is_bad_selfatari(b
, color
, lib2
))