Move group_2lib_check() et al. from Moggy to tactics/2lib.c
[pachi.git] / tactics / 2lib.c
blob563b9cfd37931211df90141b1f7f6ba482606aa1
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
5 #define DEBUG
6 #include "board.h"
7 #include "debug.h"
8 #include "mq.h"
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
19 static bool
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:
27 * X X X O
28 * X . . O
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])) {
33 can_pull_out = true;
34 } else if (cc != color) {
35 continue;
38 group_t cg = group_at(b, c);
39 if (cg && cg != group && board_group_info(b, cg).libs > 1)
40 can_connect = true;
41 });
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])
45 continue;
46 if (cc == S_NONE && can_connect) {
47 return true;
48 } else if (cc != color) {
49 continue;
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);
55 });
56 return false;
59 void
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))
67 continue;
69 /* Don't play at the spot if it is extremely short
70 * of liberties... */
71 /* XXX: This looks harmful, could significantly
72 * prefer atari to throwin:
74 * XXXOOOOOXX
75 * .OO.....OX
76 * XXXOOOOOOX */
77 #if 0
78 if (neighbor_count_at(b, lib, stone_other(owner)) + immediate_liberty_count(b, lib) < 2)
79 continue;
80 #endif
82 /* If the move is too "lumpy", do not play it:
84 * #######
85 * ..O.X.X <- always play the left one!
86 * OXXXXXX */
87 if (neighbor_count_at(b, lib, stone_other(owner)) + neighbor_count_at(b, lib, S_OFFBOARD) == 3)
88 continue;
90 #ifdef NO_DOOMED_GROUPS
91 /* If the owner can't play at the spot, we don't want
92 * to bother either. */
93 if (is_bad_selfatari(b, owner, lib))
94 continue;
95 #endif
97 /* Of course we don't want to play bad selfatari
98 * ourselves, if we are the attacker... */
99 if (
100 #ifdef NO_DOOMED_GROUPS
101 to_play != owner &&
102 #endif
103 is_bad_selfatari(b, to_play, lib))
104 continue;
106 /* Tasty! Crispy! Good! */
107 mq_add(q, lib, tag);
108 mq_nodup(q);
112 void
113 group_2lib_check(struct board *b, group_t group, enum stone to_play, struct move_queue *q, int tag)
115 enum stone color = board_at(b, group_base(group));
116 assert(color != S_OFFBOARD && color != S_NONE);
118 if (DEBUGL(5))
119 fprintf(stderr, "[%s] 2lib check of color %d\n",
120 coord2sstr(group, b), color);
122 /* Do not try to atari groups that cannot be harmed. */
123 if (miai_2lib(b, group, color))
124 return;
126 check_group_atari(b, group, color, to_play, q, tag);
128 /* Can we counter-atari another group, if we are the defender? */
129 if (to_play != color)
130 return;
131 foreach_in_group(b, group) {
132 foreach_neighbor(b, c, {
133 if (board_at(b, c) != stone_other(color))
134 continue;
135 group_t g2 = group_at(b, c);
136 if (board_group_info(b, g2).libs == 1) {
137 /* We can capture a neighbor. */
138 mq_add(q, board_group_info(b, g2).lib[0], tag);
139 mq_nodup(q);
140 continue;
142 if (board_group_info(b, g2).libs != 2)
143 continue;
144 check_group_atari(b, g2, color, to_play, q, tag);
146 } foreach_in_group_end;