5 #define QUICK_BOARD_CODE
11 #include "tactics/1lib.h"
12 #include "tactics/ladder.h"
16 is_border_ladder(struct board
*b
, coord_t coord
, group_t laddered
, enum stone lcolor
)
18 if (can_countercapture(b
, lcolor
, laddered
, lcolor
, NULL
, 0))
21 int x
= coord_x(coord
, b
), y
= coord_y(coord
, b
);
24 fprintf(stderr
, "border ladder\n");
25 /* Direction along border; xd is horiz. border, yd vertical. */
27 if (board_atxy(b
, x
+ 1, y
) == S_OFFBOARD
|| board_atxy(b
, x
- 1, y
) == S_OFFBOARD
)
31 /* Direction from the border; -1 is above/left, 1 is below/right. */
32 int dd
= (board_atxy(b
, x
+ yd
, y
+ xd
) == S_OFFBOARD
) ? 1 : -1;
34 fprintf(stderr
, "xd %d yd %d dd %d\n", xd
, yd
, dd
);
40 /* This is normally caught, unless we have friends both above
42 if (board_atxy(b
, x
+ xd
* 2, y
+ yd
* 2) == lcolor
43 && board_atxy(b
, x
- xd
* 2, y
- yd
* 2) == lcolor
)
46 /* ...or can't block where we need because of shortage
48 group_t g1
= group_atxy(b
, x
+ xd
- yd
* dd
, y
+ yd
- xd
* dd
);
49 int libs1
= board_group_info(b
, g1
).libs
;
50 group_t g2
= group_atxy(b
, x
- xd
- yd
* dd
, y
- yd
- xd
* dd
);
51 int libs2
= board_group_info(b
, g2
).libs
;
53 fprintf(stderr
, "libs1 %d libs2 %d\n", libs1
, libs2
);
54 /* Already in atari? */
55 if (libs1
< 2 || libs2
< 2)
57 /* Would be self-atari? */
58 if (libs1
< 3 && (board_atxy(b
, x
+ xd
* 2, y
+ yd
* 2) != S_NONE
59 || coord_is_adjecent(board_group_info(b
, g1
).lib
[0], board_group_info(b
, g1
).lib
[1], b
)))
61 if (libs2
< 3 && (board_atxy(b
, x
- xd
* 2, y
- yd
* 2) != S_NONE
62 || coord_is_adjecent(board_group_info(b
, g2
).lib
[0], board_group_info(b
, g2
).lib
[1], b
)))
68 /* This is a rather expensive ladder reader. It can read out any sequences
69 * where laddered group should be kept at two liberties. The recursion
70 * always makes a "to-be-laddered" move and then considers the chaser's
71 * two alternatives (usually, one of them is trivially refutable). The
72 * function returns true if there is a branch that ends up with laddered
73 * group captured, false if not (i.e. for each branch, laddered group can
74 * gain three liberties). */
77 middle_ladder_walk(struct board
*b
, struct board
*bset
, group_t laddered
, coord_t nextmove
, enum stone lcolor
)
79 assert(board_group_info(b
, laddered
).libs
== 1);
83 fprintf(stderr
, " ladder escape %s\n", coord2sstr(nextmove
, b
));
84 struct move m
= { nextmove
, lcolor
};
85 int res
= board_play(b
, &m
);
86 laddered
= group_at(b
, laddered
);
89 board_print(b
, stderr
);
90 fprintf(stderr
, "%s c %d\n", coord2sstr(laddered
, b
), board_group_info(b
, laddered
).libs
);
93 if (board_group_info(b
, laddered
).libs
== 1) {
95 fprintf(stderr
, "* we can capture now\n");
98 if (board_group_info(b
, laddered
).libs
> 2) {
100 fprintf(stderr
, "* we are free now\n");
104 foreach_neighbor(b
, m
.coord
, {
105 if (board_at(b
, c
) == stone_other(lcolor
) && board_group_info(b
, group_at(b
, c
)).libs
== 1) {
106 /* We can capture one of the ladder stones
108 /* XXX: If we were very lucky, capturing
109 * this stone will not help us escape.
110 * That should be pretty rate. */
112 fprintf(stderr
, "* can capture chaser\n");
117 /* Now, consider alternatives. */
118 int liblist
[2], libs
= 0;
119 for (int i
= 0; i
< 2; i
++) {
120 coord_t ataristone
= board_group_info(b
, laddered
).lib
[i
];
121 coord_t escape
= board_group_info(b
, laddered
).lib
[1 - i
];
122 if (immediate_liberty_count(b
, escape
) > 2 + coord_is_adjecent(ataristone
, escape
, b
)) {
123 /* Too much free space, ignore. */
129 /* Try out the alternatives. */
130 bool is_ladder
= false;
131 for (int i
= 0; !is_ladder
&& i
< libs
; i
++) {
132 struct board
*b2
= b
;
138 coord_t ataristone
= board_group_info(b2
, laddered
).lib
[liblist
[i
]];
139 // coord_t escape = board_group_info(b2, laddered).lib[1 - liblist[i]];
140 struct move m
= { ataristone
, stone_other(lcolor
) };
141 int res
= board_play(b2
, &m
);
142 /* If we just played self-atari, abandon ship. */
143 /* XXX: If we were very lucky, capturing this stone will
144 * not help us escape. That should be pretty rate. */
146 fprintf(stderr
, "(%d=%d) ladder atari %s (%d libs)\n", i
, res
, coord2sstr(ataristone
, b2
), board_group_info(b2
, group_at(b2
, ataristone
)).libs
);
147 if (res
>= 0 && board_group_info(b2
, group_at(b2
, ataristone
)).libs
> 1)
148 is_ladder
= middle_ladder_walk(b2
, bset
, laddered
, board_group_info(b2
, laddered
).lib
[0], lcolor
);
151 board_done_noalloc(b2
);
155 fprintf(stderr
, "propagating %d\n", is_ladder
);
160 is_middle_ladder(struct board
*b
, coord_t coord
, group_t laddered
, enum stone lcolor
)
162 /* TODO: Remove the redundant parameters. */
163 assert(board_group_info(b
, laddered
).libs
== 1);
164 assert(board_group_info(b
, laddered
).lib
[0] == coord
);
165 assert(board_at(b
, laddered
) == lcolor
);
167 /* If we can move into empty space or do not have enough space
168 * to escape, this is obviously not a ladder. */
169 if (immediate_liberty_count(b
, coord
) != 2) {
171 fprintf(stderr
, "no ladder, wrong free space\n");
175 /* A fair chance for a ladder. Group in atari, with some but limited
176 * space to escape. Time for the expensive stuff - set up a temporary
177 * board and start selective 2-liberty search. */
179 struct board
*bset
= malloc2(BOARD_MAX_SIZE
* 2 * sizeof(struct board
));
181 struct move_queue ccq
= { .moves
= 0 };
182 if (can_countercapture(b
, lcolor
, laddered
, lcolor
, &ccq
, 0)) {
183 /* We could escape by countercapturing a group.
185 assert(ccq
.moves
> 0);
186 for (unsigned int i
= 0; i
< ccq
.moves
; i
++) {
189 bool is_ladder
= middle_ladder_walk(&b2
, bset
, laddered
, ccq
.move
[i
], lcolor
);
190 board_done_noalloc(&b2
);
200 bool is_ladder
= middle_ladder_walk(&b2
, bset
, laddered
, board_group_info(&b2
, laddered
).lib
[0], lcolor
);
201 board_done_noalloc(&b2
);
207 wouldbe_ladder(struct board
*b
, group_t group
, coord_t escapelib
, coord_t chaselib
, enum stone lcolor
)
209 assert(board_group_info(b
, group
).libs
== 2);
210 assert(board_at(b
, group
) == lcolor
);
213 fprintf(stderr
, "would-be ladder check - does %s %s play out chasing move %s?\n",
214 stone2str(lcolor
), coord2sstr(escapelib
, b
), coord2sstr(chaselib
, b
));
216 if (!coord_is_8adjecent(escapelib
, chaselib
, b
)) {
218 fprintf(stderr
, "cannot determine ladder for remote simulated stone\n");
222 if (neighbor_count_at(b
, chaselib
, lcolor
) != 1 || immediate_liberty_count(b
, chaselib
) != 2) {
224 fprintf(stderr
, "overly trivial for a ladder\n");
228 bool is_ladder
= false;
229 struct board
*bset
= malloc2(BOARD_MAX_SIZE
* 2 * sizeof(struct board
));
233 struct move m
= { chaselib
, stone_other(lcolor
) };
234 int res
= board_play(&b2
, &m
);
236 is_ladder
= middle_ladder_walk(&b2
, bset
, group
, board_group_info(&b2
, group
).lib
[0], lcolor
);
238 board_done_noalloc(&b2
);