9 #include "tactics/2lib.h"
10 #include "tactics/selfatari.h"
13 /* Whether to avoid capturing/atariing doomed groups (this is big
14 * performance hit and may reduce playouts balance; it does increase
15 * the strength, but not quite proportionally to the performance). */
16 //#define NO_DOOMED_GROUPS
20 miai_2lib(struct board
*b
, group_t group
, enum stone color
)
22 bool can_connect
= false, can_pull_out
= false;
23 /* We have miai if we can either connect on both libs,
24 * or connect on one lib and escape on another. (Just
25 * having two escape routes can be risky.) We must make
26 * sure that we don't consider following as miai:
29 * O O X O - left dot would be pull-out, right dot connect */
30 foreach_neighbor(b
, board_group_info(b
, group
).lib
[0], {
31 enum stone cc
= board_at(b
, c
);
32 if (cc
== S_NONE
&& cc
!= board_at(b
, board_group_info(b
, group
).lib
[1])) {
34 } else if (cc
!= color
) {
38 group_t cg
= group_at(b
, c
);
39 if (cg
&& cg
!= group
&& board_group_info(b
, cg
).libs
> 1)
42 foreach_neighbor(b
, board_group_info(b
, group
).lib
[1], {
43 enum stone cc
= board_at(b
, c
);
44 if (c
== board_group_info(b
, group
).lib
[0])
46 if (cc
== S_NONE
&& can_connect
) {
48 } else if (cc
!= color
) {
52 group_t cg
= group_at(b
, c
);
53 if (cg
&& cg
!= group
&& board_group_info(b
, cg
).libs
> 1)
54 return (can_connect
|| can_pull_out
);
60 check_group_atari(struct board
*b
, group_t group
, enum stone owner
,
61 enum stone to_play
, struct move_queue
*q
, int tag
)
63 for (int i
= 0; i
< 2; i
++) {
64 coord_t lib
= board_group_info(b
, group
).lib
[i
];
65 assert(board_at(b
, lib
) == S_NONE
);
66 if (!board_is_valid_play(b
, to_play
, lib
))
69 /* Don't play at the spot if it is extremely short
71 /* XXX: This looks harmful, could significantly
72 * prefer atari to throwin:
78 if (neighbor_count_at(b
, lib
, stone_other(owner
)) + immediate_liberty_count(b
, lib
) < 2)
82 /* If the move is too "lumpy", do not play it:
85 * ..O.X.X <- always play the left one!
87 if (neighbor_count_at(b
, lib
, stone_other(owner
)) + neighbor_count_at(b
, lib
, S_OFFBOARD
) == 3)
90 /* XXX: We do not check connecting to a short-on-liberty
93 /* If we are the defender, do not escape with moves
94 * that do not gain liberties anyway since one of the
95 * "gained" liberties is shared. */
97 && neighbor_count_at(b
, lib
, stone_other(owner
)) + neighbor_count_at(b
, lib
, S_OFFBOARD
) == 2
98 && coord_is_adjecent(lib
, board_group_info(b
, group
).lib
[1 - i
], b
))
101 #ifdef NO_DOOMED_GROUPS
102 /* If the owner can't play at the spot, we don't want
103 * to bother either. */
104 if (is_bad_selfatari(b
, owner
, lib
))
108 /* Of course we don't want to play bad selfatari
109 * ourselves, if we are the attacker... */
111 #ifdef NO_DOOMED_GROUPS
114 is_bad_selfatari(b
, to_play
, lib
))
117 /* Tasty! Crispy! Good! */
124 group_2lib_check(struct board
*b
, group_t group
, enum stone to_play
, struct move_queue
*q
, int tag
)
126 enum stone color
= board_at(b
, group_base(group
));
127 assert(color
!= S_OFFBOARD
&& color
!= S_NONE
);
130 fprintf(stderr
, "[%s] 2lib check of color %d\n",
131 coord2sstr(group
, b
), color
);
133 /* Do not try to atari groups that cannot be harmed. */
134 if (miai_2lib(b
, group
, color
))
137 check_group_atari(b
, group
, color
, to_play
, q
, tag
);
139 /* Can we counter-atari another group, if we are the defender? */
140 if (to_play
!= color
)
142 foreach_in_group(b
, group
) {
143 foreach_neighbor(b
, c
, {
144 if (board_at(b
, c
) != stone_other(color
))
146 group_t g2
= group_at(b
, c
);
147 if (board_group_info(b
, g2
).libs
== 1) {
148 /* We can capture a neighbor. */
149 mq_add(q
, board_group_info(b
, g2
).lib
[0], tag
);
153 if (board_group_info(b
, g2
).libs
!= 2)
155 check_group_atari(b
, g2
, color
, to_play
, q
, tag
);
157 } foreach_in_group_end
;