5 #define QUICK_BOARD_CODE
11 #include "tactics/1lib.h"
12 #include "tactics/ladder.h"
13 #include "tactics/selfatari.h"
16 /* Whether to avoid capturing/atariing doomed groups (this is big
17 * performance hit and may reduce playouts balance; it does increase
18 * the strength, but not quite proportionally to the performance). */
19 //#define NO_DOOMED_GROUPS
23 can_play_on_lib(struct board
*b
, group_t g
, enum stone to_play
)
25 coord_t capture
= board_group_info(b
, g
).lib
[0];
27 fprintf(stderr
, "can capture group %d (%s)?\n",
28 g
, coord2sstr(capture
, b
));
29 /* Does playing on the liberty usefully capture the group? */
30 if (board_is_valid_play(b
, to_play
, capture
)
31 && !is_bad_selfatari(b
, to_play
, capture
))
37 /* For given position @c, decide if this is a group that is in danger from
38 * @capturer and @to_play can do anything about it (play at the last
39 * liberty to either capture or escape). */
40 /* Note that @to_play is important; e.g. consider snapback, it's good
41 * to play at the last liberty by attacker, but not defender. */
42 static inline __attribute__((always_inline
)) bool
43 capturable_group(struct board
*b
, enum stone capturer
, coord_t c
,
46 group_t g
= group_at(b
, c
);
47 if (likely(board_at(b
, c
) != stone_other(capturer
)
48 || board_group_info(b
, g
).libs
> 1))
51 return can_play_on_lib(b
, g
, to_play
);
55 can_countercapture(struct board
*b
, enum stone owner
, group_t g
,
56 enum stone to_play
, struct move_queue
*q
, int tag
)
61 unsigned int qmoves_prev
= q
? q
->moves
: 0;
63 foreach_in_group(b
, g
) {
64 foreach_neighbor(b
, c
, {
65 if (!capturable_group(b
, owner
, c
, to_play
))
71 mq_add(q
, board_group_info(b
, group_at(b
, c
)).lib
[0], tag
);
74 } foreach_in_group_end
;
76 bool can
= q
? q
->moves
> qmoves_prev
: false;
80 #ifdef NO_DOOMED_GROUPS
82 can_be_rescued(struct board
*b
, group_t group
, enum stone color
, int tag
)
84 /* Does playing on the liberty rescue the group? */
85 if (can_play_on_lib(b
, group
, color
))
88 /* Then, maybe we can capture one of our neighbors? */
89 return can_countercapture(b
, color
, group
, color
, NULL
, tag
);
94 group_atari_check(unsigned int alwaysccaprate
, struct board
*b
, group_t group
, enum stone to_play
,
95 struct move_queue
*q
, coord_t
*ladder
, bool middle_ladder
, int tag
)
97 enum stone color
= board_at(b
, group_base(group
));
98 coord_t lib
= board_group_info(b
, group
).lib
[0];
100 assert(color
!= S_OFFBOARD
&& color
!= S_NONE
);
102 fprintf(stderr
, "[%s] atariiiiiiiii %s of color %d\n",
103 coord2sstr(group
, b
), coord2sstr(lib
, b
), color
);
104 assert(board_at(b
, lib
) == S_NONE
);
106 if (to_play
!= color
) {
107 /* We are the attacker! In that case, do not try defending
108 * our group, since we can capture the culprit. */
109 #ifdef NO_DOOMED_GROUPS
110 /* Do not remove group that cannot be saved by the opponent. */
111 if (!can_be_rescued(b
, group
, color
, tag
))
114 if (can_play_on_lib(b
, group
, to_play
)) {
121 /* Can we capture some neighbor? */
122 bool ccap
= can_countercapture(b
, color
, group
, to_play
, q
, tag
);
123 if (ccap
&& !ladder
&& alwaysccaprate
> fast_random(100))
126 /* Otherwise, do not save kos. */
127 if (group_is_onestone(b
, group
)
128 && neighbor_count_at(b
, lib
, color
) + neighbor_count_at(b
, lib
, S_OFFBOARD
) == 4) {
129 /* Except when the ko is for an eye! */
130 bool eyeconnect
= false;
131 foreach_diag_neighbor(b
, lib
) {
132 if (board_at(b
, c
) == S_NONE
&& neighbor_count_at(b
, c
, color
) + neighbor_count_at(b
, c
, S_OFFBOARD
) == 4) {
136 } foreach_diag_neighbor_end
;
141 /* Do not suicide... */
142 if (!can_play_on_lib(b
, group
, to_play
))
145 fprintf(stderr
, "...escape route valid\n");
147 /* ...or play out ladders (unless we can counter-capture anytime). */
149 if (is_ladder(b
, lib
, group
, middle_ladder
)) {
150 /* Sometimes we want to keep the ladder move in the
151 * queue in order to discourage it. */
156 } else if (DEBUGL(6))
157 fprintf(stderr
, "...no ladder\n");