Move group_atari_check() et al. to tactics/1lib.c.
[pachi/ann.git] / tactics / 1lib.c
blob6f7873297f24b03ccb5aa80cdad55d35cf6051f5
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/1lib.h"
10 #include "tactics/ladder.h"
11 #include "tactics/selfatari.h"
14 /* Whether to avoid capturing/atariing doomed groups (this is big
15 * performance hit and may reduce playouts balance; it does increase
16 * the strength, but not quite proportionally to the performance). */
17 //#define NO_DOOMED_GROUPS
20 static bool
21 can_play_on_lib(struct board *b, group_t g, enum stone to_play)
23 coord_t capture = board_group_info(b, g).lib[0];
24 if (DEBUGL(6))
25 fprintf(stderr, "can capture group %d (%s)?\n",
26 g, coord2sstr(capture, b));
27 /* Does playing on the liberty usefully capture the group? */
28 if (board_is_valid_play(b, to_play, capture)
29 && !is_bad_selfatari(b, to_play, capture))
30 return true;
32 return false;
35 /* For given position @c, decide if this is a group that is in danger from
36 * @capturer and @to_play can do anything about it (play at the last
37 * liberty to either capture or escape). */
38 /* Note that @to_play is important; e.g. consider snapback, it's good
39 * to play at the last liberty by attacker, but not defender. */
40 static __attribute__((always_inline)) bool
41 capturable_group(struct board *b, enum stone capturer, coord_t c,
42 enum stone to_play)
44 group_t g = group_at(b, c);
45 if (likely(board_at(b, c) != stone_other(capturer)
46 || board_group_info(b, g).libs > 1))
47 return false;
49 return can_play_on_lib(b, g, to_play);
52 /* For given atari group @group owned by @owner, decide if @to_play
53 * can save it / keep it in danger by dealing with one of the
54 * neighboring groups. */
55 static bool
56 can_countercapture(struct board *b, enum stone owner, group_t g,
57 enum stone to_play, struct move_queue *q, int tag)
59 if (b->clen < 2)
60 return false;
62 unsigned int qmoves_prev = q ? q->moves : 0;
64 foreach_in_group(b, g) {
65 foreach_neighbor(b, c, {
66 if (!capturable_group(b, owner, c, to_play))
67 continue;
69 if (!q) {
70 return true;
72 mq_add(q, board_group_info(b, group_at(b, c)).lib[0], tag);
73 mq_nodup(q);
74 });
75 } foreach_in_group_end;
77 bool can = q ? q->moves > qmoves_prev : false;
78 return can;
81 #ifdef NO_DOOMED_GROUPS
82 static bool
83 can_be_rescued(struct board *b, group_t group, enum stone color, int tag)
85 /* Does playing on the liberty rescue the group? */
86 if (can_play_on_lib(b, group, color))
87 return true;
89 /* Then, maybe we can capture one of our neighbors? */
90 return can_countercapture(b, color, group, color, NULL, tag);
92 #endif
94 void
95 group_atari_check(unsigned int alwaysccaprate, struct board *b, group_t group, enum stone to_play,
96 struct move_queue *q, coord_t *ladder, int tag)
98 int qmoves_prev = q->moves;
100 /* We don't use @to_play almost anywhere since any moves here are good
101 * for both defender and attacker. */
103 enum stone color = board_at(b, group_base(group));
104 coord_t lib = board_group_info(b, group).lib[0];
106 assert(color != S_OFFBOARD && color != S_NONE);
107 if (DEBUGL(5))
108 fprintf(stderr, "[%s] atariiiiiiiii %s of color %d\n",
109 coord2sstr(group, b), coord2sstr(lib, b), color);
110 assert(board_at(b, lib) == S_NONE);
112 /* Can we capture some neighbor? */
113 bool ccap = can_countercapture(b, color, group, to_play, q, tag);
114 if (ccap && !ladder && alwaysccaprate > fast_random(100))
115 return;
117 /* Otherwise, do not save kos. */
118 if (group_is_onestone(b, group)
119 && neighbor_count_at(b, lib, color) + neighbor_count_at(b, lib, S_OFFBOARD) == 4)
120 return;
122 /* Do not suicide... */
123 if (!can_play_on_lib(b, group, to_play))
124 return;
125 #ifdef NO_DOOMED_GROUPS
126 /* Do not remove group that cannot be saved by the opponent. */
127 if (to_play != color && !can_be_rescued(b, group, color, tag))
128 return;
129 #endif
130 if (DEBUGL(6))
131 fprintf(stderr, "...escape route valid\n");
133 /* ...or play out ladders. */
134 if (is_ladder(b, lib, group)) {
135 /* Sometimes we want to keep the ladder move in the
136 * queue in order to discourage it. */
137 if (!ladder)
138 return;
139 else
140 *ladder = lib;
142 if (DEBUGL(6))
143 fprintf(stderr, "...no ladder\n");
145 if (to_play != color) {
146 /* We are the attacker! In that case, throw away the moves
147 * that defend our groups, since we can capture the culprit. */
148 q->moves = qmoves_prev;
151 mq_add(q, lib, tag);
152 mq_nodup(q);