Commit | Line | Data |
---|---|---|
7eeb782e AT |
1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ |
2 | * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see * | |
3 | * http://www.gnu.org/software/gnugo/ for more information. * | |
4 | * * | |
5 | * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * | |
6 | * 2008 and 2009 by the Free Software Foundation. * | |
7 | * * | |
8 | * This program is free software; you can redistribute it and/or * | |
9 | * modify it under the terms of the GNU General Public License as * | |
10 | * published by the Free Software Foundation - version 3 or * | |
11 | * (at your option) any later version. * | |
12 | * * | |
13 | * This program is distributed in the hope that it will be useful, * | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
16 | * GNU General Public License in file COPYING for more details. * | |
17 | * * | |
18 | * You should have received a copy of the GNU General Public * | |
19 | * License along with this program; if not, write to the Free * | |
20 | * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * | |
21 | * Boston, MA 02111, USA. * | |
22 | \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
23 | ||
24 | ||
25 | #include "gnugo.h" | |
26 | ||
27 | #include <stdio.h> | |
28 | #include <stdlib.h> | |
29 | #include <string.h> | |
30 | #include "liberty.h" | |
31 | ||
32 | static int find_backfilling_move(int move, int color, int *backfill_move, | |
33 | int forbidden_moves[BOARDMAX]); | |
34 | static int filllib_confirm_safety(int move, int color, int *defense_point); | |
35 | ||
36 | /* Determine whether a point is adjacent to at least one own string which | |
37 | * isn't dead. | |
38 | */ | |
39 | static int | |
40 | living_neighbor(int pos, int color) | |
41 | { | |
42 | int k; | |
43 | for (k = 0; k < 4; k++) { | |
44 | if (board[pos + delta[k]] == color | |
45 | && dragon[pos + delta[k]].status != DEAD) | |
46 | return 1; | |
47 | } | |
48 | ||
49 | return 0; | |
50 | } | |
51 | ||
52 | ||
53 | /* Determine whether (pos) effectively is a black or white point. | |
54 | * The test for inessentiality is to avoid filling the liberties | |
55 | * around a killing nakade string. | |
56 | */ | |
57 | static void | |
58 | analyze_neighbor(int pos, int *found_black, int *found_white) | |
59 | { | |
60 | switch (board[pos]) { | |
61 | case EMPTY: | |
62 | if (!(*found_black) | |
63 | && living_neighbor(pos, BLACK) | |
64 | && safe_move(pos, WHITE) != WIN) | |
65 | *found_black = 1; | |
66 | ||
67 | if (!(*found_white) | |
68 | && living_neighbor(pos, WHITE) | |
69 | && safe_move(pos, BLACK) != WIN) | |
70 | *found_white = 1; | |
71 | ||
72 | break; | |
73 | ||
74 | case BLACK: | |
75 | if (!worm[pos].inessential && DRAGON2(pos).safety != INESSENTIAL) { | |
76 | if (dragon[pos].status == ALIVE | |
77 | || dragon[pos].status == UNKNOWN) | |
78 | *found_black = 1; | |
79 | else | |
80 | *found_white = 1; | |
81 | } | |
82 | break; | |
83 | ||
84 | case WHITE: | |
85 | if (!worm[pos].inessential && DRAGON2(pos).safety != INESSENTIAL) { | |
86 | if (dragon[pos].status == ALIVE | |
87 | || dragon[pos].status == UNKNOWN) | |
88 | *found_white = 1; | |
89 | else | |
90 | *found_black = 1; | |
91 | } | |
92 | break; | |
93 | } | |
94 | } | |
95 | ||
96 | ||
97 | /* If no move of value can be found to play, this seeks to fill a | |
98 | * common liberty, backfilling or back-capturing if necessary. When | |
99 | * backfilling we take care to start from the right end, in the case | |
100 | * that several backfilling moves are ultimately necessary. | |
101 | * | |
102 | * If a move for color is found, return 1, otherwise return 0. | |
103 | * The move is returned in (*move). | |
104 | */ | |
105 | ||
106 | int | |
107 | fill_liberty(int *move, int color) | |
108 | { | |
109 | int k; | |
110 | int pos; | |
111 | int other = OTHER_COLOR(color); | |
112 | int defense_point; | |
113 | int potential_color[BOARDMAX]; | |
114 | ||
115 | /* We first make a fast scan for intersections which are potential | |
116 | * candidates for liberty filling. This is not very accurate, but it | |
117 | * does filter out intersections which could never pass the real | |
118 | * tests below but might still require a lot of tactical reading in | |
119 | * the process. | |
120 | */ | |
121 | memset(potential_color, 0, sizeof(potential_color)); | |
122 | for (pos = BOARDMIN; pos < BOARDMAX; pos++) { | |
123 | if (!IS_STONE(board[pos])) | |
124 | continue; | |
125 | ||
126 | if (worm[pos].inessential || DRAGON2(pos).safety == INESSENTIAL) | |
127 | continue; | |
128 | ||
129 | if (dragon[pos].status != ALIVE) { | |
130 | for (k = 0; k < 4; k++) { | |
131 | int pos2 = pos + delta[k]; | |
132 | if (board[pos2] == EMPTY) | |
133 | potential_color[pos2] |= OTHER_COLOR(board[pos]); | |
134 | } | |
135 | } | |
136 | ||
137 | if (dragon[pos].status != DEAD) { | |
138 | for (k = 0; k < 12; k++) { | |
139 | int d = delta[k%8]; | |
140 | ||
141 | if (k >= 8) { | |
142 | if (board[pos + d] != EMPTY) | |
143 | continue; | |
144 | d *= 2; | |
145 | } | |
146 | if (board[pos + d] == EMPTY) | |
147 | potential_color[pos + d] |= board[pos]; | |
148 | } | |
149 | } | |
150 | } | |
151 | ||
152 | ||
153 | for (pos = BOARDMIN; pos < BOARDMAX; pos++) { | |
154 | /* It seems we can't trust an empty liberty to be gray-colored | |
155 | * either as a cave or as a cavity. Instead we look for empty | |
156 | * intersections with at least one neighbor of each color, where | |
157 | * dead stones count as enemy stones. We also count empty | |
158 | * neighbors to either color if the opponent can't play there. | |
159 | */ | |
160 | int found_white = 0; | |
161 | int found_black = 0; | |
162 | ||
163 | if (board[pos] != EMPTY) | |
164 | continue; | |
165 | ||
166 | /* Quick rejection based on preliminary test above. */ | |
167 | if (potential_color[pos] != GRAY) | |
168 | continue; | |
169 | ||
170 | /* Loop over the neighbors. */ | |
171 | for (k = 0; k < 4; k++) { | |
172 | int d = delta[k]; | |
173 | if (ON_BOARD(pos + d)) | |
174 | analyze_neighbor(pos + d, &found_black, &found_white); | |
175 | } | |
176 | ||
177 | /* Do we have neighbors of both colors? */ | |
178 | if (!(found_white && found_black)) | |
179 | continue; | |
180 | ||
181 | /* Ok, we wish to play here, but maybe we can't. The following | |
182 | * cases may occur: | |
183 | * 1. Move is legal and safe. | |
184 | * 2. Move is legal but not safe because it's in the middle of a seki. | |
185 | * 3. Move is legal but not safe, can be played after backfilling. | |
186 | * 4. Move is an illegal ko recapture. | |
187 | * 5. Move is illegal but can be played after back-captures. | |
188 | * 6. Move would violate confirm_safety. | |
189 | */ | |
190 | ||
191 | DEBUG(DEBUG_FILLLIB, "Filllib: Considering move at %1m.\n", pos); | |
192 | ||
193 | /* Legal and tactically safe, play it if it passes | |
194 | * confirm_safety test, i.e. that it isn't a blunder which | |
195 | * causes problems for other strings. | |
196 | */ | |
197 | if (safe_move(pos, color) == WIN) { | |
198 | DEBUG(DEBUG_FILLLIB, "Filllib: Tactically safe.\n"); | |
199 | if (filllib_confirm_safety(pos, color, &defense_point)) { | |
200 | /* Safety confirmed. */ | |
201 | DEBUG(DEBUG_FILLLIB, "Filllib: Safety confirmed.\n"); | |
202 | *move = pos; | |
203 | return 1; | |
204 | } | |
205 | else if (defense_point != NO_MOVE && is_legal(defense_point, color)) { | |
206 | /* Safety not confirmed because the move at (pos) would set | |
207 | * up a double threat. (defense_point) is assumed to defend | |
208 | * against this threat. | |
209 | * | |
210 | * FIXME: We should verify that (defense_point) really is effective. | |
211 | */ | |
212 | DEBUG(DEBUG_FILLLIB, | |
213 | "Filllib: Safety not confirmed, but %1m defends.\n", | |
214 | defense_point); | |
215 | *move = defense_point; | |
216 | return 1; | |
217 | } | |
218 | else { | |
219 | /* The move causes problems somewhere else on the board, so | |
220 | * we have to discard it. If everything works right this | |
221 | * should not happen at this time. | |
222 | */ | |
223 | DEBUG(DEBUG_FILLLIB, "Filllib: Safety not confirmed, discarded.\n"); | |
224 | TRACE("Warning: Blunder detected in fill_liberty().\n"); | |
225 | continue; | |
226 | } | |
227 | } | |
228 | ||
229 | /* Try to play the move. */ | |
230 | if (trymove(pos, color, "fill_liberty", NO_MOVE)) { | |
231 | int forbidden_moves[BOARDMAX]; | |
232 | popgo(); | |
233 | /* Legal, but not safe. Look for backfilling move. */ | |
234 | DEBUG(DEBUG_FILLLIB, | |
235 | "Filllib: Legal but not safe, looking for backfilling move.\n"); | |
236 | ||
237 | memset(forbidden_moves, 0, sizeof(forbidden_moves)); | |
238 | while (find_backfilling_move(pos, color, move, forbidden_moves)) { | |
239 | /* Mark as forbidden in case we need another turn in the loop. */ | |
240 | forbidden_moves[*move] = 1; | |
241 | ||
242 | DEBUG(DEBUG_FILLLIB, "Filllib: Backfilling move at %1m.\n", *move); | |
243 | /* In certain positions it may happen that an illegal move | |
244 | * is found. This probably only can happen if we try to play | |
245 | * a move inside a lost semeai. Anyway we should discard the | |
246 | * move. | |
247 | */ | |
248 | if (!is_legal(*move, color)) { | |
249 | DEBUG(DEBUG_FILLLIB, "Filllib: Was illegal, discarded.\n"); | |
250 | *move = NO_MOVE; | |
251 | continue; | |
252 | } | |
253 | ||
254 | /* If the move turns out to be strategically unsafe, or | |
255 | * setting up a double threat elsewhere, also discard it. | |
256 | */ | |
257 | if (!filllib_confirm_safety(*move, color, &defense_point)) { | |
258 | DEBUG(DEBUG_FILLLIB, | |
259 | "Filllib: Safety not confirmed, discarded.\n"); | |
260 | *move = NO_MOVE; | |
261 | continue; | |
262 | } | |
263 | ||
264 | /* Seems to be ok. */ | |
265 | return 1; | |
266 | } | |
267 | ||
268 | /* No acceptable backfilling move found. | |
269 | * If we captured some stones, this move should be ok anyway. | |
270 | */ | |
271 | if (does_capture_something(pos, color)) { | |
272 | DEBUG(DEBUG_FILLLIB, | |
273 | "Filllib: Not tactically safe, but captures stones.\n"); | |
274 | if (!filllib_confirm_safety(pos, color, &defense_point)) { | |
275 | DEBUG(DEBUG_FILLLIB, | |
276 | "Filllib: Safety not confirmed, discarded.\n"); | |
277 | continue; | |
278 | } | |
279 | *move = pos; | |
280 | return 1; | |
281 | } | |
282 | } | |
283 | else { | |
284 | /* Move is illegal. Look for an attack on one of the neighbor | |
285 | * worms. If found, return that move for back-capture. | |
286 | */ | |
287 | DEBUG(DEBUG_FILLLIB, "Filllib: Illegal, looking for back-capture.\n"); | |
288 | for (k = 0; k < 4; k++) { | |
289 | int d = delta[k]; | |
290 | if (board[pos + d] == other | |
291 | && worm[pos + d].attack_codes[0] == WIN) { | |
292 | *move = worm[pos + d].attack_points[0]; | |
293 | DEBUG(DEBUG_FILLLIB, "Filllib: Found at %1m.\n", *move); | |
294 | return 1; | |
295 | } | |
296 | } | |
297 | ||
298 | DEBUG(DEBUG_FILLLIB, | |
299 | "Filllib: Nothing found, looking for ko back-capture.\n"); | |
300 | for (k = 0; k < 4; k++) { | |
301 | int d = delta[k]; | |
302 | if (board[pos + d] == other | |
303 | && worm[pos + d].attack_codes[0] != 0 | |
304 | && is_legal(worm[pos + d].attack_points[0], color)) { | |
305 | *move = worm[pos + d].attack_points[0]; | |
306 | DEBUG(DEBUG_FILLLIB, "Filllib: Found at %1m.\n", *move); | |
307 | return 1; | |
308 | } | |
309 | } | |
310 | ||
311 | DEBUG(DEBUG_FILLLIB, | |
312 | "Filllib: Nothing found, looking for threat to back-capture.\n"); | |
313 | for (k = 0; k < 4; k++) { | |
314 | int d = delta[k]; | |
315 | if (board[pos + d] == other | |
316 | && worm[pos + d].attack_codes[0] != 0) { | |
317 | /* Just pick some other liberty. */ | |
318 | /* FIXME: Something is odd about this code. */ | |
319 | int libs[2]; | |
320 | if (findlib(pos + d, 2, libs) > 1) { | |
321 | if (is_legal(libs[0], color)) | |
322 | *move = libs[0]; | |
323 | else if (is_legal(libs[1], color)) | |
324 | *move = libs[1]; | |
325 | else | |
326 | continue; | |
327 | ||
328 | DEBUG(DEBUG_FILLLIB, "Filllib: Found at %1m.\n", *move); | |
329 | return 1; | |
330 | } | |
331 | } | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | /* Nothing found. */ | |
337 | DEBUG(DEBUG_FILLLIB, "Filllib: No move found.\n"); | |
338 | return 0; | |
339 | } | |
340 | ||
341 | ||
342 | /* The strategy for finding a backfilling move is to first identify | |
343 | * moves that | |
344 | * | |
345 | * 1. defends the position obtained after playing (move). | |
346 | * 2. captures a stone adjacent to our neighbors to (move), before | |
347 | * (move) is played. | |
348 | * | |
349 | * Then we check which of these are legal before (move) is played. If | |
350 | * there is at least one, we take one of these arbitrarily as a | |
351 | * backfilling move. | |
352 | * | |
353 | * Now it may happen that (move) still isn't a safe move. In that case | |
354 | * we recurse to find a new backfilling move. To do things really | |
355 | * correctly we should also give the opponent the opportunity to keep | |
356 | * up the balance of the position by letting him do a backfilling move | |
357 | * of his own. Maybe this could also be arranged by recursing this | |
358 | * function. Currently we only do a half-hearted attempt to find | |
359 | * opponent moves. | |
360 | * | |
361 | * The purpose of the forbidden_moves[] array is to get a new | |
362 | * backfilling move if the first one later was found to be unsafe, | |
363 | * like backfilling for J5 at F9 in filllib:45. With F9 marked as | |
364 | * forbidden the correct move at G9 is found. | |
365 | */ | |
366 | static int adjs[MAXCHAIN]; | |
367 | static int libs[MAXLIBS]; | |
368 | ||
369 | static int | |
370 | find_backfilling_move(int move, int color, int *backfill_move, | |
371 | int forbidden_moves[BOARDMAX]) | |
372 | { | |
373 | int k; | |
374 | int liberties; | |
375 | int neighbors; | |
376 | int found_one = 0; | |
377 | int apos = NO_MOVE; | |
378 | int bpos = NO_MOVE; | |
379 | int extra_pop = 0; | |
380 | int success = 0; | |
381 | int acode; | |
382 | int saved_move = NO_MOVE; | |
383 | int opponent_libs; | |
384 | ||
385 | DEBUG(DEBUG_FILLLIB, "find_backfilling_move for %C %1m\n", color, move); | |
386 | if (debug & DEBUG_FILLLIB) | |
387 | dump_stack(); | |
388 | ||
389 | /* Play (move) and identify all liberties and adjacent strings. */ | |
390 | if (!trymove(move, color, "find_backfilling_move", move)) | |
391 | return 0; /* This shouldn't happen, I believe. */ | |
392 | ||
393 | /* The move wasn't safe, so there must be an attack for the | |
394 | * opponent. Save it for later use. | |
395 | */ | |
396 | acode = attack(move, &apos); | |
397 | gg_assert(acode != 0 && apos != NO_MOVE); | |
398 | ||
399 | /* Find liberties. */ | |
400 | liberties = findlib(move, MAXLIBS, libs); | |
401 | ||
402 | /* Find neighbors. */ | |
403 | neighbors = chainlinks(move, adjs); | |
404 | ||
405 | /* Remove (move) again. */ | |
406 | popgo(); | |
407 | ||
408 | /* It's most fun to capture stones. Start by trying to take some | |
409 | * neighbor off the board. If the attacking move does not directly | |
410 | * reduce the number of liberties of the attacked string we don't | |
411 | * trust it but keep it around if we don't find anything else. (See | |
412 | * filllib:17 for a position where this matters.) | |
413 | * | |
414 | * It is also necessary to take care to first attack the string with | |
415 | * the fewest liberties, which can probably be removed the fastest. | |
416 | * See filllib:37 for an example (J5 tactically attacks K7 but the | |
417 | * correct move is H5). | |
418 | * | |
419 | * FIXME: It seems we have to return immediately when we find an | |
420 | * attacking move, because recursing for further backfilling might | |
421 | * lead to moves which complete the capture but cannot be played | |
422 | * before the attacking move itself. This is not ideal but probably | |
423 | * good enough. | |
424 | * | |
425 | * In order to avoid losing unnecessary points while capturing dead | |
426 | * stones, we try first to capture stones in atari, second defending | |
427 | * at a liberty, and third capture stones with two or more | |
428 | * liberties. See filllib:43 for a position where capturing dead | |
429 | * stones (B10 or C8) loses a point compared to defending at a | |
430 | * liberty (C6). | |
431 | */ | |
432 | for (opponent_libs = 1; opponent_libs <= 1; opponent_libs++) { | |
433 | for (k = 0; k < neighbors; k++) { | |
434 | if (opponent_libs < 5 && countlib(adjs[k]) != opponent_libs) | |
435 | continue; | |
436 | if (attack(adjs[k], &bpos) == WIN) { | |
437 | if (forbidden_moves[bpos]) | |
438 | continue; | |
439 | if (liberty_of_string(bpos, adjs[k])) { | |
440 | *backfill_move = bpos; | |
441 | return 1; | |
442 | } | |
443 | else | |
444 | saved_move = bpos; | |
445 | } | |
446 | } | |
447 | } | |
448 | ||
449 | /* Otherwise look for a safe move at a liberty. */ | |
450 | if (!found_one) { | |
451 | for (k = 0; k < liberties; k++) { | |
452 | if (!forbidden_moves[libs[k]] && safe_move(libs[k], color) == WIN) { | |
453 | *backfill_move = libs[k]; | |
454 | found_one = 1; | |
455 | break; | |
456 | } | |
457 | } | |
458 | } | |
459 | ||
460 | if (!found_one) { | |
461 | for (opponent_libs = 2; opponent_libs <= 5; opponent_libs++) { | |
462 | for (k = 0; k < neighbors; k++) { | |
463 | if (opponent_libs < 5 && countlib(adjs[k]) != opponent_libs) | |
464 | continue; | |
465 | if (attack(adjs[k], &bpos) == WIN) { | |
466 | if (forbidden_moves[bpos]) | |
467 | continue; | |
468 | if (liberty_of_string(bpos, adjs[k])) { | |
469 | *backfill_move = bpos; | |
470 | return 1; | |
471 | } | |
472 | else | |
473 | saved_move = bpos; | |
474 | } | |
475 | } | |
476 | } | |
477 | } | |
478 | ||
479 | /* If no luck so far, try with superstring liberties. */ | |
480 | if (!found_one) { | |
481 | trymove(move, color, "find_backfilling_move", move); | |
482 | find_proper_superstring_liberties(move, &liberties, libs, 0); | |
483 | popgo(); | |
484 | for (k = 0; k < liberties; k++) { | |
485 | if (!forbidden_moves[libs[k]] && safe_move(libs[k], color) == WIN) { | |
486 | *backfill_move = libs[k]; | |
487 | found_one = 1; | |
488 | break; | |
489 | } | |
490 | } | |
491 | } | |
492 | ||
493 | /* If no luck so far, try attacking superstring neighbors. */ | |
494 | if (!found_one) { | |
495 | trymove(move, color, "find_backfilling_move", move); | |
496 | superstring_chainlinks(move, &neighbors, adjs, 4); | |
497 | popgo(); | |
498 | for (k = 0; k < neighbors; k++) { | |
499 | if (attack(adjs[k], &bpos) == WIN) { | |
500 | if (!forbidden_moves[bpos] && liberty_of_string(bpos, adjs[k])) { | |
501 | *backfill_move = bpos; | |
502 | return 1; | |
503 | } | |
504 | } | |
505 | } | |
506 | } | |
507 | ||
508 | if (found_one) { | |
509 | ASSERT1(!forbidden_moves[*backfill_move], *backfill_move); | |
510 | ||
511 | if (!trymove(*backfill_move, color, "find_backfilling_move", move)) | |
512 | return 0; /* This really shouldn't happen. */ | |
513 | ||
514 | /* Allow opponent to get a move in here. */ | |
515 | if (trymove(apos, OTHER_COLOR(color), "find_backfilling_move", move)) | |
516 | extra_pop = 1; | |
517 | ||
518 | /* If still not safe, recurse to find a new backfilling move. */ | |
519 | if (safe_move(move, color) == WIN) | |
520 | success = 1; | |
521 | else | |
522 | success = find_backfilling_move(move, color, backfill_move, | |
523 | forbidden_moves); | |
524 | ||
525 | /* Pop move(s) and return. */ | |
526 | if (extra_pop) | |
527 | popgo(); | |
528 | popgo(); | |
529 | } | |
530 | ||
531 | if (!success && saved_move != NO_MOVE) { | |
532 | ASSERT1(!forbidden_moves[saved_move], saved_move); | |
533 | *backfill_move = saved_move; | |
534 | success = 1; | |
535 | } | |
536 | ||
537 | if (!success) | |
538 | *backfill_move = NO_MOVE; | |
539 | ||
540 | return success; | |
541 | } | |
542 | ||
543 | ||
544 | /* Confirm that (move) is a safe move for color. In addition to | |
545 | * calling the global confirm_safety(), this function also calls the | |
546 | * owl code to verify the strategical viability of the move. | |
547 | */ | |
548 | static int | |
549 | filllib_confirm_safety(int move, int color, int *defense_point) | |
550 | { | |
551 | int k; | |
552 | int apos = NO_MOVE; | |
553 | int save_verbose; | |
554 | ||
555 | gg_assert(stackp == 0); | |
556 | gg_assert(defense_point != NULL); | |
557 | *defense_point = NO_MOVE; | |
558 | ||
559 | /* Before we can call the owl code, we need to find a neighbor of | |
560 | * our color. | |
561 | */ | |
562 | for (k = 0; k < 4; k++) | |
563 | if (board[move + delta[k]] == color) { | |
564 | apos = move + delta[k]; | |
565 | break; | |
566 | } | |
567 | ||
568 | /* If none found, look for a neighbor of an attacked adjacent string. */ | |
569 | if (apos == NO_MOVE) | |
570 | for (k = 0; k < 4; k++) { | |
571 | int pos2 = move + delta[k]; | |
572 | if (board[pos2] == OTHER_COLOR(color) | |
573 | && !play_attack_defend_n(color, 0, 1, move, pos2)) { | |
574 | int adj; | |
575 | adj = chainlinks(pos2, adjs); | |
576 | /* It seems unlikely that we would ever get no adjacent strings | |
577 | * here, but if it should happen we simply give up and say the | |
578 | * move is unsafe. | |
579 | */ | |
580 | if (adj == 0) | |
581 | return 0; | |
582 | ||
583 | apos = adjs[0]; | |
584 | break; | |
585 | } | |
586 | } | |
587 | ||
588 | /* Next attempt are diagonal neighbors. */ | |
589 | if (apos == NO_MOVE) { | |
590 | for (k = 4; k < 8; k++) | |
591 | if (board[move + delta[k]] == color) { | |
592 | apos = move + delta[k]; | |
593 | break; | |
594 | } | |
595 | } | |
596 | ||
597 | /* And two steps away. */ | |
598 | if (apos == NO_MOVE) { | |
599 | for (k = 0; k < 4; k++) | |
600 | if (board[move + 2 * delta[k]] == color) { | |
601 | apos = move + 2 * delta[k]; | |
602 | break; | |
603 | } | |
604 | } | |
605 | ||
606 | /* We should have found something by now. If not something's | |
607 | * probably broken elsewhere. Declare the move unsafe if it happens. | |
608 | */ | |
609 | if (apos == NO_MOVE) | |
610 | return 0; | |
611 | ||
612 | /* Ask the owl code whether this move is strategically viable. */ | |
613 | ||
614 | save_verbose = verbose; | |
615 | if (verbose > 0) | |
616 | verbose--; | |
617 | if (!owl_does_defend(move, apos, NULL)) | |
618 | return 0; | |
619 | verbose = save_verbose; | |
620 | ||
621 | return confirm_safety(move, color, defense_point, NULL); | |
622 | } | |
623 | ||
624 | ||
625 | /* | |
626 | * Local Variables: | |
627 | * tab-width: 8 | |
628 | * c-basic-offset: 2 | |
629 | * End: | |
630 | */ |