Updated README: Equal sign not required with `--mode` flag.
[sgk-go] / engine / owl.c
CommitLineData
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 * The code in this file implements "Optics With Limit-negotiation (OWL)."
26 *
27 * The life and death code in optics.c, works reasonably well as long as the
28 * position is in a *terminal position*, which we define to be one where there
29 * are no moves left which can expand the eye space, or limit it. In
30 * situations where the dragon is surrounded, yet has room to thrash around a
31 * bit making eyes, a simple application of the graph-based analysis will not
32 * work. Instead, a bit of reading is needed to reach a terminal position.
33 * The defender tries to expand his eyespace, the attacker to limit it, and
34 * when neither finds an effective move, the position is evaluated. We call
35 * this type of life and death reading *Optics With Limit-negotiation* (OWL).
36 *
37 * (|__|)
38 * (@)(@))
39 * |:v:: |
40 * ( )
41 * \| |/
42 * =#===#=
43 * /___/
44 *
45 * The owl is noted for its keen vision
46 * and (purported) wisdom.
47 */
48
49#include "gnugo.h"
50
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include "liberty.h"
55#include "readconnect.h"
56#include "patterns.h"
57#include "cache.h"
58#include "sgftree.h"
59#include "gg_utils.h"
60
61#define MAX_MOVES 3 /* maximum number of branches at each node */
62#define MAX_SEMEAI_MOVES 6 /* semeai branch factor */
63#define MAX_SEMEAI_DEPTH 100 /* Don't read below this depth */
64#define MAX_LUNCHES 10
65#define MAX_GOAL_WORMS 15 /* maximum number of worms in a dragon to be */
66 /* cataloged. NOTE: Must fit in value2 in hashnode! */
67#define MAX_ESCAPE 3 /* After this many escape moves, owl_determine_life is */
68 /* not called */
69
70struct local_owl_data {
71 signed char goal[BOARDMAX];
72 signed char boundary[BOARDMAX];
73 /* Same as goal, except never anything is removed from it. */
74 signed char cumulative_goal[BOARDMAX];
75
76 /* FIXME: neighbors[] and escape_values[] are never recomputed.
77 * Consider moving these arrays from stack to a static or
78 * dynamic variable so it is not copied around in
79 * do_push_owl(). Be aware of semeai code though.
80 */
81 signed char neighbors[BOARDMAX];
82
83 signed char escape_values[BOARDMAX];
84 int color;
85
86 struct eye_data my_eye[BOARDMAX];
87 /* array of half-eye data for use during owl reading */
88 struct half_eye_data half_eye[BOARDMAX];
89
90 int lunch[MAX_LUNCHES];
91 int lunch_attack_code[MAX_LUNCHES];
92 int lunch_attack_point[MAX_LUNCHES];
93 int lunch_defend_code[MAX_LUNCHES];
94 int lunch_defense_point[MAX_LUNCHES];
95 signed char inessential[BOARDMAX];
96
97 int lunches_are_current; /* If true, owl lunch data is current */
98
99 signed char safe_move_cache[BOARDMAX];
100
101 /* This is used to organize the owl stack. */
102 struct local_owl_data *restore_from;
103};
104
105
106static int result_certain;
107
108/* Statistics. */
109static int local_owl_node_counter;
110/* Node limitation. */
111static int global_owl_node_counter = 0;
112
113static struct local_owl_data *current_owl_data;
114static struct local_owl_data *other_owl_data;
115
116static int goal_worms_computed = 0;
117static int owl_goal_worm[MAX_GOAL_WORMS];
118
119
120#define MAX_CUTS 5
121
122enum same_dragon_value {
123 SAME_DRAGON_NOT_CONNECTED,
124 SAME_DRAGON_MAYBE_CONNECTED,
125 SAME_DRAGON_CONNECTED,
126 SAME_DRAGON_ALL_CONNECTED
127};
128
129struct matched_pattern_data;
130
131struct owl_move_data {
132 int pos; /* move coordinate */
133 int value; /* value */
134 const char *name; /* name of the pattern suggesting the move */
135 /* whether the move extends the dragon or not */
136 enum same_dragon_value same_dragon;
137 int lunch; /* Position of a lunch, if applicable.*/
138 int escape; /* true if an escape pattern is matched */
139 int defense_pos; /* defense coordinate for vital owl attack patterns. */
140 int cuts[MAX_CUTS]; /* strings of the goal that might get cut off */
141 /* pointer to pattern data, used for SAME_DRAGON_ALL_CONNECTED */
142 struct matched_pattern_data *pattern_data;
143};
144
145#define USE_BDIST 1
146
147struct matched_pattern_data {
148 int move;
149 int value;
150 int ll;
151 int anchor;
152#if USE_BDIST
153 int bdist;
154#endif
155 struct pattern *pattern;
156
157 /* To link combinable patterns in chains. */
158 int next_pattern_index;
159};
160
161struct matched_patterns_list_data {
162 int initialized;
163 int counter; /* Number of patterns in the list. */
164 int used; /* How many patterns have already been used?*/
165 int list_size;
166 struct matched_pattern_data *pattern_list;
167 int first_pattern_index[BOARDMAX];
168
169 int heap_num_patterns;
170 struct matched_pattern_data **pattern_heap;
171};
172
173void dump_pattern_list(struct matched_patterns_list_data *list);
174
175
176static int do_owl_attack(int str, int *move, int *wormid,
177 struct local_owl_data *owl, int escape);
178static int do_owl_defend(int str, int *move, int *wormid,
179 struct local_owl_data *owl, int escape);
180static void owl_shapes(struct matched_patterns_list_data *list,
181 struct owl_move_data moves[MAX_MOVES], int color,
182 struct local_owl_data *owl, struct pattern_db *type);
183static void collect_owl_shapes_callbacks(int anchor, int color,
184 struct pattern *pattern_db,
185 int ll, void *data);
186
187static void pattern_list_prepare(struct matched_patterns_list_data *list);
188static void pattern_list_build_heap(struct matched_patterns_list_data *list);
189static void pattern_list_pop_heap_once(struct matched_patterns_list_data *list);
190static void pattern_list_sink_heap_top_element(struct matched_patterns_list_data
191 *list);
192
193static int get_next_move_from_list(struct matched_patterns_list_data *list,
194 int color, struct owl_move_data *moves,
195 int cutoff, struct local_owl_data *owl);
196static void init_pattern_list(struct matched_patterns_list_data *list);
197static void close_pattern_list(int color,
198 struct matched_patterns_list_data *list);
199static void owl_shapes_callback(int anchor, int color,
200 struct pattern *pattern_db,
201 int ll, void *data);
202static void owl_add_move(struct owl_move_data *moves, int move, int value,
203 const char *reason,
204 enum same_dragon_value same_dragon, int lunch,
205 int escape, int defense_pos, int max_moves,
206 struct matched_pattern_data *pattern_data);
207static void owl_determine_life(struct local_owl_data *owl,
208 struct local_owl_data *second_owl,
209 int does_attack,
210 struct owl_move_data *moves,
211 struct eyevalue *probable_eyes,
212 int *eyemin, int *eyemax);
213static void owl_find_relevant_eyespaces(struct local_owl_data *owl,
214 int mw[BOARDMAX], int mz[BOARDMAX]);
215static int owl_estimate_life(struct local_owl_data *owl,
216 struct local_owl_data *second_owl,
217 struct owl_move_data vital_moves[MAX_MOVES],
218 const char **live_reason,
219 int does_attack,
220 struct eyevalue *probable_eyes,
221 int *eyemin, int *eyemax);
222static int modify_stupid_eye_vital_point(struct local_owl_data *owl,
223 int *vital_point,
224 int is_attack_point);
225static int modify_eyefilling_move(int *move, int color);
226static int estimate_lunch_half_eye_bonus(int lunch,
227 struct half_eye_data half_eye[BOARDMAX]);
228static void owl_mark_dragon(int apos, int bpos,
229 struct local_owl_data *owl,
230 int new_dragons[BOARDMAX]);
231static void owl_mark_worm(int apos, int bpos,
232 struct local_owl_data *owl);
233static void owl_mark_boundary(struct local_owl_data *owl);
234static void owl_update_goal(int pos, enum same_dragon_value same_dragon,
235 int lunch, struct local_owl_data *owl,
236 int semeai_call,
237 struct matched_pattern_data *pattern_data);
238static void owl_test_cuts(signed char goal[BOARDMAX], int color,
239 int cuts[MAX_CUTS]);
240static void componentdump(const signed char component[BOARDMAX]);
241static void owl_update_boundary_marks(int pos, struct local_owl_data *owl);
242static void owl_find_lunches(struct local_owl_data *owl);
243static int improve_lunch_attack(int lunch, int attack_point);
244static int improve_lunch_defense(int lunch, int defense_point);
245static void owl_make_domains(struct local_owl_data *owla,
246 struct local_owl_data *owlb);
247static int owl_safe_move(int move, int color);
248static void sniff_lunch(int lunch, int *min, int *probable, int *max,
249 struct local_owl_data *owl);
250static void eat_lunch_escape_bonus(int lunch, int *min, int *probable,
251 int *max, struct local_owl_data *owl);
252static int select_new_goal_origin(int origin, struct local_owl_data *owl);
253static void compute_owl_escape_values(struct local_owl_data *owl);
254static int owl_escape_route(struct local_owl_data *owl);
255static void do_owl_analyze_semeai(int apos, int bpos,
256 struct local_owl_data *owla,
257 struct local_owl_data *owlb,
258 int *resulta, int *resultb,
259 int *move, int pass, int owl_phase);
260static int semeai_trymove_and_recurse(int apos, int bpos,
261 struct local_owl_data *owla,
262 struct local_owl_data *owlb,
263 int owl_phase,
264 int move, int color, int ko_allowed,
265 int move_value, const char *move_name,
266 enum same_dragon_value same_dragon,
267 struct matched_pattern_data *pattern_data,
268 int lunch, int *semeai_move,
269 int *this_resulta, int *this_resultb);
270static void semeai_add_sgf_comment(int value, int owl_phase);
271static int semeai_trust_tactical_attack(int str);
272static int semeai_propose_eyespace_filling_move(struct local_owl_data *owla,
273 struct local_owl_data *owlb);
274static void semeai_review_owl_moves(struct owl_move_data owl_moves[MAX_MOVES],
275 struct local_owl_data *owla,
276 struct local_owl_data *owlb, int color,
277 int *safe_outside_liberty_found,
278 int *safe_common_liberty_found,
279 int *riskless_move_found,
280 signed char mw[BOARDMAX],
281 struct owl_move_data semeai_moves[MAX_SEMEAI_MOVES],
282 int guess_same_dragon, int value_bonus,
283 int *critical_semeai_worms);
284static int semeai_move_value(int move, struct local_owl_data *owla,
285 struct local_owl_data *owlb, int raw_value,
286 int *critical_semeai_worms);
287static int semeai_is_riskless_move(int move, struct local_owl_data *owla);
288static void remove_eye_filling_moves(struct local_owl_data *our_owl,
289 struct owl_move_data *moves);
290static int find_semeai_backfilling_move(int worm, int liberty);
291static int liberty_of_goal(int pos, struct local_owl_data *owl);
292static int second_liberty_of_goal(int pos, struct local_owl_data *owl);
293static int matches_found;
294static signed char found_matches[BOARDMAX];
295
296static void reduced_init_owl(struct local_owl_data **owl,
297 int at_bottom_of_stack);
298static void init_owl(struct local_owl_data **owl, int target1, int target2,
299 int move, int use_stack, int new_dragons[BOARDMAX]);
300
301static struct local_owl_data *owl_stack[2 * MAXSTACK];
302static int owl_stack_size = 0;
303static int owl_stack_pointer = 0;
304static void check_owl_stack_size(void);
305static void push_owl(struct local_owl_data **owl);
306static void do_push_owl(struct local_owl_data **owl);
307static void pop_owl(struct local_owl_data **owl);
308
309#if 0
310static int catalog_goal(struct local_owl_data *owl,
311 int goal_worm[MAX_GOAL_WORMS]);
312#endif
313
314static int list_goal_worms(struct local_owl_data *owl,
315 int goal_worm[MAX_GOAL_WORMS]);
316
317/* FIXME: taken from move_reasons.h */
318#define MAX_DRAGONS 2 * MAX_BOARD * MAX_BOARD / 3
319
320static int dragon_goal_worms[MAX_DRAGONS][MAX_GOAL_WORMS];
321
322static void
323prepare_goal_list(int str, struct local_owl_data *owl,
324 int list[MAX_GOAL_WORMS], int *flag, int *kworm,
325 int do_list);
326static void
327finish_goal_list(int *flag, int *wpos, int list[MAX_GOAL_WORMS], int index);
328
329
330/* Semeai worms are worms whose capture wins the semeai. */
331
332#define MAX_SEMEAI_WORMS 20
333static int s_worms = 0;
334static int semeai_worms[MAX_SEMEAI_WORMS];
335static int important_semeai_worms[MAX_SEMEAI_WORMS];
336
337/* Whether one color prefers to get a ko over a seki. */
338static int prefer_ko;
339
340/* Usually it's a bad idea to include the opponent worms involved in
341 * the semeai in the eyespace. For some purposes (determining a
342 * definite lack of eyespace, finding certain vital moves), however,
343 * we want to do that anyway. Then set this variable to 1 before
344 * calling owl_estimate_life() and reset it afterwards.
345 *
346 * FIXME: We should implement a nicer mechanism to propagate this
347 * information to owl_lively(), where it's used.
348 */
349static int include_semeai_worms_in_eyespace = 0;
350
351
352
353static void
354clear_cut_list(int cuts[MAX_CUTS])
355{
356 int i;
357 for (i = 0; i < MAX_CUTS; i++)
358 cuts[i] = NO_MOVE;
359}
360
361
362
363/* Called when (apos) and (bpos) point to adjacent dragons
364 * of the opposite color, both with matcher_status DEAD or
365 * CRITICAL, analyzes the semeai, assuming that the player
366 * of the (apos) dragon moves first. The results returned
367 * by *resulta and *resultb are the results of the defense
368 * of the apos dragon and the attack of the bpos dragon,
369 * respectively. Thus if these results are 1 and 0,
370 * respectively, the usual meaning is that a move by the
371 * apos player produces seki.
372 *
373 * owl determines whether owl moves are being generated
374 * or simple liberty filling is taking place.
375 *
376 */
377
378void
379owl_analyze_semeai(int apos, int bpos, int *resulta, int *resultb,
380 int *semeai_move, int owl, int *semeai_result_certain)
381{
382 owl_analyze_semeai_after_move(PASS_MOVE, EMPTY, apos, bpos, resulta, resultb,
383 semeai_move, owl, semeai_result_certain, 0);
384}
385
386/* Same as the function above with the addition that an arbitrary move
387 * may be made before the analysis is performed.
388 */
389void
390owl_analyze_semeai_after_move(int move, int color, int apos, int bpos,
391 int *resulta, int *resultb, int *semeai_move,
392 int owl, int *semeai_result_certain,
393 int recompute_dragons)
394{
395 signed char ms[BOARDMAX];
396 int w1, w2;
397 int str;
398 SGFTree *save_sgf_dumptree = sgf_dumptree;
399 int save_verbose = verbose;
400 int dummy_resulta;
401 int dummy_resultb;
402 int dummy_semeai_move;
403 double start = 0.0;
404 int reading_nodes_when_called = get_reading_node_counter();
405 int nodes_used;
406 int new_dragons[BOARDMAX];
407
408 struct local_owl_data *owla;
409 struct local_owl_data *owlb;
410 Hash_data goal_hash;
411
412 if (!resulta)
413 resulta = &dummy_resulta;
414 if (!resultb)
415 resultb = &dummy_resultb;
416 if (!semeai_move)
417 semeai_move = &dummy_semeai_move;
418
419 if (debug & DEBUG_OWL_PERFORMANCE)
420 start = gg_cputime();
421
422 if (recompute_dragons) {
423 if (tryko(move, color, "Recompute dragons for semeai.")) {
424 compute_new_dragons(new_dragons);
425 popgo();
426 }
427 else
428 recompute_dragons = 0;
429 }
430
431
432 /* Look for owl substantial worms of either dragon adjoining
433 * the other dragon. Capturing such a worm wins the semeai.
434 * These are the semeai_worms. This code must come before
435 * the owl_init() calls because the owl_substantial
436 *
437 * FIXME: The sentence above is unfinished.
438 */
439 s_worms = 0;
440 memset(ms, 0, sizeof(ms));
441 for (w1 = first_worm_in_dragon(apos);
442 w1 != NO_MOVE;
443 w1 = next_worm_in_dragon(w1)) {
444 for (w2 = first_worm_in_dragon(bpos);
445 w2 != NO_MOVE;
446 w2 = next_worm_in_dragon(w2)) {
447 if (adjacent_strings(w1, w2) || have_common_lib(w1, w2, NULL)) {
448 mark_string(w1, ms, 1);
449 mark_string(w2, ms, 1);
450 }
451 }
452 }
453
454
455
456 sgf_dumptree = NULL;
457 if (verbose > 0)
458 verbose--;
459 for (str = BOARDMIN; str < BOARDMAX; str++)
460 if (ON_BOARD(str) && ms[str] && worm[str].origin == str) {
461 int adj;
462 int adjs[MAXCHAIN];
463 int k;
464 int adjacent_to_outside = 0;
465
466 /* Is the string adjacent to a living dragon outside the semeai?
467 * In that case it's important to attack/defend it for the life
468 * of the opponent.
469 *
470 * FIXME: Checking crude_status here isn't quite appropriate but
471 * owl_status is not always computed and status itself is unsafe
472 * since it might change before later calls to this code, e.g.
473 * when checking for blunders.
474 *
475 * Not checking for aliveness at all gives problems in e.g.
476 * ld_owl:302 where S19 is a separate dragon and R19 should not
477 * be considered critically important. What we really would like
478 * to determine is whether it's outside the semeai, however.
479 */
480 adj = chainlinks(str, adjs);
481 for (k = 0; k < adj; k++) {
482 if (!is_same_dragon(adjs[k], apos)
483 && !is_same_dragon(adjs[k], bpos)
484 && dragon[adjs[k]].crude_status == ALIVE)
485 adjacent_to_outside = 1;
486 }
487
488 if ((adjacent_to_outside || countstones(str) > 6)
489 && s_worms < MAX_SEMEAI_WORMS) {
490 important_semeai_worms[s_worms] = 1;
491 semeai_worms[s_worms++] = str;
492 DEBUG(DEBUG_SEMEAI, "important semeai worm: %1m\n", str);
493 }
494 else if (owl_substantial(str) && s_worms < MAX_SEMEAI_WORMS) {
495 important_semeai_worms[s_worms] = 0;
496 semeai_worms[s_worms++] = str;
497 DEBUG(DEBUG_SEMEAI, "semeai worm: %1m\n", str);
498 }
499 }
500 verbose = save_verbose;
501 sgf_dumptree = save_sgf_dumptree;
502
503 ASSERT1(board[apos] == OTHER_COLOR(board[bpos]), apos);
504 count_variations = 1;
505 if (move == PASS_MOVE)
506 DEBUG(DEBUG_SEMEAI, "owl_analyze_semeai: %1m vs. %1m\n", apos, bpos);
507 else
508 DEBUG(DEBUG_SEMEAI, "owl_analyze_semeai_after_move %C %1m: %1m vs. %1m\n",
509 color, move, apos, bpos);
510
511 if (owl) {
512 if (recompute_dragons) {
513 init_owl(&owla, apos, NO_MOVE, NO_MOVE, 1, new_dragons);
514 init_owl(&owlb, bpos, NO_MOVE, NO_MOVE, 0, new_dragons);
515 }
516 else {
517 init_owl(&owla, apos, NO_MOVE, NO_MOVE, 1, NULL);
518 init_owl(&owlb, bpos, NO_MOVE, NO_MOVE, 0, NULL);
519 }
520 owl_make_domains(owla, owlb);
521 }
522 else {
523 reduced_init_owl(&owla, 1);
524 reduced_init_owl(&owlb, 0);
525 local_owl_node_counter = 0;
526 owl_mark_worm(apos, NO_MOVE, owla);
527 owl_mark_worm(bpos, NO_MOVE, owlb);
528 }
529
530 result_certain = 1;
531
532 {
533 Hash_data temp = goal_to_hashvalue(owla->goal);
534 goal_hash = goal_to_hashvalue(owlb->goal);
535 hashdata_xor(goal_hash, temp);
536 }
537 if (owl
538 && search_persistent_semeai_cache(ANALYZE_SEMEAI,
539 apos, bpos, move, color, &goal_hash,
540 resulta, resultb, semeai_move,
541 semeai_result_certain)) {
542 if (move == PASS_MOVE) {
543 DEBUG(DEBUG_OWL_PERFORMANCE,
544 "analyze_semeai %1m vs. %1m, result %d %d %1m (cached)\n",
545 apos, bpos, *resulta, *resultb, *semeai_move);
546 }
547 else {
548 DEBUG(DEBUG_OWL_PERFORMANCE,
549 "analyze_semeai_after_move %C %1m: %1m vs. %1m, result %d %d %1m (cached)\n",
550 color, move, apos, bpos, *resulta, *resultb, *semeai_move);
551 }
552 return;
553 }
554
555 /* In some semeai situations one or both players have the option to
556 * choose between seki and ko for the life and death of both. In
557 * general this choice depends on the ko threat situation, the
558 * overall score, and the strategical effects on surrounding
559 * dragons, but we don't try to correctly estimate this. Instead we
560 * make the reasonable assumption that if one dragon is
561 * substantially smaller than the other dragon, ko is to be
562 * preferred for the smaller dragon and seki for the larger dragon.
563 *
564 * prefer_ko can be either WHITE, BLACK, or EMPTY and tells which
565 * color, if any, prefers to get ko.
566 */
567 if (dragon[apos].size <= 5 && dragon[bpos].size > 3 * dragon[apos].size)
568 prefer_ko = board[apos];
569 else if (dragon[bpos].size <= 5 && dragon[apos].size > 3 * dragon[bpos].size)
570 prefer_ko = board[bpos];
571 else
572 prefer_ko = EMPTY;
573
574 if (move == PASS_MOVE)
575 do_owl_analyze_semeai(apos, bpos, owla, owlb,
576 resulta, resultb, semeai_move, 0, owl);
577 else {
578 semeai_trymove_and_recurse(bpos, apos, owlb, owla, owl,
579 move, color, 1, 0, "mandatory move",
580 SAME_DRAGON_MAYBE_CONNECTED, NULL, NO_MOVE,
581 semeai_move, resultb, resulta);
582 *resulta = REVERSE_RESULT(*resulta);
583 *resultb = REVERSE_RESULT(*resultb);
584 }
585
586 nodes_used = get_reading_node_counter() - reading_nodes_when_called;
587 if (move == PASS_MOVE) {
588 DEBUG(DEBUG_OWL_PERFORMANCE,
589 "analyze_semeai %1m vs. %1m, result %d %d %1m (%d, %d nodes, %f seconds)\n",
590 apos, bpos, *resulta, *resultb, *semeai_move, local_owl_node_counter,
591 nodes_used, gg_cputime() - start);
592 }
593 else {
594 DEBUG(DEBUG_OWL_PERFORMANCE,
595 "analyze_semeai_after_move %C %1m: %1m vs. %1m, result %d %d %1m (%d, %d nodes, %f seconds)\n",
596 color, move, apos, bpos, *resulta, *resultb, *semeai_move,
597 local_owl_node_counter,
598 nodes_used, gg_cputime() - start);
599 }
600
601 if (semeai_result_certain)
602 *semeai_result_certain = result_certain;
603
604 if (owl)
605 store_persistent_semeai_cache(ANALYZE_SEMEAI, apos, bpos, move, color,
606 &goal_hash,
607 *resulta, *resultb, *semeai_move,
608 result_certain, nodes_used,
609 owla->goal, owlb->goal);
610}
611
612
613
614/* It is assumed that the 'a' player moves first, and
615 * determines the best result for both players. The
616 * parameter "pass" is 1 if the opponent's last move is
617 * pass. In this case, if no move is found but the genus
618 * is less than 2, then the position is declared seki.
619 *
620 * If a move is needed to get this result, then (*move) is
621 * the location, otherwise this field returns PASS.
622 */
623
624static void
625do_owl_analyze_semeai(int apos, int bpos,
626 struct local_owl_data *owla,
627 struct local_owl_data *owlb,
628 int *resulta, int *resultb,
629 int *move, int pass, int owl_phase)
630{
631 int color = board[apos];
632 int other = OTHER_COLOR(color);
633#if 0
634 int wormsa, wormsb;
635 int goal_wormsa[MAX_GOAL_WORMS], goal_wormsb[MAX_GOAL_WORMS];
636#endif
637 struct owl_move_data vital_defensive_moves[MAX_MOVES];
638 struct owl_move_data vital_offensive_moves[MAX_MOVES];
639 struct owl_move_data shape_defensive_moves[MAX_MOVES];
640 struct owl_move_data shape_offensive_moves[MAX_MOVES];
641 struct matched_patterns_list_data shape_offensive_patterns;
642 struct matched_patterns_list_data shape_defensive_patterns;
643 struct owl_move_data moves[MAX_SEMEAI_MOVES];
644 struct owl_move_data outside_liberty;
645 struct owl_move_data common_liberty;
646 struct owl_move_data backfill_outside_liberty;
647 struct owl_move_data backfill_common_liberty;
648 int safe_outside_liberty_found = 0;
649 int safe_common_liberty_found = 0;
650 int riskless_move_found = 0;
651 signed char mw[BOARDMAX];
652 int k;
653 SGFTree *save_sgf_dumptree = sgf_dumptree;
654 int save_count_variations = count_variations;
655 int move_value;
656 int best_resulta = 0;
657 int best_resultb = 0;
658 int best_move = 0;
659 const char *best_move_name = NULL;
660 int this_resulta = -1;
661 int this_resultb = -1;
662 int xpos;
663 int value1;
664 int value2;
665 int this_variation_number = count_variations - 1;
666 int you_look_alive = 0;
667 int I_look_alive = 0;
668 int dummy_move;
669 int tested_moves;
670 int critical_semeai_worms[MAX_SEMEAI_WORMS];
671 int sworm;
672 int we_might_be_inessential;
673 struct eyevalue probable_eyes_a;
674 struct eyevalue probable_eyes_b;
675 struct eyevalue dummy_eyes;
676 int I_have_more_eyes;
677
678 SETUP_TRACE_INFO2("do_owl_analyze_semeai", apos, bpos);
679
680 if (!move)
681 move = &dummy_move;
682
683 ASSERT1(board[apos] == owla->color, apos);
684 ASSERT1(board[bpos] == owlb->color, bpos);
685
686 apos = find_origin(apos);
687 bpos = find_origin(bpos);
688
689 if (stackp <= semeai_branch_depth
690 && owl_phase
691 && tt_get(&ttable, SEMEAI, apos, bpos, depth - stackp, NULL,
692 &value1, &value2, &xpos) == 2) {
693 TRACE_CACHED_RESULT2(value1, value2, xpos);
694 *move = xpos;
695
696 *resulta = value1;
697 *resultb = value2;
698
699 TRACE("%oVariation %d: %1m %1m %s %s %1m (cached) ",
700 this_variation_number, apos, bpos,
701 result_to_string(*resulta),
702 result_to_string(*resultb),
703 *move);
704 SGFTRACE_SEMEAI(xpos, *resulta, *resultb, "cached");
705 return;
706 }
707
708 global_owl_node_counter++;
709 local_owl_node_counter++;
710
711 shape_offensive_patterns.initialized = 0;
712 shape_defensive_patterns.initialized = 0;
713
714#if 0
715 wormsa = catalog_goal(owla, goal_wormsa);
716 wormsb = catalog_goal(owlb, goal_wormsb);
717#endif
718
719 outside_liberty.pos = NO_MOVE;
720 common_liberty.pos = NO_MOVE;
721 backfill_outside_liberty.pos = NO_MOVE;
722 backfill_common_liberty.pos = NO_MOVE;
723 for (k = 0; k < MAX_SEMEAI_MOVES; k++) {
724 moves[k].pos = 0;
725 moves[k].value = -1;
726 moves[k].name = NULL;
727 moves[k].same_dragon = SAME_DRAGON_CONNECTED;
728 moves[k].lunch = NO_MOVE;
729 clear_cut_list(moves[k].cuts);
730 }
731 ASSERT1(other == board[bpos], bpos);
732 memset(mw, 0, sizeof(mw));
733
734 /* Turn off the sgf file and variation counting. */
735 sgf_dumptree = NULL;
736 count_variations = 0;
737
738 /* Look for a tactical attack. We seek a semeai worm of owlb which
739 * can be attacked. If such exists and is considered critical, we
740 * declare victory. If it's not considered critical we add the
741 * attacking move as a high priority move to try.
742 */
743
744 {
745 int upos;
746
747 for (sworm = 0; sworm < s_worms; sworm++) {
748 critical_semeai_worms[sworm] = 0;
749 if (board[semeai_worms[sworm]] == other) {
750 int acode = attack(semeai_worms[sworm], &upos);
751 if (acode == WIN
752 && semeai_trust_tactical_attack(semeai_worms[sworm])
753 && important_semeai_worms[sworm]) {
754 *resulta = WIN;
755 *resultb = WIN;
756 *move = upos;
757 sgf_dumptree = save_sgf_dumptree;
758 count_variations = save_count_variations;
759 SGFTRACE_SEMEAI(upos, WIN, WIN, "tactical win found");
760 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
761 move, upos, WIN, WIN);
762 }
763 else if (acode != 0
764 && find_defense(semeai_worms[sworm], NULL)) {
765 critical_semeai_worms[sworm] = 1;
766 owl_add_move(moves, upos, 105, "attack semeai worm",
767 SAME_DRAGON_MAYBE_CONNECTED,
768 NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL);
769 TRACE("Added %1m %d (-1)\n", upos, 105);
770 }
771 else if (acode == WIN
772 && important_semeai_worms[sworm]) {
773 owl_add_move(moves, upos, 100, "attack semeai worm",
774 SAME_DRAGON_MAYBE_CONNECTED,
775 NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL);
776 TRACE("Added %1m %d (-1)\n", upos, 100);
777 }
778 }
779 }
780 /* Look for a tactical rescue. If a semeai worm of owla is tactically
781 * threatened, try to save it.
782 */
783
784 we_might_be_inessential = 1;
785 for (sworm = 0; sworm < s_worms; sworm++)
786 if (board[semeai_worms[sworm]] == color) {
787 if (important_semeai_worms[sworm])
788 we_might_be_inessential = 0;
789
790 if (attack(semeai_worms[sworm], NULL)
791 && find_defense(semeai_worms[sworm], &upos)) {
792 critical_semeai_worms[sworm] = 1;
793 owl_add_move(moves, upos, 85, "defend semeai worm",
794 SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE,
795 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL);
796 TRACE("Added %1m %d (0)\n", upos, 85);
797 }
798 }
799 }
800
801 /* We generate the candidate moves. During the early stages of
802 * the semeai, there may be moves to expand or shrink the
803 * eyespaces of the two dragons. During the later stages, the
804 * picture is simplified and reading the semeai is a matter
805 * of filling liberties until one of the dragons may be removed,
806 * or a seki results. The first stage we call the owl phase.
807 */
808 if (!owl_phase) {
809 set_eyevalue(&probable_eyes_a, 0, 0, 0, 0);
810 set_eyevalue(&probable_eyes_b, 0, 0, 0, 0);
811 I_have_more_eyes = 0;
812 }
813 else {
814 /* First the vital moves. These include moves to attack or
815 * defend the eyespace (e.g. nakade, or hane to reduce the
816 * number of eyes) or moves to capture a lunch.
817 */
818 int eyemin_a;
819 int eyemin_b;
820 int eyemax_a;
821 int eyemax_b;
822 const char *live_reasona;
823 const char *live_reasonb;
824
825 /* We do not wish for any string of the 'b' dragon to be
826 * counted as a lunch of the 'a' dragon since owl_determine_life
827 * can give a wrong result in the case of a semeai. So we eliminate
828 * such lunches.
829 */
830
831 owl_find_lunches(owla);
832 owl_find_lunches(owlb);
833 for (k = 0; k < MAX_LUNCHES; k++) {
834 if (owla->lunch[k] != NO_MOVE
835 && owlb->goal[owla->lunch[k]]) {
836 owla->lunch[k] = NO_MOVE;
837 }
838 }
839#if 1
840 for (k = 0; k < MAX_LUNCHES; k++) {
841 if (owlb->lunch[k] != NO_MOVE
842 && owla->goal[owlb->lunch[k]]) {
843 owlb->lunch[k] = NO_MOVE;
844 }
845 }
846#endif
847
848 if (owl_estimate_life(owla, owlb, vital_defensive_moves,
849 &live_reasona, 0, &probable_eyes_a,
850 &eyemin_a, &eyemax_a))
851 I_look_alive = 1;
852 else if (stackp > 2 && owl_escape_route(owla) >= 5) {
853 live_reasona = "escaped";
854 I_look_alive = 1;
855 }
856
857 if (owl_estimate_life(owlb, owla, vital_offensive_moves,
858 &live_reasonb, 1, &probable_eyes_b,
859 &eyemin_b, &eyemax_b))
860 you_look_alive = 1;
861 else if (stackp > 2 && owl_escape_route(owlb) >= 5) {
862 live_reasonb = "escaped";
863 you_look_alive = 1;
864 }
865
866 if (verbose) {
867 gprintf("probable_eyes_a: %s eyemin: %d eyemax: %d",
868 eyevalue_to_string(&probable_eyes_a), eyemin_a, eyemax_a);
869 if (I_look_alive)
870 gprintf("%o I look alive (%s)", live_reasona);
871 gprintf("%o\n");
872 gprintf("probable_eyes_b: %s eyemin: %d eyemax: %d",
873 eyevalue_to_string(&probable_eyes_b), eyemin_b, eyemax_b);
874 if (you_look_alive)
875 gprintf("%o you look alive(%s)", live_reasonb);
876 gprintf("%o\n");
877 }
878
879 /* Stop here if both look certain to live. */
880 if (I_look_alive && you_look_alive) {
881 *resulta = WIN;
882 *resultb = 0;
883 *move = PASS_MOVE;
884 sgf_dumptree = save_sgf_dumptree;
885 count_variations = save_count_variations;
886 TRACE("Both live\n");
887 SGFTRACE_SEMEAI(PASS_MOVE, WIN, 0, "Both live");
888 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
889 move, PASS_MOVE, WIN, 0);
890 }
891
892 /* Next the shape moves. */
893 if (!I_look_alive) {
894 owl_shapes(&shape_defensive_patterns, shape_defensive_moves, color,
895 owla, &owl_defendpat_db);
896 for (k = 0; k < MAX_MOVES-1; k++)
897 if (!get_next_move_from_list(&shape_defensive_patterns, color,
898 shape_defensive_moves, 1, owla))
899 break;
900 }
901 else
902 shape_defensive_moves[0].pos = NO_MOVE;
903
904 if (!you_look_alive) {
905 owl_shapes(&shape_offensive_patterns, shape_offensive_moves, color,
906 owlb, &owl_attackpat_db);
907 for (k = 0; k < MAX_MOVES-1; k++)
908 if (!get_next_move_from_list(&shape_offensive_patterns, color,
909 shape_offensive_moves, 1, owlb))
910 break;
911 }
912 else
913 shape_offensive_moves[0].pos = NO_MOVE;
914
915 /* Filter out moves, which fill our eye (and not split it). */
916 if (eyemax_a > 0) {
917 remove_eye_filling_moves(owla, vital_defensive_moves);
918 remove_eye_filling_moves(owla, vital_offensive_moves);
919 remove_eye_filling_moves(owla, shape_defensive_moves);
920 remove_eye_filling_moves(owla, shape_offensive_moves);
921 }
922
923 /* Now we review the moves already considered, while collecting
924 * them into a single list.
925 */
926
927 if (!I_look_alive) {
928 semeai_review_owl_moves(vital_defensive_moves, owla, owlb, color,
929 &safe_outside_liberty_found,
930 &safe_common_liberty_found,
931 &riskless_move_found,
932 mw, moves, 0, 30,
933 critical_semeai_worms);
934
935 semeai_review_owl_moves(shape_defensive_moves, owla, owlb, color,
936 &safe_outside_liberty_found,
937 &safe_common_liberty_found,
938 &riskless_move_found,
939 mw, moves, 0, 0,
940 critical_semeai_worms);
941 }
942
943 if (!you_look_alive) {
944 semeai_review_owl_moves(vital_offensive_moves, owla, owlb, color,
945 &safe_outside_liberty_found,
946 &safe_common_liberty_found,
947 &riskless_move_found,
948 mw, moves, 1, 30,
949 critical_semeai_worms);
950
951 semeai_review_owl_moves(shape_offensive_moves, owla, owlb, color,
952 &safe_outside_liberty_found,
953 &safe_common_liberty_found,
954 &riskless_move_found,
955 mw, moves, 1, 0,
956 critical_semeai_worms);
957 }
958
959 /* If no moves were found so far, also check the eyespaces when
960 * opponent semeai worms are allowed to be included for vital
961 * moves.
962 */
963 if (moves[0].pos == NO_MOVE || we_might_be_inessential) {
964 include_semeai_worms_in_eyespace = 1;
965 if (!owl_estimate_life(owlb, owla, vital_offensive_moves,
966 &live_reasonb, 1, &dummy_eyes,
967 &eyemin_b, &eyemax_b))
968 semeai_review_owl_moves(vital_offensive_moves, owla, owlb, color,
969 &safe_outside_liberty_found,
970 &safe_common_liberty_found,
971 &riskless_move_found,
972 mw, moves, 1, 30,
973 critical_semeai_worms);
974 include_semeai_worms_in_eyespace = 0;
975 }
976
977 if (eyemin_a == eyemax_a)
978 /* We have stable number of eyes, so we can try to reduce
979 * opponent eyes.
980 */
981 I_have_more_eyes = (eyemin_a > min_eyes(&probable_eyes_b));
982 else {
983 if (min_eyes(&probable_eyes_a) == max_eyes(&probable_eyes_a))
984 /* If we can't increase our number of eyes, we try to reduce
985 * opponent eyes.
986 */
987 I_have_more_eyes = (max_eyes(&probable_eyes_a) > min_eyes(&probable_eyes_b));
988 else
989 /* If we can increase our number of eyes, we do it and let
990 * opponent to increase his.
991 */
992 I_have_more_eyes = (max_eyes(&probable_eyes_a) > max_eyes(&probable_eyes_b));
993 }
994
995 if (get_level() < 8) {
996 /* If no owl moves were found on two consecutive moves,
997 * turn off the owl phase.
998 */
999 if (moves[0].pos == NO_MOVE) {
1000 if (owl_phase == 1)
1001 owl_phase = 2;
1002 else if (owl_phase == 2)
1003 owl_phase = 0;
1004 }
1005 else
1006 owl_phase = 1;
1007 }
1008 }
1009
1010 if (1 && verbose) {
1011 showboard(0);
1012 goaldump(owla->goal);
1013 goaldump(owlb->goal);
1014 }
1015
1016 /* Now we look for a move to fill a liberty. This is only
1017 * interesting if the opponent doesn't already have two eyes.
1018 * If we have more eyes, always check for a backfilling move.
1019 */
1020 if (!you_look_alive
1021 && !safe_outside_liberty_found
1022 && (moves[0].value < 110 || I_have_more_eyes)) {
1023 int pos;
1024 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1025 if (!ON_BOARD(pos))
1026 continue;
1027
1028 if (board[pos] == EMPTY && !mw[pos]) {
1029 if (liberty_of_goal(pos, owlb)) {
1030 if (!liberty_of_goal(pos, owla)) {
1031 /* outside liberty */
1032 if (safe_move(pos, color) == WIN) {
1033 safe_outside_liberty_found = 1;
1034 outside_liberty.pos = pos;
1035 break;
1036 }
1037 else if (backfill_outside_liberty.pos == NO_MOVE)
1038 backfill_outside_liberty.pos = find_semeai_backfilling_move(bpos,
1039 pos);
1040 }
1041 else {
1042 /* common liberty */
1043 if (safe_move(pos, color) == WIN) {
1044 safe_common_liberty_found = 1;
1045 common_liberty.pos = pos;
1046 }
1047 else if (backfill_common_liberty.pos == NO_MOVE)
1048 backfill_common_liberty.pos = find_semeai_backfilling_move(bpos,
1049 pos);
1050 }
1051 }
1052 }
1053 }
1054 }
1055
1056 /* Add the best liberty filling move available. We first want to
1057 * play outer liberties, second backfilling moves required before
1058 * filling an outer liberty. If no such moves are available we try
1059 * to fill a mutual liberty or play a corresponding backfilling
1060 * move.
1061 */
1062 if (!you_look_alive) {
1063 if (safe_outside_liberty_found
1064 && outside_liberty.pos != NO_MOVE) {
1065 move_value = semeai_move_value(outside_liberty.pos,
1066 owla, owlb, 50,
1067 critical_semeai_worms);
1068 owl_add_move(moves, outside_liberty.pos, move_value,
1069 "safe outside liberty", SAME_DRAGON_NOT_CONNECTED,
1070 NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL);
1071 riskless_move_found = 1;
1072 TRACE("Added %1m %d (5)\n", outside_liberty.pos, move_value);
1073 }
1074 else if (backfill_outside_liberty.pos != NO_MOVE) {
1075 move_value = semeai_move_value(backfill_outside_liberty.pos,
1076 owla, owlb, 50,
1077 critical_semeai_worms);
1078 owl_add_move(moves, backfill_outside_liberty.pos, move_value,
1079 "backfilling move", SAME_DRAGON_NOT_CONNECTED, NO_MOVE, 0,
1080 NO_MOVE, MAX_SEMEAI_MOVES, NULL);
1081 riskless_move_found = 1;
1082 TRACE("Added %1m %d (6)\n", backfill_outside_liberty.pos, move_value);
1083 }
1084 else if (safe_common_liberty_found
1085 && common_liberty.pos != NO_MOVE) {
1086 move_value = semeai_move_value(common_liberty.pos,
1087 owla, owlb, 10,
1088 critical_semeai_worms);
1089 owl_add_move(moves, common_liberty.pos, move_value,
1090 "safe common liberty", SAME_DRAGON_MAYBE_CONNECTED,
1091 NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL);
1092 if (semeai_is_riskless_move(common_liberty.pos, owla))
1093 riskless_move_found = 1;
1094 TRACE("Added %1m %d (7)\n", common_liberty.pos, move_value);
1095 }
1096 else if (backfill_common_liberty.pos != NO_MOVE) {
1097 move_value = semeai_move_value(backfill_common_liberty.pos,
1098 owla, owlb, 10,
1099 critical_semeai_worms);
1100 owl_add_move(moves, backfill_common_liberty.pos, move_value,
1101 "backfilling move", SAME_DRAGON_NOT_CONNECTED, NO_MOVE, 0,
1102 NO_MOVE, MAX_SEMEAI_MOVES, NULL);
1103 if (semeai_is_riskless_move(backfill_common_liberty.pos, owla))
1104 riskless_move_found = 1;
1105 TRACE("Added %1m %d (6)\n", backfill_common_liberty.pos, move_value);
1106 }
1107 }
1108
1109 if (moves[0].pos == NO_MOVE) {
1110 /* If no move has been found yet, see if we can fill opponent's
1111 * eye (i.e. put more stones in "bulky five" shape).
1112 */
1113 if (min_eyes(&probable_eyes_b) == 1) {
1114 int move = semeai_propose_eyespace_filling_move(owla, owlb);
1115
1116 if (move) {
1117 owl_add_move(moves, move, 70, "eyespace filling",
1118 SAME_DRAGON_NOT_CONNECTED, NO_MOVE,
1119 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL);
1120 }
1121 }
1122
1123 if (moves[0].pos == NO_MOVE)
1124 TRACE("No move found\n");
1125 }
1126
1127 /* Now we are ready to try moves. Turn on the sgf output ... */
1128 sgf_dumptree = save_sgf_dumptree;
1129 count_variations = save_count_variations;
1130 tested_moves = 0;
1131 for (k = 0; k < MAX_SEMEAI_MOVES; k++) {
1132 int mpos = moves[k].pos;
1133 if (mpos == NO_MOVE)
1134 break;
1135
1136 if (moves[k].value == 0)
1137 continue;
1138
1139 /* Do not try too many moves. */
1140 if (tested_moves > 2
1141 || (stackp > semeai_branch_depth2 && tested_moves > 1)
1142 || (stackp > semeai_branch_depth && tested_moves > 0)) {
1143 /* If allpats, try and pop to get the move in the sgf record. */
1144 if (!allpats)
1145 break;
1146 else if (trymove(mpos, color, moves[k].name, apos)) {
1147 semeai_add_sgf_comment(moves[k].value, owl_phase);
1148 popgo();
1149 }
1150 continue;
1151 }
1152
1153 if (count_variations >= semeai_node_limit
1154 || stackp >= MAX_SEMEAI_DEPTH)
1155 continue;
1156
1157 /* Try playing the move at mpos and call ourselves recursively to
1158 * determine the result obtained by this move.
1159 */
1160 if (semeai_trymove_and_recurse(apos, bpos, owla, owlb,
1161 owl_phase, mpos, color,
1162 best_resulta == 0 || best_resultb == 0,
1163 moves[k].value, moves[k].name,
1164 moves[k].same_dragon, moves[k].pattern_data,
1165 moves[k].lunch, NULL,
1166 &this_resulta, &this_resultb)) {
1167 tested_moves++;
1168 if (this_resultb == WIN && this_resulta == WIN) {
1169 /* Ideal result, no need to try any more moves. */
1170 *resulta = WIN;
1171 *resultb = WIN;
1172 *move = mpos;
1173 TRACE("After %1m I (%C) am alive, you are dead\n", mpos, color);
1174 SGFTRACE_SEMEAI(mpos, WIN, WIN, moves[k].name);
1175 close_pattern_list(color, &shape_defensive_patterns);
1176 close_pattern_list(color, &shape_offensive_patterns);
1177 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1178 move, mpos, WIN, WIN);
1179 }
1180 /* When there is a choice between ko and seki, the prefer_ko
1181 * variable decides policy. Thus if prefer_ko == color we
1182 * consider attacking the opponent more important than defending
1183 * our dragon, and vise versa otherwise.
1184 */
1185 else if ((prefer_ko != color
1186 && (this_resulta > best_resulta
1187 || (this_resulta == best_resulta
1188 && this_resultb > best_resultb)))
1189 || (prefer_ko == color
1190 && (this_resultb > best_resultb
1191 || (this_resultb == best_resultb
1192 && this_resulta > best_resulta)))) {
1193 best_resulta = this_resulta;
1194 best_resultb = this_resultb;
1195 best_move = mpos;
1196 best_move_name = moves[k].name;
1197 }
1198 }
1199 }
1200
1201 close_pattern_list(color, &shape_defensive_patterns);
1202 close_pattern_list(color, &shape_offensive_patterns);
1203
1204 /* If we can't find a move and the opponent looks alive, we have
1205 * lost.
1206 */
1207 if (best_resulta == 0 && best_resultb == 0 && you_look_alive) {
1208 *resulta = 0;
1209 *resultb = 0;
1210 *move = PASS_MOVE;
1211 SGFTRACE_SEMEAI(PASS_MOVE, 0, 0, "You live, I die");
1212 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1213 move, PASS_MOVE, 0, 0);
1214 }
1215
1216 /* If we didn't find a working move and we look dead even if including the
1217 * opponent stones in our eyespace, we have lost.
1218 */
1219 if (best_resulta == 0 && best_resultb == 0
1220 && !riskless_move_found) {
1221 const char *live_reasona;
1222 int eyemin_a;
1223 int eyemax_a;
1224 for (sworm = 0; sworm < s_worms; sworm++) {
1225 if (board[semeai_worms[sworm]] == other) {
1226 if (important_semeai_worms[sworm])
1227 break;
1228 }
1229 }
1230
1231 if (sworm == s_worms) {
1232 include_semeai_worms_in_eyespace = 1;
1233 if (!owl_estimate_life(owla, owlb, vital_defensive_moves,
1234 &live_reasona, 0, &dummy_eyes,
1235 &eyemin_a, &eyemax_a)
1236 && eyemax_a < 2) {
1237 include_semeai_worms_in_eyespace = 0;
1238 *resulta = 0;
1239 *resultb = 0;
1240 *move = PASS_MOVE;
1241 SGFTRACE_SEMEAI(PASS_MOVE, 0, 0, "You live, I die - 2");
1242 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1243 move, PASS_MOVE, 0, 0);
1244 }
1245 include_semeai_worms_in_eyespace = 0;
1246 }
1247 }
1248
1249 /* If we can't find a useful move and opponent passed, it's seki, unless
1250 * one dragon has more eyes than the other.
1251 */
1252 if (best_resulta == 0 && best_resultb == 0
1253 && !riskless_move_found) {
1254 if (pass) {
1255 if (max_eyes(&probable_eyes_a) < min_eyes(&probable_eyes_b)) {
1256 *resulta = 0;
1257 *resultb = 0;
1258 *move = PASS_MOVE;
1259 TRACE("You have more eyes.\n");
1260 SGFTRACE_SEMEAI(PASS_MOVE, 0, 0, "You have more eyes");
1261 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1262 move, PASS_MOVE, 0, 0);
1263 }
1264 else if (max_eyes(&probable_eyes_b) < min_eyes(&probable_eyes_a)) {
1265 *resulta = WIN;
1266 *resultb = WIN;
1267 *move = PASS_MOVE;
1268 TRACE("I have more eyes\n");
1269 SGFTRACE_SEMEAI(PASS_MOVE, WIN, WIN, "I have more eyes");
1270 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1271 move, PASS_MOVE, WIN, WIN);
1272 }
1273 else {
1274 *resulta = WIN;
1275 *resultb = 0;
1276 *move = PASS_MOVE;
1277 TRACE("Seki\n");
1278 SGFTRACE_SEMEAI(PASS_MOVE, WIN, 0, "Seki");
1279 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1280 move, PASS_MOVE, WIN, 0);
1281 }
1282 }
1283 else {
1284 /* No working move was found, but opponent hasn't passed. Then we pass. */
1285 do_owl_analyze_semeai(bpos, apos, owlb, owla,
1286 resultb, resulta, NULL, 1, owl_phase);
1287 *resulta = REVERSE_RESULT(*resulta);
1288 *resultb = REVERSE_RESULT(*resultb);
1289 TRACE("No move found\n");
1290 SGFTRACE_SEMEAI(PASS_MOVE, *resulta, *resultb, "No move found");
1291 *move = PASS_MOVE;
1292 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1293 move, PASS_MOVE, *resulta, *resultb);
1294 }
1295 }
1296
1297 /* There are a few selected cases where we should try to see if it
1298 * would be better to pass rather than playing any move in the semeai.
1299 *
1300 * A first simple example is the case of positions where there is nothing
1301 * left to play but common liberties. In case the above analysis concluded
1302 * the result is seki and if the best (and only) move happens to be a
1303 * common liberty, we attempt to pass, so that the engine considers tenuki
1304 * as a viable option in case it actually is.
1305 *
1306 * Another example is related to "disturbing" kos.
1307 *
1308 * .OOOOOOOO. In this position (similar to semeai:130), X has just taken
1309 * OOXXXXXXOO the ko on the left. The semeai code finds the ko recapture
1310 * OX.XXOOXXO as the only attacking move and concludes the result is KO_B.
1311 * OOXX.OO.XO
1312 * ----------
1313 *
1314 * In such cases too, we try to pass to see if it doesn't actually yield
1315 * a better result.
1316 *
1317 * FIXME: there might be more cases where passing would be valuable.
1318 */
1319 if (!pass && k == 1) {
1320 if ((best_resulta == WIN && best_resultb == 0
1321 && best_move != NO_MOVE
1322 && best_move == common_liberty.pos)
1323 || (best_resulta == KO_B && best_resultb == KO_B
1324 && is_ko(best_move, owla->color, NULL))) {
1325 do_owl_analyze_semeai(bpos, apos, owlb, owla, &this_resultb,
1326 &this_resulta, NULL, 1, owl_phase);
1327 if (REVERSE_RESULT(this_resulta) >= best_resulta
1328 && REVERSE_RESULT(this_resultb) >= best_resultb) {
1329 best_move = PASS_MOVE;
1330 best_resulta = REVERSE_RESULT(this_resulta);
1331 best_resultb = REVERSE_RESULT(this_resultb);
1332 best_move_name = "Pass";
1333 }
1334 }
1335 }
1336
1337 *resulta = best_resulta;
1338 *resultb = best_resultb;
1339 if (best_resulta == 0)
1340 best_move = PASS_MOVE;
1341 *move = best_move;
1342 SGFTRACE_SEMEAI(best_move, best_resulta, best_resultb, best_move_name);
1343 READ_RETURN_SEMEAI(SEMEAI, apos, bpos, depth - stackp,
1344 move, best_move, best_resulta, best_resultb);
1345}
1346
1347/* Play a move, update goal and boundaries appropriately, and call
1348 * do_owl_analyze_semeai() recursively to determine the result of this
1349 * move.
1350 */
1351static int
1352semeai_trymove_and_recurse(int apos, int bpos, struct local_owl_data *owla,
1353 struct local_owl_data *owlb,
1354 int owl_phase,
1355 int move, int color, int ko_allowed,
1356 int move_value, const char *move_name,
1357 enum same_dragon_value same_dragon,
1358 struct matched_pattern_data *pattern_data,
1359 int lunch, int *semeai_move,
1360 int *this_resulta, int *this_resultb)
1361{
1362 int ko_move = 0;
1363
1364 gg_assert(this_resulta != NULL && this_resultb != NULL);
1365 *this_resulta = 0;
1366 *this_resultb = 0;
1367
1368 if (!komaster_trymove(move, color, move_name, apos, &ko_move, ko_allowed)) {
1369 int kpos;
1370 if (is_ko(move, color, &kpos)) {
1371 /* Move was not allowed because of komaster. We want to check
1372 * if this situation is double ko and when it is, we won semeai.
1373 */
1374 int libs[MAX_LIBERTIES];
1375 int n;
1376 int nlib;
1377 int sworm;
1378 int worm_color;
1379 int other = OTHER_COLOR(color);
1380
1381 for (sworm = 0; sworm < s_worms; sworm++) {
1382 worm_color = board[semeai_worms[sworm]];
1383 if (worm_color == color) {
1384 /* We only check up to MAX_LIBERTIES, due to performance
1385 * reasons. When we have more liberties we have some outside
1386 * liberties to fill and these moves will be tried later
1387 * (and double ko situation will be found).
1388 */
1389 nlib = findlib(semeai_worms[sworm], MAX_LIBERTIES, libs);
1390 if (nlib > MAX_LIBERTIES)
1391 return 0;
1392
1393 for (n = 0; n < nlib; n++)
1394 if (is_ko(libs[n], other, NULL)) {
1395 /* Check if situation is not a nested ko capture. */
1396 if (DIAGONAL_NEIGHBORS(libs[n], kpos))
1397 return 0;
1398
1399 /* Our dragon has double ko, but we have to check if
1400 * opponent dragon doesn't have outside liberties or
1401 * double ko.
1402 */
1403 *this_resulta = WIN;
1404 *this_resultb = WIN;
1405 }
1406 }
1407 else if (worm_color == other) {
1408 if (countlib(semeai_worms[sworm]) > 2)
1409 /* In double ko situation the opponent can have only a
1410 * single eye and a ko outside liberty to be sure that we
1411 * will always win double ko.
1412 */
1413 return 0;
1414 }
1415 }
1416 if (*this_resulta == WIN)
1417 return 1;
1418 }
1419
1420 return 0;
1421 }
1422
1423 semeai_add_sgf_comment(move_value, owl_phase);
1424 TRACE("Trying %C %1m. Current stack: ", color, move);
1425 if (verbose) {
1426 dump_stack();
1427 goaldump(owla->goal);
1428 gprintf("\n");
1429 goaldump(owlb->goal);
1430 gprintf("\n");
1431 }
1432 TRACE("%s, value %d, same_dragon %d\n", move_name, move_value, same_dragon);
1433
1434 push_owl(&owla);
1435 push_owl(&owlb);
1436
1437 if (owla->color == color) {
1438 owl_update_goal(move, same_dragon, lunch, owla, 1, pattern_data);
1439 owl_update_boundary_marks(move, owlb);
1440 }
1441 else {
1442 owl_update_goal(move, same_dragon, lunch, owlb, 1, pattern_data);
1443 owl_update_boundary_marks(move, owla);
1444 }
1445 mark_goal_in_sgf(owla->goal);
1446 mark_goal_in_sgf(owlb->goal);
1447
1448 /* Do a recursive call to read the semeai after the move we just
1449 * tried. If dragon b was captured by the move, call
1450 * do_owl_attack() to see whether it sufficed for us to live.
1451 */
1452 if (board[bpos] == EMPTY) {
1453 /* FIXME: Are all owl_data fields and relevant static
1454 * variables properly set up for a call to do_owl_attack()?
1455 */
1456 *this_resulta = REVERSE_RESULT(do_owl_attack(apos, semeai_move, NULL, owla, 0));
1457 *this_resultb = *this_resulta;
1458 }
1459 else {
1460 do_owl_analyze_semeai(bpos, apos, owlb, owla,
1461 this_resultb, this_resulta, semeai_move,
1462 0, owl_phase);
1463 *this_resulta = REVERSE_RESULT(*this_resulta);
1464 *this_resultb = REVERSE_RESULT(*this_resultb);
1465 }
1466
1467 pop_owl(&owlb);
1468 pop_owl(&owla);
1469
1470 popgo();
1471
1472 /* Does success require ko? */
1473 if (ko_move) {
1474 if (*this_resulta != 0)
1475 *this_resulta = KO_B;
1476 if (*this_resultb != 0)
1477 *this_resultb = KO_B;
1478 }
1479
1480 if (count_variations >= semeai_node_limit) {
1481 TRACE("Out of nodes, claiming win.\n");
1482 result_certain = 0;
1483 *this_resulta = WIN;
1484 *this_resultb = WIN;
1485 }
1486 return 1;
1487}
1488
1489/* Add details in sgf file about move value and whether owl_phase is active. */
1490static void
1491semeai_add_sgf_comment(int value, int owl_phase)
1492{
1493 char buf[100];
1494
1495 if (!sgf_dumptree)
1496 return;
1497
1498 if (owl_phase)
1499 gg_snprintf(buf, 100, "value %d, owl_phase", value);
1500 else
1501 gg_snprintf(buf, 100, "value %d", value);
1502 sgftreeAddComment(sgf_dumptree, buf);
1503}
1504
1505
1506/* In semeai situations tactical attacks often cannot be trusted. This
1507 * in particular holds for strings with three or more liberties. Two
1508 * liberties can usually be trusted, but if neither liberty can be
1509 * played immediately, the need for backfilling moves gives an
1510 * effective liberty count of more than two, again making the attack
1511 * untrustworthy.
1512 *
1513 * This function decides whether an attack should be trusted. It does
1514 * not check whether there actually is an attack, though.
1515 */
1516static int
1517semeai_trust_tactical_attack(int str)
1518{
1519 int liberties;
1520 int libs[3];
1521 int other = OTHER_COLOR(board[str]);
1522
1523 liberties = findlib(str, 3, libs);
1524 if (liberties > 2)
1525 return 0;
1526
1527 if (liberties < 2)
1528 return 1;
1529
1530 if (!is_self_atari(libs[0], other)
1531 || !is_self_atari(libs[1], other))
1532 return 1;
1533
1534 return 0;
1535}
1536
1537
1538/* A move is deemed riskless (i.e., doesn't kill ourself in a seki situation)
1539 * if it doesn't decrease the liberty count of any goal string of our
1540 * dragon.
1541 */
1542static int
1543semeai_is_riskless_move(int move, struct local_owl_data *owla)
1544{
1545 int k;
1546 int liberties = accuratelib(move, owla->color, MAXLIBS, NULL);
1547 if (!liberty_of_goal(move, owla))
1548 return 1;
1549 for (k = 0; k < 4; k++) {
1550 int pos = move + delta[k];
1551 if (board[pos] == owla->color
1552 && owla->goal[pos]
1553 && countlib(pos) > liberties)
1554 return 0;
1555 }
1556 return 1;
1557}
1558
1559
1560/* Review the moves in owl_moves[] and add them into semeai_moves[].
1561 * This is used to merge multiple sets of owl moves into one move
1562 * list, while revising the values for use in semeai reading.
1563 *
1564 * We also record whether the moves include an outer or common liberty
1565 * in the semeai.
1566 */
1567static void
1568semeai_review_owl_moves(struct owl_move_data owl_moves[MAX_MOVES],
1569 struct local_owl_data *owla,
1570 struct local_owl_data *owlb, int color,
1571 int *safe_outside_liberty_found,
1572 int *safe_common_liberty_found,
1573 int *riskless_move_found,
1574 signed char mw[BOARDMAX],
1575 struct owl_move_data semeai_moves[MAX_SEMEAI_MOVES],
1576 int guess_same_dragon, int value_bonus,
1577 int *critical_semeai_worms)
1578{
1579 int move;
1580 int move_value;
1581 enum same_dragon_value same_dragon;
1582 struct matched_pattern_data *pattern_data = NULL;
1583 int k;
1584
1585 for (k = 0; k < MAX_MOVES-1; k++) {
1586 move = owl_moves[k].pos;
1587 if (move == NO_MOVE)
1588 break;
1589
1590 if (owl_moves[k].value == 0)
1591 continue;
1592
1593 /* Does the move fill a liberty in the semeai? */
1594 if (liberty_of_goal(move, owlb)
1595 && safe_move(move, color)) {
1596 if (!liberty_of_goal(move, owla))
1597 *safe_outside_liberty_found = 1;
1598 else
1599 *safe_common_liberty_found = 1;
1600 }
1601 if (is_legal(move, color) && !is_ko(move, color, NULL)
1602 && semeai_is_riskless_move(move, owla))
1603 *riskless_move_found = 1;
1604
1605 /* For some types of owl moves we don't have same_dragon
1606 * information recorded and need to guess.
1607 */
1608 if (guess_same_dragon) {
1609 if (liberty_of_goal(move, owla)
1610 || second_liberty_of_goal(move, owla))
1611 same_dragon = SAME_DRAGON_MAYBE_CONNECTED;
1612 else
1613 same_dragon = SAME_DRAGON_NOT_CONNECTED;
1614 }
1615 else {
1616 same_dragon = owl_moves[k].same_dragon;
1617 pattern_data = owl_moves[k].pattern_data;
1618 }
1619
1620 mw[move] = 1;
1621 move_value = (semeai_move_value(move, owla, owlb, owl_moves[k].value,
1622 critical_semeai_worms)
1623 + value_bonus);
1624 owl_add_move(semeai_moves, move, move_value, owl_moves[k].name,
1625 same_dragon, NO_MOVE, owl_moves[k].escape,
1626 NO_MOVE, MAX_SEMEAI_MOVES, pattern_data);
1627 TRACE("Added %1m %d\n", move, move_value);
1628 }
1629}
1630
1631
1632/* Propose an eyespace filling move. Such a move can, for instance,
1633 * add a stone to opponent's "bulky five" shape. We of course choose
1634 * a move that doesn't allow opponent to turn his dead eyeshape into a
1635 * two eyes eyeshape. E.g. in this position, the function will
1636 * propose the move at '*', not at the '.':
1637 *
1638 * XXX
1639 * XXOX
1640 * XOOX
1641 * X.*X
1642 * ----
1643 */
1644static int
1645semeai_propose_eyespace_filling_move(struct local_owl_data *owla,
1646 struct local_owl_data *owlb)
1647{
1648 int color = OTHER_COLOR(owlb->color);
1649 int pos;
1650 int mw[BOARDMAX];
1651 int mz[BOARDMAX];
1652
1653 owl_find_relevant_eyespaces(owlb, mw, mz);
1654
1655 /* Never try to fill opponent's eyes which contain our dragon. This
1656 * is nothing else than suicide.
1657 */
1658 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1659 if (ON_BOARD(pos) && owla->goal[pos])
1660 mw[owlb->my_eye[pos].origin] = 0;
1661 }
1662
1663 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1664 if (board[pos] == EMPTY) {
1665 int origin = owlb->my_eye[pos].origin;
1666
1667 if (mw[origin] > 1
1668 && min_eyes(&owlb->my_eye[origin].value) == 1) {
1669 int good_move = 0;
1670
1671 if (trymove(pos, color, "eyespace_filling", NO_MOVE)) {
1672 struct eyevalue new_value;
1673 int dummy_attack;
1674 int dummy_defense;
1675
1676 compute_eyes(origin, &new_value, &dummy_attack, &dummy_defense,
1677 owlb->my_eye, owlb->half_eye, 0);
1678 if (max_eyes(&new_value) <= 1)
1679 good_move = 1;
1680
1681 popgo();
1682 }
1683
1684 if (good_move)
1685 return pos;
1686 }
1687 }
1688 }
1689
1690 return NO_MOVE;
1691}
1692
1693
1694/* Try to estimate the value of a semeai move. This has two
1695 * components. The first is the change in the total number of
1696 * liberties for strings involved in the semeai. The second is a bonus
1697 * for attacks and defenses of critical semeai worms.
1698 */
1699
1700static int
1701semeai_move_value(int move, struct local_owl_data *owla,
1702 struct local_owl_data *owlb,
1703 int raw_value, int *critical_semeai_worms)
1704{
1705 int pos;
1706 int net = 0;
1707 int color = owla->color;
1708 int save_verbose = verbose;
1709 int k;
1710 int bonus = 0;
1711
1712 ASSERT1(board[move] == EMPTY, move);
1713 verbose = 0;
1714 if (safe_move(move, color)) {
1715 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1716 if (IS_STONE(board[pos])
1717 && pos == find_origin(pos)) {
1718 int count_lib = -1;
1719 if (owla->goal[pos]) {
1720 count_lib = countlib(pos);
1721 net -= 75 * count_lib;
1722 }
1723 if (owlb->goal[pos]) {
1724 if (count_lib < 0)
1725 count_lib = countlib(pos);
1726 net += 100 * count_lib;
1727 }
1728 }
1729 }
1730 if (!trymove(move, color, NULL, 0)) {
1731 verbose = save_verbose;
1732 return 0;
1733 }
1734 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1735 if (IS_STONE(board[pos])
1736 && pos == find_origin(pos)) {
1737 int count_lib = -1;
1738 if (owla->goal[pos]
1739 || (pos == move && liberty_of_goal(move, owla))) {
1740 count_lib = countlib(pos);
1741 net += 75 * count_lib;
1742 }
1743 if (owlb->goal[pos]) {
1744 if (count_lib < 0)
1745 count_lib = countlib(pos);
1746 net -= 100 * count_lib;
1747 }
1748 }
1749 }
1750
1751 increase_depth_values();
1752 for (k = 0; k < s_worms; k++) {
1753 if (!critical_semeai_worms[k])
1754 continue;
1755 if (board[semeai_worms[k]] == color
1756 && !attack(semeai_worms[k], NULL))
1757 bonus += 50;
1758 else if (board[semeai_worms[k]] == OTHER_COLOR(color)
1759 && !find_defense(semeai_worms[k], NULL))
1760 bonus += 50;
1761 }
1762 decrease_depth_values();
1763
1764 popgo();
1765 }
1766
1767 verbose = save_verbose;
1768
1769 if (net < 0)
1770 net = 0;
1771
1772 net /= 25;
1773 net *= 3;
1774
1775 return raw_value + net + bonus;
1776}
1777
1778
1779/* Remove all moves from the list that would fill our own eye. */
1780static void
1781remove_eye_filling_moves(struct local_owl_data *our_owl,
1782 struct owl_move_data *moves)
1783{
1784 int k;
1785 int color = our_owl->color;
1786
1787 for (k = 0; k < MAX_MOVES; k++) {
1788 if (moves[k].pos == NO_MOVE)
1789 break;
1790 else {
1791 struct eye_data *eye = &our_owl->my_eye[moves[k].pos];
1792
1793 /* If esize==1 this eye must not be a real eye (at least one
1794 * worm is capturable, otherwise this move would not be
1795 * proposed).
1796 */
1797 if (eye->color == color && eye->msize == 0 && eye->neighbors <= 1
1798 && eye->esize != 1
1799 && our_owl->half_eye[moves[k].pos].type != HALF_EYE
1800 && !has_neighbor(moves[k].pos, OTHER_COLOR(color)))
1801 moves[k].value = 0;
1802 }
1803 }
1804}
1805
1806/* Is the vertex at pos adjacent to an element of the owl goal? */
1807static int
1808liberty_of_goal(int pos, struct local_owl_data *owl)
1809{
1810 int k;
1811 for (k = 0; k < 4; k++)
1812 if (IS_STONE(board[pos + delta[k]]) && owl->goal[pos + delta[k]])
1813 return 1;
1814
1815 return 0;
1816}
1817
1818/* Is the vertex at pos a second liberty of the owl goal? */
1819static int
1820second_liberty_of_goal(int pos, struct local_owl_data *owl)
1821{
1822 int k;
1823 for (k = 0; k < 4; k++)
1824 if (board[pos + delta[k]] == EMPTY && liberty_of_goal(pos + delta[k], owl))
1825 return 1;
1826
1827 return 0;
1828}
1829
1830
1831/* 'liberty' is a liberty of 'worm' which we would like to fill.
1832 * However it is not safe to play there, so we look for a
1833 * backfilling move. For example in this situation:
1834 *
1835 * ------+
1836 * O.OaXc|
1837 * OOOOOX|
1838 * XXXXXb|
1839 * ......|
1840 *
1841 * If 'worm' is the O string and 'liberty' is 'a', the
1842 * function returns 'b'. To fill at 'a', X must first
1843 * fill 'b' and 'c' and it is better to fill at 'b' first
1844 * since that will sometimes leave fewer or smaller ko threats.
1845 *
1846 * Returns NO_MOVE if no move is found.
1847 */
1848
1849static int
1850find_semeai_backfilling_move(int worm, int liberty)
1851{
1852 int color = board[worm];
1853 int other = OTHER_COLOR(color);
1854 int result = NO_MOVE;
1855
1856 if (safe_move(liberty, other) == WIN)
1857 return liberty;
1858 if (is_self_atari(liberty, other)) {
1859 int fill;
1860 if (approxlib(liberty, other, 1, &fill) > 0
1861 && trymove(fill, other, "find_semeai_backfilling_move", worm)) {
1862 if (safe_move(liberty, other))
1863 result = fill;
1864 else if (board[worm] != EMPTY)
1865 result = find_semeai_backfilling_move(worm, liberty);
1866 popgo();
1867 }
1868 }
1869 if (ON_BOARD(result) && safe_move(result, other))
1870 return result;
1871 else
1872 return NO_MOVE;
1873}
1874
1875/* Some helper function for do_owl_attack/defend. */
1876
1877static int
1878reading_limit_reached(const char **live_reason, int this_variation_number)
1879{
1880 /* If (stackp > owl_reading_depth), interpret deep reading
1881 * conservatively as escape.
1882 */
1883 if (stackp > owl_reading_depth) {
1884 TRACE("%oVariation %d: ALIVE (maximum reading depth reached)\n",
1885 this_variation_number);
1886 *live_reason = "max reading depth reached";
1887 return 1;
1888 }
1889 /* If the owl node limit has been reached, assume the dragon has
1890 * managed to escape.
1891 */
1892 if (local_owl_node_counter >= owl_node_limit) {
1893 result_certain = 0;
1894 TRACE("%oVariation %d: ALIVE (owl node limit reached)\n",
1895 this_variation_number);
1896 *live_reason = "owl node limit reached";
1897 return 1;
1898 }
1899 return 0;
1900}
1901
1902static void
1903clear_owl_move_data(struct owl_move_data moves[MAX_MOVES])
1904{
1905 int k;
1906 for (k = 0; k < MAX_MOVES; k++) {
1907 moves[k].pos = NO_MOVE;
1908 moves[k].value = -1;
1909 moves[k].name = NULL;
1910 moves[k].same_dragon = SAME_DRAGON_CONNECTED;
1911 moves[k].escape = 0;
1912 moves[k].lunch = NO_MOVE;
1913 moves[k].pattern_data = NULL;
1914 clear_cut_list(moves[k].cuts);
1915 }
1916}
1917
1918static void
1919set_single_owl_move(struct owl_move_data moves[MAX_MOVES],
1920 int pos, const char *name)
1921{
1922 moves[0].pos = pos;
1923 moves[0].value = 25;
1924 moves[0].name = name;
1925 moves[0].same_dragon = SAME_DRAGON_MAYBE_CONNECTED;
1926 moves[0].escape = 0;
1927 moves[0].lunch = NO_MOVE;
1928 moves[0].pattern_data = NULL;
1929 clear_cut_list(moves[0].cuts);
1930 moves[1].value = 0;
1931}
1932
1933
1934/* Returns true if a move can be found to attack the dragon
1935 * at (target), in which case (*attack_point) is the recommended move.
1936 * (attack_point) can be a null pointer if only the result is needed.
1937 *
1938 * The array goal marks the extent of the dragon. This must
1939 * be maintained during reading. Call this function only when
1940 * stackp==0; otherwise you can call do_owl_attack but you must
1941 * set up the goal and boundary arrays by hand first.
1942 *
1943 * Returns KO_A or KO_B if the position is ko:
1944 *
1945 * - Returns KO_A if the attack prevails provided attacker is willing to
1946 * ignore any ko threat (the attacker makes the first ko capture).
1947 *
1948 * - Returns KO_B if attack succeeds provided attacker has a ko threat
1949 * which must be answered (the defender makes the first ko capture).
1950 *
1951 * If GNU Go is compiled with `configure --enable-experimental-owl-ext'
1952 * then a return codes of GAIN is also possible.
1953 *
1954 * - Returns GAIN if the attack fails but another worm of the
1955 * opponent's is captured in during the failed attack. The location
1956 * of the killed worm is returned through the *kworm field.
1957 *
1958 * */
1959
1960int
1961owl_attack(int target, int *attack_point, int *certain, int *kworm)
1962{
1963 int result;
1964 struct local_owl_data *owl;
1965 int reading_nodes_when_called = get_reading_node_counter();
1966 double start = 0.0;
1967 int tactical_nodes;
1968 int move = NO_MOVE;
1969 int wpos = NO_MOVE;
1970 int wid = MAX_GOAL_WORMS;
1971
1972 result_certain = 1;
1973 if (worm[target].unconditional_status == DEAD) {
1974 if (attack_point)
1975 *attack_point = NO_MOVE;
1976 if (kworm)
1977 *kworm = NO_MOVE;
1978 if (certain)
1979 *certain = 1;
1980 return 1;
1981 }
1982
1983 if (search_persistent_owl_cache(OWL_ATTACK, target, 0, 0, &result,
1984 attack_point, kworm, certain))
1985 return result;
1986
1987 if (debug & DEBUG_OWL_PERFORMANCE)
1988 start = gg_cputime();
1989
1990 TRACE("owl_attack %1m\n", target);
1991 init_owl(&owl, target, NO_MOVE, NO_MOVE, 1, NULL);
1992 owl_make_domains(owl, NULL);
1993 prepare_goal_list(target, owl, owl_goal_worm, &goal_worms_computed,
1994 kworm, 1);
1995 result = do_owl_attack(target, &move, &wid, owl, 0);
1996 finish_goal_list(&goal_worms_computed, &wpos, owl_goal_worm, wid);
1997 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
1998
1999 DEBUG(DEBUG_OWL_PERFORMANCE,
2000 "owl_attack %1m, result %d %1m (%d, %d nodes, %f seconds)\n",
2001 target, result, move, local_owl_node_counter,
2002 tactical_nodes, gg_cputime() - start);
2003
2004 store_persistent_owl_cache(OWL_ATTACK, target, 0, 0,
2005 result, move, wpos,
2006 result_certain, tactical_nodes,
2007 owl->goal, board[target]);
2008 if (attack_point)
2009 *attack_point = move;
2010 if (kworm)
2011 *kworm = wpos;
2012 if (certain)
2013 *certain = result_certain;
2014
2015 return result;
2016}
2017
2018
2019/* Static function containing the main recursive code for
2020 * owl_attack.
2021 */
2022
2023static int
2024do_owl_attack(int str, int *move, int *wormid,
2025 struct local_owl_data *owl, int escape)
2026{
2027 int color = board[str];
2028 int other = OTHER_COLOR(color);
2029 struct owl_move_data vital_moves[MAX_MOVES];
2030 struct owl_move_data shape_moves[MAX_MOVES];
2031 struct owl_move_data *moves;
2032 struct matched_patterns_list_data shape_patterns;
2033 signed char mw[BOARDMAX];
2034 int number_tried_moves = 0;
2035 int pass;
2036 int k;
2037 int savemove = 0;
2038 int saveworm = MAX_GOAL_WORMS;
2039 int savecode = 0;
2040 int eyemin = -1; /* Lower bound on the number of eyes. */
2041 int eyemax = -1; /* Upper bound on the number of eyes. */
2042 struct eyevalue probable_eyes; /* Best guess of eyevalue. */
2043 const char *live_reason;
2044 int move_cutoff;
2045 int xpos;
2046 int value1;
2047 int value2;
2048 int this_variation_number = count_variations - 1;
2049
2050 SETUP_TRACE_INFO("owl_attack", str);
2051
2052 shape_patterns.initialized = 0;
2053
2054 str = find_origin(str);
2055
2056 if (tt_get(&ttable, OWL_ATTACK, str, NO_MOVE, depth - stackp, NULL,
2057 &value1, &value2, &xpos) == 2) {
2058
2059 TRACE_CACHED_RESULT(value1, xpos);
2060 if (move)
2061 *move = xpos;
2062
2063 if (value1 == GAIN) {
2064 if (wormid) {
2065 if (goal_worms_computed)
2066 *wormid = value2;
2067 else
2068 *wormid = MAX_GOAL_WORMS;
2069 }
2070 }
2071
2072 if (value1 == WIN)
2073 TRACE("%oVariation %d: DEAD (cached)\n", this_variation_number);
2074 else
2075 TRACE("%oVariation %d: ALIVE (cached)\n", this_variation_number);
2076
2077 SGFTRACE(xpos, value1, "cached");
2078
2079 return value1;
2080 }
2081
2082
2083 /* If reading goes to deep or we run out of nodes, we assume life. */
2084 if (reading_limit_reached(&live_reason, this_variation_number)) {
2085 SGFTRACE(0, 0, live_reason);
2086 READ_RETURN(OWL_ATTACK, str, depth - stackp, move, 0, 0);
2087 }
2088
2089 memset(mw, 0, sizeof(mw));
2090 global_owl_node_counter++;
2091 local_owl_node_counter++;
2092
2093 current_owl_data = owl;
2094 memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache));
2095
2096 /* First see whether there is any chance to kill. */
2097 if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 1,
2098 &probable_eyes, &eyemin, &eyemax)) {
2099 /*
2100 * We need to check here if there's a worm under atari. If yes,
2101 * locate it and report a (gote) GAIN.
2102 */
2103 int acode = 0;
2104 int mpos = NO_MOVE;
2105 if (experimental_owl_ext && goal_worms_computed) {
2106 int size = 0;
2107 saveworm = MAX_GOAL_WORMS;
2108 for (k = 0; k < MAX_GOAL_WORMS; k++) {
2109 if (owl_goal_worm[k] == NO_MOVE)
2110 break;
2111 if (board[owl_goal_worm[k]] == EMPTY
2112 || countlib(owl_goal_worm[k]) > 1)
2113 continue;
2114 if (worm[owl_goal_worm[k]].size > size) {
2115 saveworm = k;
2116 size = worm[owl_goal_worm[k]].size;
2117 }
2118 }
2119 if (saveworm != MAX_GOAL_WORMS && size >= 3) {
2120 acode = GAIN;
2121 findlib(worm[owl_goal_worm[saveworm]].origin, 1, &mpos);
2122 /* ASSERT1( ... */
2123 }
2124 }
2125 SGFTRACE(0, acode, live_reason);
2126 TRACE("%oVariation %d: ALIVE (%s)\n", this_variation_number, live_reason);
2127 if (acode == 0) {
2128 READ_RETURN(OWL_ATTACK, str, depth - stackp, move, 0, 0);
2129 }
2130 else {
2131 if (wormid)
2132 *wormid = saveworm;
2133 READ_RETURN2(OWL_ATTACK, str, depth - stackp,
2134 move, mpos, acode, saveworm);
2135 }
2136 }
2137
2138 /* We try moves in five passes.
2139 * stackp==0 stackp>0
2140 * 0. Vital moves in the interval [70..] [45..]
2141 * 1. Shape moves
2142 * 2. Vital moves in the interval [..69] [..44]
2143 * 3. Tactical attack moves (except certain kos)
2144 * 4. Moves found by the defender
2145 * 5. Tactical ko attack moves which were not tried in pass 3
2146 */
2147 for (pass = 0; pass < 6; pass++) {
2148 moves = NULL;
2149 move_cutoff = 1;
2150
2151 current_owl_data = owl;
2152 /* Get the shape moves if we are in the right pass. */
2153 switch (pass) {
2154 case 1:
2155 if (stackp > owl_branch_depth && number_tried_moves > 0)
2156 continue;
2157
2158 owl_shapes(&shape_patterns, shape_moves, other, owl, &owl_attackpat_db);
2159 moves = shape_moves;
2160 break;
2161
2162 case 0:
2163 case 2:
2164 if (stackp > owl_branch_depth && number_tried_moves > 0)
2165 continue;
2166
2167 moves = vital_moves;
2168 if (pass == 0 || stackp > owl_distrust_depth) {
2169 if (stackp == 0)
2170 move_cutoff = 70;
2171 else
2172 move_cutoff = 45;
2173 }
2174 if (eyemax < 2 && stackp > 2)
2175 move_cutoff = 99; /* Effectively disable vital moves. */
2176 break;
2177
2178 case 3:
2179 case 5:
2180 {
2181 /* Look for a tactical attack. This is primarily intended for
2182 * the case where the whole dragon is a single string, therefore
2183 * we only look at the string at the "origin".
2184 *
2185 * We must be wary with attacks giving ko. Unless the dragon
2186 * otherwise looks alive, this may turn a dead dragon into one
2187 * which can live by ko. Such moves will be tried anyway in
2188 * pass 5. Notice though that we can only reach there if an owl
2189 * defense was found in pass 4.
2190 */
2191 int apos;
2192 int result;
2193 SGFTree *save_sgf_dumptree = sgf_dumptree;
2194 int save_count_variations = count_variations;
2195
2196 sgf_dumptree = NULL;
2197 count_variations = 0;
2198 result = attack(str, &apos);
2199 if (result == WIN
2200 || (result != 0 && (min_eyes(&probable_eyes) >= 2
2201 || pass == 5))) {
2202 set_single_owl_move(shape_moves, apos, "tactical attack");
2203 moves = shape_moves;
2204 }
2205 sgf_dumptree = save_sgf_dumptree;
2206 count_variations = save_count_variations;
2207 }
2208 break;
2209
2210 /* If we found no move in the first four passes we ask the defender
2211 * for a move suggestion.
2212 */
2213 case 4:
2214 if (number_tried_moves == 0) {
2215 int dpos;
2216 int dcode = do_owl_defend(str, &dpos, NULL, owl, escape);
2217 /* No defense, we won. */
2218 if (dcode == 0) {
2219 TRACE("%oVariation %d: DEAD (no defense)\n",
2220 this_variation_number);
2221 SGFTRACE(0, WIN, "no defense");
2222 close_pattern_list(other, &shape_patterns);
2223 READ_RETURN(OWL_ATTACK, str, depth - stackp, move, 0, WIN);
2224 }
2225 else if (dpos != NO_MOVE) {
2226 /* The dragon could be defended by one more move. Try to
2227 * attack with this move.
2228 *
2229 * If the move is suicide for us, try to find a backfilling
2230 * move to play instead. Do this also if the move is a
2231 * send-two-return-one sacrifice.
2232 */
2233 const char *name = "defense move";
2234 SGFTree *save_sgf_dumptree = sgf_dumptree;
2235 int save_count_variations = count_variations;
2236
2237 sgf_dumptree = NULL;
2238 count_variations = 0;
2239
2240 if (is_suicide(dpos, other) || send_two_return_one(dpos, other)) {
2241 int dpos2;
2242 for (k = 0; k < 4; k++) {
2243 if (board[dpos + delta[k]] == other
2244 && find_defense(dpos + delta[k], &dpos2)) {
2245 dpos = dpos2;
2246 name = "defense move (backfill)";
2247 break;
2248 }
2249 }
2250 }
2251
2252 sgf_dumptree = save_sgf_dumptree;
2253 count_variations = save_count_variations;
2254
2255 if (dpos != NO_MOVE) {
2256 set_single_owl_move(shape_moves, dpos, name);
2257 moves = shape_moves;
2258 }
2259 }
2260 }
2261 break;
2262 } /* switch (pass) */
2263
2264
2265 /* FIXME: This block probably should reappear somewhere in this
2266 * function.
2267 */
2268#if 0
2269 /* First test whether the dragon has escaped. */
2270 if (owl_escape_route(owl) >= 5) {
2271 /* FIXME: We probably should make distinction in the returned
2272 * result whether the dragon lives by making two eyes or by
2273 * escaping.
2274 */
2275 TRACE("%oVariation %d: ALIVE (escaped)\n", this_variation_number);
2276 SGFTRACE(0, 0, "escaped");
2277 close_pattern_list(other, &shape_patterns);
2278 READ_RETURN0(OWL_ATTACK, str, depth - stackp);
2279 }
2280#endif
2281
2282 if (!moves)
2283 continue;
2284
2285 /* For the up to MAX_MOVES best moves with value equal to
2286 * move_cutoff or higher, try to attack the dragon and see if it
2287 * can then be defended.
2288 */
2289 for (k = 0; k < MAX_MOVES; k++) {
2290 int mpos;
2291 int ko_move = -1;
2292 int origin = NO_MOVE;
2293 int captured;
2294 int wid = MAX_GOAL_WORMS;
2295 int dcode;
2296
2297 /* Consider only the highest scoring move if we're deeper than
2298 * owl_branch_depth.
2299 *
2300 * FIXME: To behave as intended, k should be replaced by
2301 * number_tried_moves.
2302 */
2303 if (stackp > owl_branch_depth && k > 0)
2304 break;
2305
2306 current_owl_data = owl;
2307
2308 /* Shape moves are selected on demand. */
2309 if (pass == 1) {
2310 if (!get_next_move_from_list(&shape_patterns, other,
2311 shape_moves, move_cutoff, owl))
2312 break;
2313 }
2314 else
2315 if (moves[k].value < move_cutoff)
2316 break;
2317
2318 mpos = moves[k].pos;
2319 ASSERT_ON_BOARD1(mpos);
2320
2321 /* Have we already tested this move? */
2322 if (mw[mpos])
2323 continue;
2324
2325 captured = (color == WHITE ? white_captured : black_captured);
2326
2327 /* Try to make the move. */
2328 if (!komaster_trymove(mpos, other, moves[k].name, str,
2329 &ko_move, savecode == 0))
2330 continue;
2331
2332 captured = (color == WHITE ? white_captured : black_captured) - captured;
2333
2334 TRACE("Trying %C %1m. Escape = %d. Current stack: ",
2335 other, mpos, escape);
2336 if (verbose)
2337 dump_stack();
2338
2339 /* We have now made a move. Analyze the new position. */
2340 push_owl(&owl);
2341 mw[mpos] = 1;
2342 number_tried_moves++;
2343 owl_update_boundary_marks(mpos, owl);
2344
2345 /* If the origin of the dragon has been captured, we look
2346 * for another string which was part of the original dragon,
2347 * marked when stackp==0, which has not been captured. If no
2348 * such string is found, owl_attack declares victory.
2349 */
2350 if (IS_STONE(board[str]))
2351 origin = str;
2352 else
2353 origin = select_new_goal_origin(NO_MOVE, owl);
2354
2355 /* Test whether the move cut the goal dragon apart. */
2356 if (moves[k].cuts[0] != NO_MOVE && origin != NO_MOVE) {
2357 owl_test_cuts(owl->goal, owl->color, moves[k].cuts);
2358 if (!owl->goal[origin])
2359 origin = select_new_goal_origin(origin, owl);
2360 }
2361 mark_goal_in_sgf(owl->goal);
2362
2363 if (origin == NO_MOVE)
2364 dcode = 0;
2365 else
2366 dcode = do_owl_defend(origin, NULL, &wid, owl, escape);
2367
2368 if (!ko_move) {
2369 if (dcode == 0) {
2370 pop_owl(&owl);
2371 popgo();
2372 if (sgf_dumptree) {
2373 const char *wintxt;
2374 char winstr[192];
2375 if (origin == NO_MOVE)
2376 wintxt = "all original stones captured";
2377 else
2378 wintxt = "attack effective";
2379 sprintf(winstr, "%s)\n (%d variations", wintxt,
2380 count_variations - this_variation_number);
2381 SGFTRACE(mpos, WIN, winstr);
2382 }
2383 close_pattern_list(other, &shape_patterns);
2384 READ_RETURN(OWL_ATTACK, str, depth - stackp, move, mpos, WIN);
2385 }
2386 else if (experimental_owl_ext && dcode == LOSS) {
2387 if (saveworm == MAX_GOAL_WORMS
2388 || worm[owl_goal_worm[wid]].size
2389 > worm[owl_goal_worm[saveworm]].size)
2390 saveworm = wid;
2391 }
2392 /* The conditions here are set so that this code doesn't get
2393 * triggered when the capture is immediate (the tactical
2394 * reading code should take care of these).
2395 */
2396 else if (experimental_owl_ext && goal_worms_computed
2397#if 0
2398 && stackp > 1
2399#endif
2400 && captured >= 3) {
2401 int w = MAX_GOAL_WORMS;
2402 int size = 0;
2403 int l;
2404 /* locate the biggest captured worm */
2405 for (l = 0; l < MAX_GOAL_WORMS; l++) {
2406 if (owl_goal_worm[l] == NO_MOVE)
2407 break;
2408 if (board[owl_goal_worm[l]] == EMPTY)
2409 if (size == 0 || worm[owl_goal_worm[l]].size > size) {
2410 w = l;
2411 size = worm[owl_goal_worm[l]].size;
2412 }
2413 }
2414 if (w != MAX_GOAL_WORMS) {
2415 if (GAIN > savecode) {
2416 /* if new result better, just update */
2417 dcode = LOSS;
2418 saveworm = w;
2419 }
2420 else if (GAIN == savecode) {
2421 /* bigger ? */
2422 int wpos = owl_goal_worm[saveworm];
2423 if (size > worm[wpos].size)
2424 saveworm = w;
2425 }
2426 }
2427 }
2428 UPDATE_SAVED_KO_RESULT(savecode, savemove, dcode, mpos);
2429 }
2430 else { /* ko_move */
2431 if (dcode != WIN) {
2432 if (mpos == 0) {
2433 SGFTRACE(mpos, KO_B, "all original stones captured with ko");
2434 }
2435 else {
2436 SGFTRACE(mpos, KO_B, "attack effective - ko");
2437 }
2438 /* We already know the savecode was previously 0. */
2439 savemove = mpos;
2440 savecode = KO_B;
2441
2442 /* It's possible that the defender has no defense even if we
2443 * give up the ko. In order to force a test of this,
2444 * assuming this was our only move, we decrease the number
2445 * of tried moves counter, disregarding this move.
2446 */
2447 number_tried_moves--;
2448 }
2449 }
2450
2451 pop_owl(&owl);
2452 popgo();
2453 }
2454 }
2455
2456 close_pattern_list(other, &shape_patterns);
2457
2458 if (savecode) {
2459 if (savecode == GAIN) {
2460 SGFTRACE(savemove, savecode, "attack effective (gain) - E");
2461 if (wormid)
2462 *wormid = saveworm;
2463 READ_RETURN2(OWL_ATTACK, str, depth - stackp,
2464 move, savemove, savecode, saveworm);
2465 }
2466 else {
2467 SGFTRACE(savemove, savecode, "attack effective (ko) - E");
2468 READ_RETURN(OWL_ATTACK, str, depth - stackp, move, savemove, savecode);
2469 }
2470 }
2471
2472 if (sgf_dumptree) {
2473 char winstr[128];
2474 sprintf(winstr, "attack failed)\n (%d variations",
2475 count_variations - this_variation_number);
2476 SGFTRACE(0, 0, winstr);
2477 }
2478
2479 READ_RETURN0(OWL_ATTACK, str, depth - stackp);
2480}
2481
2482
2483/* Returns true if the dragon at (target) can be captured given
2484 * two moves in a row. The first two moves to capture the
2485 * dragon are given as (*attack1) and (*attack2).
2486 */
2487
2488int
2489owl_threaten_attack(int target, int *attack1, int *attack2)
2490{
2491 struct owl_move_data moves[MAX_MOVES];
2492 int k;
2493 int other = OTHER_COLOR(board[target]);
2494 struct local_owl_data *owl;
2495 int result = 0;
2496 int reading_nodes_when_called = get_reading_node_counter();
2497 signed char saved_boundary[BOARDMAX];
2498 double start = 0.0;
2499 int tactical_nodes;
2500 int move = 0;
2501 int move2 = 0;
2502 struct matched_patterns_list_data shape_patterns;
2503
2504 shape_patterns.initialized = 0;
2505 result_certain = 1;
2506 if (search_persistent_owl_cache(OWL_THREATEN_ATTACK, target, 0, 0,
2507 &result, attack1, attack2, NULL))
2508 return result;
2509
2510 if (debug & DEBUG_OWL_PERFORMANCE)
2511 start = gg_cputime();
2512
2513 gg_assert(stackp == 0);
2514 TRACE("owl_threaten_attack %1m\n", target);
2515 init_owl(&owl, target, NO_MOVE, NO_MOVE, 1, NULL);
2516 memcpy(saved_boundary, owl->boundary, sizeof(saved_boundary));
2517 owl_make_domains(owl, NULL);
2518 owl_shapes(&shape_patterns, moves, other, owl, &owl_attackpat_db);
2519 for (k = 0; k < MAX_MOVES; k++) {
2520 current_owl_data = owl;
2521 if (!get_next_move_from_list(&shape_patterns, other, moves, 1, owl))
2522 break;
2523 else {
2524 int mpos = moves[k].pos;
2525
2526 if (mpos != NO_MOVE && moves[k].value > 0)
2527 if (trymove(mpos, other, moves[k].name, target)) {
2528 int pos;
2529 int origin = NO_MOVE;
2530 owl->lunches_are_current = 0;
2531 owl_update_boundary_marks(mpos, owl);
2532
2533 /* If the origin of the dragon has been captured, we look
2534 * for another string which was part of the original dragon,
2535 * marked when stackp==0, which has not been captured. If no
2536 * such string is found, owl_attack declares victory.
2537 */
2538
2539 if (board[target] == EMPTY) {
2540 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
2541 if (IS_STONE(board[pos]) && owl->goal[pos] == 1) {
2542 origin = find_origin(pos);
2543 break;
2544 }
2545 }
2546
2547 if (origin == NO_MOVE
2548 || do_owl_attack(origin, NULL, NULL, owl, 0)) {
2549 /* probably this can't happen */
2550 popgo();
2551 gg_assert(stackp == 0);
2552 result = 1;
2553 break;
2554 }
2555 }
2556 else if (do_owl_attack(target, &move2, NULL, owl, 0) == WIN) {
2557 move = moves[k].pos;
2558 popgo();
2559 gg_assert(stackp == 0);
2560 result = 1;
2561 break;
2562 }
2563 popgo();
2564 memcpy(owl->boundary, saved_boundary, sizeof(saved_boundary));
2565 }
2566 }
2567 }
2568 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
2569 gg_assert(stackp == 0);
2570
2571 DEBUG(DEBUG_OWL_PERFORMANCE,
2572 "owl_threaten_attack %1m %1m %1m, result %d (%d, %d nodes, %f seconds)\n",
2573 target, move, move2, result, local_owl_node_counter,
2574 tactical_nodes, gg_cputime() - start);
2575
2576 store_persistent_owl_cache(OWL_THREATEN_ATTACK, target, 0, 0,
2577 result, move, move2, 0,
2578 tactical_nodes, owl->goal, board[target]);
2579
2580 if (attack1)
2581 *attack1 = move;
2582 if (attack2)
2583 *attack2 = move2;
2584
2585 close_pattern_list(other, &shape_patterns);
2586 return result;
2587}
2588
2589
2590/* Returns true if a move can be found to defend the dragon
2591 * at (target), in which case (*defense_point) is the recommended move.
2592 * (defense_point) can be a null pointer if the result is not needed.
2593 *
2594 * The array goal marks the extent of the dragon. This must
2595 * be maintained during reading. Call this function only when
2596 * stackp==0; otherwise you can call do_owl_attack but you must
2597 * set up the goal and boundary arrays by hand first.
2598 *
2599 * Returns KO_A or KO_B if the position is ko:
2600 *
2601 * - Returns KO_A if the defendse succeeds provided the defender is willing to
2602 * ignore any ko threat (the defender makes the first ko capture).
2603 * - Returns KO_B if the defense succeeds provided the defender has a ko threat
2604 * which must be answered (the attacker makes the first ko capture).
2605 *
2606 * If GNU Go is compiled with `configure --enable-experimental-owl-ext'
2607 * then a return codes of GAIN is also possible.
2608 *
2609 * - Returns LOSS if the defense succeeds but another worm of the
2610 * defender's is captured in during the defense. The location
2611 * of the killed worm is returned through the *kworm field.
2612 *
2613 * The array goal marks the extent of the dragon. This must
2614 * be maintained during reading.
2615 */
2616
2617int
2618owl_defend(int target, int *defense_point, int *certain, int *kworm)
2619{
2620 int result;
2621 static struct local_owl_data *owl;
2622 int reading_nodes_when_called = get_reading_node_counter();
2623 double start = 0.0;
2624 int tactical_nodes;
2625 int move = NO_MOVE;
2626 int wpos = NO_MOVE;
2627 int wid = MAX_GOAL_WORMS;
2628
2629 result_certain = 1;
2630 if (worm[target].unconditional_status == DEAD)
2631 return 0;
2632
2633 if (search_persistent_owl_cache(OWL_DEFEND, target, 0, 0, &result,
2634 defense_point, kworm, certain))
2635 return result;
2636
2637 if (debug & DEBUG_OWL_PERFORMANCE)
2638 start = gg_cputime();
2639
2640 TRACE("owl_defend %1m\n", target);
2641 init_owl(&owl, target, NO_MOVE, NO_MOVE, 1, NULL);
2642 owl_make_domains(owl, NULL);
2643 prepare_goal_list(target, owl, owl_goal_worm, &goal_worms_computed,
2644 kworm, 1);
2645 result = do_owl_defend(target, &move, &wid, owl, 0);
2646 finish_goal_list(&goal_worms_computed, &wpos, owl_goal_worm, wid);
2647 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
2648
2649 DEBUG(DEBUG_OWL_PERFORMANCE,
2650 "owl_defend %1m, result %d %1m (%d, %d nodes, %f seconds)\n",
2651 target, result, move, local_owl_node_counter,
2652 tactical_nodes, gg_cputime() - start);
2653
2654 store_persistent_owl_cache(OWL_DEFEND, target, 0, 0, result, move, wpos,
2655 result_certain, tactical_nodes, owl->goal,
2656 board[target]);
2657
2658 if (defense_point)
2659 *defense_point = move;
2660 if (kworm)
2661 *kworm = wpos;
2662 if (certain)
2663 *certain = result_certain;
2664
2665 return result;
2666}
2667
2668
2669/* Static function containing the main recursive code for owl_defend.
2670 */
2671
2672static int
2673do_owl_defend(int str, int *move, int *wormid, struct local_owl_data *owl,
2674 int escape)
2675{
2676 int color = board[str];
2677 struct owl_move_data shape_moves[MAX_MOVES];
2678 struct owl_move_data vital_moves[MAX_MOVES];
2679 struct owl_move_data *moves;
2680 struct matched_patterns_list_data shape_patterns;
2681 signed char mw[BOARDMAX];
2682 int number_tried_moves = 0;
2683 int pass;
2684 int k;
2685 int savemove = 0;
2686 int saveworm = MAX_GOAL_WORMS;
2687 int savecode = 0;
2688 int eyemin = -1; /* Lower bound on the number of eyes. */
2689 int eyemax = -1; /* Upper bound on the number of eyes. */
2690 struct eyevalue probable_eyes; /* Best guess of eyevalue. */
2691 int escape_route;
2692 const char *live_reason;
2693 int move_cutoff;
2694 int xpos;
2695 int value1;
2696 int value2;
2697 int this_variation_number = count_variations - 1;
2698
2699 SETUP_TRACE_INFO("owl_defend", str);
2700
2701 shape_patterns.initialized = 0;
2702
2703 str = find_origin(str);
2704
2705 if (tt_get(&ttable, OWL_DEFEND, str, NO_MOVE, depth - stackp, NULL,
2706 &value1, &value2, &xpos) == 2) {
2707
2708 TRACE_CACHED_RESULT(value1, xpos);
2709 if (move)
2710 *move = xpos;
2711
2712 if (value1 == LOSS) {
2713 if (wormid) {
2714 if (goal_worms_computed)
2715 *wormid = value2;
2716 else
2717 *wormid = MAX_GOAL_WORMS;
2718 }
2719 }
2720
2721 if (value1 == WIN || value1 == LOSS)
2722 TRACE("%oVariation %d: ALIVE (cached)\n", this_variation_number);
2723 else
2724 TRACE("%oVariation %d: DEAD (cached)\n", this_variation_number);
2725
2726 SGFTRACE(xpos, value1, "cached");
2727
2728 return value1;
2729 }
2730
2731 /* In order to get a defense move even if we seem to already have
2732 * escaped and to reduce the impact of overestimated escape
2733 * possibilities, we don't declare escape victory on the first move.
2734 *
2735 * FIXME: Should introduce a new owl depth value rather than having
2736 * this hardwired value.
2737 */
2738 escape_route = owl_escape_route(owl);
2739 if (stackp > 2 && escape_route >= 5) {
2740 /* FIXME: We probably should make distinction in the returned
2741 * result whether the dragon lives by making two eyes or by
2742 * escaping.
2743 */
2744 TRACE("%oVariation %d: ALIVE (escaped)\n", this_variation_number);
2745 SGFTRACE(0, WIN, "escaped");
2746 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN);
2747 }
2748
2749 /* If reading goes to deep or we run out of nodes, we assume life. */
2750 if (reading_limit_reached(&live_reason, this_variation_number)) {
2751 SGFTRACE(0, WIN, live_reason);
2752 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN);
2753 }
2754
2755 memset(mw, 0, sizeof(mw));
2756 local_owl_node_counter++;
2757 global_owl_node_counter++;
2758
2759 current_owl_data = owl;
2760 memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache));
2761
2762 /* First see whether we might already be alive. */
2763 if (escape < MAX_ESCAPE) {
2764 if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 0,
2765 &probable_eyes, &eyemin, &eyemax)) {
2766 SGFTRACE(0, WIN, live_reason);
2767 TRACE("%oVariation %d: ALIVE (%s)\n",
2768 this_variation_number, live_reason);
2769 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN);
2770 }
2771 }
2772 else {
2773 /* In this case we don't recompute eyes. However, to avoid accessing
2774 * partially-random data left on stack, we copy eye data from the
2775 * previous depth level. It should be reasonably close to the actual
2776 * state of eyes.
2777 */
2778 memcpy(owl->my_eye, owl->restore_from->my_eye, sizeof(owl->my_eye));
2779 memcpy(owl->half_eye, owl->restore_from->half_eye, sizeof(owl->half_eye));
2780
2781 vital_moves[0].pos = 0;
2782 vital_moves[0].value = -1;
2783 set_eyevalue(&probable_eyes, 0, 0, 0, 0);
2784 }
2785
2786 /* We try moves in four passes.
2787 * stackp==0 stackp>0
2788 * 0. Vital moves in the interval [70..] [45..]
2789 * 1. Shape moves
2790 * 2. Vital moves in the interval [..69] [..44]
2791 * 3. Tactical defense moves
2792 */
2793 for (pass = 0; pass < 4; pass++) {
2794 moves = NULL;
2795 move_cutoff = 1;
2796
2797 current_owl_data = owl;
2798 switch (pass) {
2799 /* Get the shape moves if we are in the right pass. */
2800 case 1:
2801
2802 if (stackp > owl_branch_depth && number_tried_moves > 0)
2803 continue;
2804
2805 owl_shapes(&shape_patterns, shape_moves, color, owl, &owl_defendpat_db);
2806 moves = shape_moves;
2807 break;
2808
2809 case 0:
2810 case 2:
2811 if (stackp > owl_branch_depth && number_tried_moves > 0)
2812 continue;
2813
2814 moves = vital_moves;
2815 if (pass == 0 || stackp > owl_distrust_depth) {
2816 if (stackp == 0)
2817 move_cutoff = 70;
2818 else if (eyemin + min_eyes(&probable_eyes) > 3)
2819 move_cutoff = 25;
2820 else if (eyemin + min_eyes(&probable_eyes) >= 3)
2821 move_cutoff = 35;
2822 else
2823 move_cutoff = 45;
2824 }
2825 if (eyemax < 2 && stackp > 2)
2826 move_cutoff = 99; /* Effectively disable vital moves. */
2827 break;
2828
2829 case 3:
2830 {
2831 int goalcount = 0;
2832
2833 /* If the goal is small, try a tactical defense. */
2834
2835 for (k = BOARDMIN; k < BOARDMAX; k++)
2836 if (ON_BOARD(k))
2837 goalcount += owl->goal[k];
2838
2839 if (goalcount < 5) {
2840
2841 /* Look for a tactical defense. This is primarily intended for
2842 * the case where the whole dragon is a single string, therefore
2843 * we only look at the string at the "origin".
2844 *
2845 * We only accept clearly effective tactical defenses here,
2846 * using a liberty heuristic. The reason for this is problems
2847 * with ineffective self ataris which do defend tactically but
2848 * have no strategical effect other than wasting owl nodes or
2849 * confusing the eye analysis.
2850 */
2851 int dpos;
2852 SGFTree *save_sgf_dumptree = sgf_dumptree;
2853 int save_count_variations = count_variations;
2854
2855 sgf_dumptree = NULL;
2856 count_variations = 0;
2857 if (attack_and_defend(str, NULL, NULL, NULL, &dpos)
2858 && (approxlib(dpos, color, 2, NULL) > 1
2859 || does_capture_something(dpos, color))) {
2860 TRACE("Found tactical defense for %1m at %1m.\n", str, dpos);
2861 set_single_owl_move(shape_moves, dpos, "tactical_defense");
2862 moves = shape_moves;
2863 }
2864 sgf_dumptree = save_sgf_dumptree;
2865 count_variations = save_count_variations;
2866 }
2867 if (!moves)
2868 continue;
2869 }
2870 } /* switch (pass) */
2871
2872 /* For the up to MAX_MOVES best moves with value equal to
2873 * move_cutoff or higher, try to defend the dragon and see if it
2874 * can then be attacked.
2875 */
2876 for (k = 0; k < MAX_MOVES; k++) {
2877 int mpos;
2878 int ko_move = -1;
2879 int new_escape;
2880 int wid = MAX_GOAL_WORMS;
2881
2882 /* Consider only the highest scoring move if we're deeper than
2883 * owl_branch_depth.
2884 *
2885 * FIXME: To behave as intended, k should be replaced by
2886 * number_tried_moves.
2887 */
2888 if (stackp > owl_branch_depth && k > 0)
2889 break;
2890
2891 current_owl_data = owl;
2892
2893 if (pass == 1) {
2894 if (!get_next_move_from_list(&shape_patterns, color, shape_moves,
2895 move_cutoff, owl))
2896 break;
2897 }
2898 else
2899 if (moves[k].value < move_cutoff)
2900 break;
2901
2902 mpos = moves[k].pos;
2903 modify_eyefilling_move(&mpos, color);
2904 ASSERT_ON_BOARD1(mpos);
2905
2906 /* Have we already tested this move? */
2907 if (mw[mpos])
2908 continue;
2909
2910 /* Try to make the move. */
2911 if (!komaster_trymove(mpos, color, moves[k].name, str,
2912 &ko_move, savecode == 0))
2913 continue;
2914
2915 new_escape = escape;
2916 if (moves[k].escape)
2917 new_escape++;
2918
2919 TRACE("Trying %C %1m. Escape = %d. Current stack: ",
2920 color, mpos, escape);
2921 if (verbose)
2922 dump_stack();
2923
2924 /* We have now made a move. Analyze the new position. */
2925 push_owl(&owl);
2926 mw[mpos] = 1;
2927 number_tried_moves++;
2928
2929 /* Add the stone just played to the goal dragon, unless the
2930 * pattern explicitly asked for not doing this.
2931 */
2932 owl_update_goal(mpos, moves[k].same_dragon, moves[k].lunch, owl, 0,
2933 moves[k].pattern_data);
2934 mark_goal_in_sgf(owl->goal);
2935
2936 if (!ko_move) {
2937 int acode = do_owl_attack(str, NULL, &wid, owl, new_escape);
2938 if (!acode) {
2939 pop_owl(&owl);
2940 popgo();
2941 if (sgf_dumptree) {
2942 char winstr[192];
2943 sprintf(winstr, "defense effective)\n (%d variations",
2944 count_variations - this_variation_number);
2945 SGFTRACE(mpos, WIN, winstr);
2946 }
2947 close_pattern_list(color, &shape_patterns);
2948 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, mpos, WIN);
2949 }
2950 if (acode == GAIN)
2951 saveworm = wid;
2952 UPDATE_SAVED_KO_RESULT(savecode, savemove, acode, mpos);
2953 }
2954 else {
2955 if (do_owl_attack(str, NULL, NULL, owl, new_escape) != WIN) {
2956 savemove = mpos;
2957 savecode = KO_B;
2958 }
2959 }
2960
2961 /* Undo the tested move. */
2962 pop_owl(&owl);
2963 popgo();
2964 }
2965 }
2966
2967 close_pattern_list(color, &shape_patterns);
2968
2969 if (savecode) {
2970 if (savecode == LOSS) {
2971 SGFTRACE(savemove, savecode, "defense effective (loss) - B");
2972 if (wormid)
2973 *wormid = saveworm;
2974 READ_RETURN2(OWL_DEFEND, str, depth - stackp,
2975 move, savemove, savecode, saveworm);
2976 }
2977 else {
2978 SGFTRACE(savemove, savecode, "defense effective (ko) - B");
2979 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, savemove, savecode);
2980 }
2981 }
2982
2983 if (number_tried_moves == 0 && min_eyes(&probable_eyes) >= 2) {
2984 SGFTRACE(0, WIN, "genus probably >= 2");
2985 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN);
2986 }
2987
2988
2989 if (sgf_dumptree) {
2990 char winstr[196];
2991 int print_genus = eyemin == 1 ? 1 : 0;
2992 sprintf(winstr, "defense failed - genus %d)\n (%d variations",
2993 print_genus, count_variations - this_variation_number);
2994 SGFTRACE(0, 0, winstr);
2995 }
2996
2997 READ_RETURN0(OWL_DEFEND, str, depth - stackp);
2998}
2999
3000
3001/* Returns true if the dragon at (target) can be defended given
3002 * two moves in a row. The first two moves to defend the
3003 * dragon are given as (*defend1) and (*defend2).
3004 */
3005
3006int
3007owl_threaten_defense(int target, int *defend1, int *defend2)
3008{
3009 struct owl_move_data moves[MAX_MOVES];
3010 int k;
3011 int color = board[target];
3012 int result = 0;
3013 struct local_owl_data *owl;
3014 int reading_nodes_when_called = get_reading_node_counter();
3015 signed char saved_goal[BOARDMAX];
3016 double start = 0.0;
3017 int tactical_nodes;
3018 int move = 0;
3019 int move2 = 0;
3020 struct matched_patterns_list_data shape_patterns;
3021
3022 shape_patterns.initialized = 0;
3023
3024 result_certain = 1;
3025 if (worm[target].unconditional_status == DEAD)
3026 return 0;
3027
3028 if (search_persistent_owl_cache(OWL_THREATEN_DEFENSE, target, 0, 0,
3029 &result, defend1, defend2, NULL))
3030 return result;
3031
3032 if (debug & DEBUG_OWL_PERFORMANCE)
3033 start = gg_cputime();
3034
3035 TRACE("owl_threaten_defense %1m\n", target);
3036 init_owl(&owl, target, NO_MOVE, NO_MOVE, 1, NULL);
3037 memcpy(saved_goal, owl->goal, sizeof(saved_goal));
3038 owl_make_domains(owl, NULL);
3039 owl_shapes(&shape_patterns, moves, color, owl, &owl_defendpat_db);
3040 for (k = 0; k < MAX_MOVES; k++) {
3041 current_owl_data = owl;
3042 if (!get_next_move_from_list(&shape_patterns, color, moves, 1, owl))
3043 break;
3044 else {
3045 if (moves[k].pos != NO_MOVE && moves[k].value > 0)
3046 if (trymove(moves[k].pos, color, moves[k].name, target)) {
3047 owl->lunches_are_current = 0;
3048 owl_update_goal(moves[k].pos, moves[k].same_dragon,
3049 moves[k].lunch, owl, 0, moves[k].pattern_data);
3050 if (do_owl_defend(target, &move2, NULL, owl, 0) == WIN) {
3051 move = moves[k].pos;
3052 popgo();
3053 /* Don't return the second move if occupied before trymove */
3054 if (move2 != NO_MOVE && IS_STONE(board[move2]))
3055 move2 = NO_MOVE;
3056 result = WIN;
3057 break;
3058 }
3059 else
3060 popgo();
3061 memcpy(owl->goal, saved_goal, sizeof(saved_goal));
3062 }
3063 }
3064 }
3065 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
3066 gg_assert(stackp == 0);
3067
3068 DEBUG(DEBUG_OWL_PERFORMANCE,
3069 "owl_threaten_defense %1m %1m %1m, result %d (%d, %d nodes, %f seconds)\n",
3070 target, move, move2, result, local_owl_node_counter,
3071 tactical_nodes, gg_cputime() - start);
3072
3073 store_persistent_owl_cache(OWL_THREATEN_DEFENSE, target, 0, 0,
3074 result, move, move2, 0,
3075 tactical_nodes, owl->goal, board[target]);
3076
3077 if (defend1)
3078 *defend1 = move;
3079 if (defend2)
3080 *defend2 = move2;
3081
3082 close_pattern_list(color, &shape_patterns);
3083 return result;
3084}
3085
3086
3087
3088/*
3089 * This function calls owl_determine_life() to get an eye estimate,
3090 * and matchpat() for vital attack moves, and decides according to
3091 * various policies (depth-dependant) whether the dragon should thus
3092 * be considered alive.
3093 */
3094static int
3095owl_estimate_life(struct local_owl_data *owl,
3096 struct local_owl_data *second_owl,
3097 struct owl_move_data vital_moves[MAX_MOVES],
3098 const char **live_reason, int does_attack,
3099 struct eyevalue *probable_eyes, int *eyemin, int *eyemax)
3100{
3101 SGFTree *save_sgf_dumptree = sgf_dumptree;
3102 int save_count_variations = count_variations;
3103 struct owl_move_data dummy_moves[MAX_MOVES];
3104 int other = OTHER_COLOR(owl->color);
3105
3106 sgf_dumptree = NULL;
3107 count_variations = 0;
3108
3109 owl_determine_life(owl, second_owl, does_attack, vital_moves,
3110 probable_eyes, eyemin, eyemax);
3111
3112 matches_found = 0;
3113 memset(found_matches, 0, sizeof(found_matches));
3114
3115 if (get_level() >= 8) {
3116 memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache));
3117 if (!does_attack) {
3118 clear_owl_move_data(dummy_moves);
3119 matchpat(owl_shapes_callback, other,
3120 &owl_vital_apat_db, dummy_moves, owl->goal);
3121 }
3122 else if (max_eyes(probable_eyes) >= 2)
3123 matchpat(owl_shapes_callback, other,
3124 &owl_vital_apat_db, vital_moves, owl->goal);
3125 }
3126
3127 if ((debug & DEBUG_EYES) && (debug & DEBUG_OWL))
3128 gprintf("owl: eyemin=%d matches_found=%d\n", *eyemin, matches_found);
3129 if (*eyemin >= matches_found)
3130 *eyemin -= matches_found;
3131 else
3132 *eyemin = 0;
3133
3134 sgf_dumptree = save_sgf_dumptree;
3135 count_variations = save_count_variations;
3136
3137 if (*eyemin >= 2
3138 || (*eyemin == 1 && min_eyes(probable_eyes) >= 4)
3139 || (stackp > owl_distrust_depth
3140 && min_eyes(probable_eyes) >= 2
3141 && !matches_found)) {
3142 if (*eyemin >= 2)
3143 *live_reason = "2 or more secure eyes";
3144 else if (*eyemin == 1 && min_eyes(probable_eyes) >= 4)
3145 *live_reason = "1 secure eye, likely >= 4";
3146 else if (stackp > owl_distrust_depth
3147 && min_eyes(probable_eyes) >= 2
3148 && !matches_found)
3149 *live_reason = "getting deep, looks lively";
3150 else
3151 gg_assert(0);
3152 return 1;
3153 }
3154
3155 if (!does_attack
3156 && (*eyemin + matches_found >= 2
3157 || (*eyemin + matches_found == 1 && min_eyes(probable_eyes) >= 4)
3158 || (stackp > owl_distrust_depth
3159 && min_eyes(probable_eyes) >= 2))) {
3160 /* We are not yet alive only due to owl vital attack patterns matching.
3161 * Let's try to defend against it.
3162 */
3163 owl_add_move(vital_moves, dummy_moves[0].defense_pos,
3164 dummy_moves[0].value, dummy_moves[0].name,
3165 SAME_DRAGON_CONNECTED, NO_MOVE, 0, NO_MOVE, MAX_MOVES, NULL);
3166 }
3167
3168 return 0;
3169}
3170
3171
3172/*
3173 * This function is invoked from do_owl_attack() and do_owl_defend()
3174 * for each node to determine whether the the dragon has sufficient
3175 * eye potential to live. It also generates vital moves to attack or
3176 * defend the eyes. There are two distinct sources for eyes. The first
3177 * is the eyespaces found by make_domains() and evaluated by
3178 * compute_eyes_pessimistic(). The second is the lunches found by
3179 * owl_find_lunches() and evaluated by sniff_lunch().
3180 *
3181 * The best guess of the eye potential is stored as an eyevalue in
3182 * *probable_eyes. This is not entirely reliable though since the
3183 * graph matching techniques in optics.c fail to understand subtleties
3184 * like atari inside the eyespace, cutting points in the wall, and
3185 * shortage of outside liberties. (The patterns in owl_vital_apats.db
3186 * are used to compensate for this. See do_owl_attack() and
3187 * do_owl_defend() for how these are used.) Also the estimates from
3188 * sniff_lunch() are fairly unreliable.
3189 *
3190 * A lower and upper bound on the number of eyes are returned in
3191 * *eyemin and *eyemax. The value of *eyemin must be offset by the
3192 * matches of owl_vital_apats.db. If that number is 2 or larger, we
3193 * should be certain of life.
3194 *
3195 * Vital moves to attack or defend eyes are returned in the moves[]
3196 * array. Also moves to reduce the uncertainty of the eye estimates
3197 * are added to this array, but with smaller move values. The
3198 * parameter does_attack determines whether to generate vital attack
3199 * moves or vital defense moves.
3200 *
3201 * The dragon is specified by the information in the owl struct. The
3202 * color of the dragon is passed in the color parameter.
3203 *
3204 * For use in the semeai code, a second dragon can be provided. Set
3205 * this to NULL when only one dragon is involved.
3206 */
3207
3208static void
3209owl_determine_life(struct local_owl_data *owl,
3210 struct local_owl_data *second_owl,
3211 int does_attack,
3212 struct owl_move_data *moves,
3213 struct eyevalue *probable_eyes, int *eyemin, int *eyemax)
3214{
3215 int color = owl->color;
3216 struct eye_data *eye = owl->my_eye;
3217 int mw[BOARDMAX]; /* mark relevant eye origins */
3218 int mz[BOARDMAX]; /* mark potentially irrelevant eye origins */
3219 int vital_values[BOARDMAX];
3220 int dummy_eyemin = 0;
3221 int dummy_eyemax = 0;
3222 struct eyevalue eyevalue;
3223 struct eyevalue eyevalue_list[BOARDMAX/2];
3224 int eyes_attack_points[BOARDMAX/2];
3225 int pessimistic_min;
3226 int attack_point;
3227 int defense_point;
3228 int pos;
3229 int k;
3230 int lunch;
3231 int num_eyes = 0;
3232 int num_lunches = 0;
3233 int save_debug = debug;
3234 memset(vital_values, 0, sizeof(vital_values));
3235
3236 if (!eyemin)
3237 eyemin = &dummy_eyemin;
3238 if (!eyemax)
3239 eyemax = &dummy_eyemax;
3240
3241 *eyemin = 0;
3242 *eyemax = 0;
3243
3244 /* Turn off eye debugging if we're not also debugging owl. */
3245 if (!(debug & DEBUG_OWL))
3246 debug &= ~DEBUG_EYES;
3247
3248 clear_owl_move_data(moves);
3249
3250 if (!owl->lunches_are_current)
3251 owl_find_lunches(owl);
3252
3253 if (0) {
3254 for (k = 0; k < MAX_LUNCHES; k++)
3255 if (owl->lunch[k] != NO_MOVE)
3256 gprintf("owl lunch %1m, attack %1m, defend %1m\n",
3257 owl->lunch[k],
3258 owl->lunch_attack_point[k],
3259 owl->lunch_defense_point[k]);
3260 }
3261
3262 owl_make_domains(owl, second_owl);
3263
3264 owl_find_relevant_eyespaces(owl, mw, mz);
3265
3266 /* Reset halfeye data. Set topological eye value to something big. */
3267 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
3268 if (ON_BOARD(pos)) {
3269 owl->half_eye[pos].type = 0;
3270 owl->half_eye[pos].value = 10.0;
3271 }
3272 }
3273
3274 /* Find topological half eyes and false eyes. */
3275 find_half_and_false_eyes(color, eye, owl->half_eye, mw);
3276
3277 /* The eyespaces may have been split or changed in other ways by the
3278 * topological analysis, so we need to regenerate them and once more
3279 * determine which ones are relevant.
3280 */
3281 partition_eyespaces(owl->my_eye, owl->color);
3282 owl_find_relevant_eyespaces(owl, mw, mz);
3283
3284 set_eyevalue(probable_eyes, 0, 0, 0, 0);
3285
3286 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
3287 if (ON_BOARD(pos) && mw[pos] > 1) {
3288 int value = 0;
3289 const char *reason = "";
3290 compute_eyes_pessimistic(pos, &eyevalue, &pessimistic_min,
3291 &attack_point, &defense_point,
3292 eye, owl->half_eye);
3293
3294 /* If the eyespace is more in contact with own stones not in the goal,
3295 * than with ones in the goal, there is a risk that we can be cut off
3296 * from a major part of the eyespace. Thus we can't trust the opinion
3297 * of compute_eyes().
3298 *
3299 * (Obviously this is a quite fuzzy heuristic. With more accurate
3300 * connection analysis in the owl code we could do this more robustly.)
3301 */
3302 if (mw[pos] < mz[pos]
3303 || (mw[pos] < 3 * mz[pos] && mz[pos] > 5))
3304 pessimistic_min = 0;
3305
3306 /* It appears that this policy is needed no longer. */
3307#if 0
3308 /* If this eyespace includes an owl inessential string, we must assume
3309 * that the pessimistic min is 0.
3310 */
3311 if (pessimistic_min > 0) {
3312 for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
3313 if (ON_BOARD(pos2)
3314 && eye[pos2].origin == pos
3315 && owl->inessential[pos2]) {
3316 pessimistic_min = 0;
3317 break;
3318 }
3319 }
3320 }
3321#endif
3322
3323 eyes_attack_points[num_eyes] = NO_MOVE;
3324 eyevalue_list[num_eyes] = eyevalue;
3325 *eyemin += pessimistic_min;
3326
3327 /* Fill in the value field for use by the owl_eyespace() function. */
3328 eye[pos].value = eyevalue;
3329
3330 /* This shortcut has been disabled for two reasons:
3331 * 1. Due to the vital attack moves being able to later reduce
3332 * the *eyemin, we can't say that a certain *eyemin is
3333 * sufficient.
3334 * 2. This part of the code is in no way time critical.
3335 */
3336#if 0
3337 /* Found two certain eyes---look no further. */
3338 if (*eyemin >= 2) {
3339 debug = save_debug;
3340 return 2;
3341 }
3342#endif
3343
3344 if (eye_move_urgency(&eyevalue)) {
3345 value = 50;
3346 if (max_eyes(&eyevalue) - min_eyes(&eyevalue) == 2)
3347 value = 70;
3348 else if (max_eyes(&eyevalue) - pessimistic_min == 2)
3349 value = 60;
3350 reason = "vital move";
3351 }
3352 else if (max_eyes(&eyevalue) != pessimistic_min) {
3353 if (max_eyes(&eyevalue) - pessimistic_min == 2)
3354 value = 40;
3355 else
3356 value = 30;
3357 reason = "marginal eye space";
3358 }
3359
3360 if (value > 0) {
3361 if (does_attack && attack_point != NO_MOVE) {
3362 if (vital_values[attack_point] > 0) {
3363 value += vital_values[attack_point];
3364 if (value > 98)
3365 value = 98; /* Higher values may get special interpretation. */
3366 }
3367
3368 TRACE("%s at %1m, score %d (eye at %1m, value %s, pessimistic_min %d)\n",
3369 reason, attack_point, value,
3370 pos, eyevalue_to_string(&eyevalue), pessimistic_min);
3371
3372 if (eye[attack_point].marginal
3373 && modify_stupid_eye_vital_point(owl, &attack_point, 1))
3374 TRACE("vital point looked stupid, moved it to %1m\n",
3375 attack_point);
3376
3377 if (attack_point != NO_MOVE) {
3378 owl_add_move(moves, attack_point, value, reason,
3379 SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE,
3380 0, NO_MOVE, MAX_MOVES, NULL);
3381 vital_values[attack_point] = value;
3382 eyes_attack_points[num_eyes] = attack_point;
3383 }
3384 }
3385
3386 /* The reason for the last set of tests is that we don't
3387 * want to play a self atari in e.g. this position
3388 *
3389 * |XXX.
3390 * |OOX.
3391 * |.OX.
3392 * |XOXX
3393 * |XOOX
3394 * |O*OX
3395 * +----
3396 *
3397 * but it's okay in this position
3398 *
3399 * |XXXXX
3400 * |....X
3401 * |OOOOX
3402 * |.XXOX
3403 * |.*XOX
3404 * +-----
3405 *
3406 * In both cases * is the vital point according to the graph
3407 * matching. The significant difference is that in the first
3408 * case the vital point is adjacent to stones in the goal.
3409 */
3410 else if (!does_attack
3411 && defense_point != NO_MOVE
3412 && board[defense_point] == EMPTY
3413 && (!liberty_of_goal(defense_point, owl)
3414 || !is_self_atari(defense_point, color)
3415 || is_ko(defense_point, color, NULL)
3416 || safe_move(defense_point, color) != 0)) {
3417 if (vital_values[defense_point] > 0) {
3418 value += vital_values[defense_point];
3419 if (value > 98)
3420 value = 98; /* Higher values may get special interpretation. */
3421 }
3422
3423 TRACE("%s at %1m, score %d (eye at %1m, value %s, pessimistic_min %d)\n",
3424 reason, defense_point, value, pos,
3425 eyevalue_to_string(&eyevalue), pessimistic_min);
3426
3427 if ((eye[defense_point].marginal
3428 || eye[defense_point].origin != pos)
3429 && modify_stupid_eye_vital_point(owl, &defense_point, 0))
3430 TRACE("vital point looked stupid, moved it to %1m\n",
3431 defense_point);
3432
3433 if (defense_point != NO_MOVE) {
3434 owl_add_move(moves, defense_point, value, reason,
3435 SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE,
3436 0, NO_MOVE, MAX_MOVES, NULL);
3437 vital_values[defense_point] = value;
3438 }
3439 }
3440 }
3441 num_eyes++;
3442 }
3443 }
3444
3445 /* Sniff each lunch for nutritional value. The assumption is that
3446 * capturing the lunch is gote, therefore the number of half eyes
3447 * equals the MINIMUM number of eyes yielded by the resulting eye
3448 * space.
3449 */
3450 {
3451 for (lunch = 0; (lunch < MAX_LUNCHES); lunch++)
3452 if (owl->lunch[lunch] != NO_MOVE
3453 && owl->lunch_defense_point[lunch] != NO_MOVE) {
3454 int value = 0;
3455 int lunch_min;
3456 int lunch_probable;
3457 int lunch_max;
3458 struct eyevalue e;
3459 sniff_lunch(owl->lunch[lunch],
3460 &lunch_min, &lunch_probable, &lunch_max, owl);
3461
3462 set_eyevalue(&e, 0, 0, lunch_probable, lunch_probable);
3463 *eyemax += lunch_max;
3464
3465 if (lunch_probable == 0) {
3466 if (countstones(owl->lunch[lunch]) == 1)
3467 continue;
3468 value = 20;
3469 }
3470 else if (lunch_probable == 1 && lunch_max == 1)
3471 value = 60 + countstones(owl->lunch[lunch]);
3472 else if (lunch_probable == 1 && lunch_max == 2)
3473 value = 70 + countstones(owl->lunch[lunch]);
3474 else
3475 value = 75 + countstones(owl->lunch[lunch]);
3476
3477 if (owl->lunch_attack_code[lunch] != WIN)
3478 value -= 10;
3479
3480 if (does_attack) {
3481 defense_point = improve_lunch_defense(owl->lunch[lunch],
3482 owl->lunch_defense_point[lunch]);
3483
3484 if (vital_values[defense_point]) {
3485 /* The point here is that the move which saves the lunch also
3486 * attacks an eye. So this attack move reduces the global eye
3487 * potential. The eyes arithmetic for probable_eyes has then
3488 * to be adapted accordingly.
3489 */
3490 int ne;
3491 for (ne = 0; ne < num_eyes - num_lunches; ne++)
3492 if (eyes_attack_points[ne] == defense_point)
3493 break;
3494 gg_assert(ne < num_eyes - num_lunches);
3495 /* merge eye values */
3496 add_eyevalues(&eyevalue_list[ne], &e, &eyevalue_list[ne]);
3497 /* and adjust */
3498 eyevalue_list[ne].a = 0;
3499 eyevalue_list[ne].b = 0;
3500 }
3501 else {
3502 num_lunches++;
3503 eyevalue_list[num_eyes++] = e;
3504 }
3505
3506 TRACE("save lunch at %1m with %1m, score %d, probable eye %d, max eye %d\n",
3507 owl->lunch[lunch], defense_point, value,
3508 lunch_probable, lunch_max);
3509 owl_add_move(moves, defense_point, value,
3510 "save lunch", SAME_DRAGON_MAYBE_CONNECTED,
3511 NO_MOVE, 0, NO_MOVE, MAX_MOVES, NULL);
3512 }
3513 else {
3514 attack_point = improve_lunch_attack(owl->lunch[lunch],
3515 owl->lunch_attack_point[lunch]);
3516 TRACE("eat lunch at %1m with %1m, score %d, probable eye %d, max eye %d\n",
3517 owl->lunch[lunch], attack_point, value,
3518 lunch_probable, lunch_max);
3519 /* We only remember the lunch for owl_update_goal() if the lunch
3520 * cannot be defended with ko after the move.
3521 * If we capture the lunch by an illegal ko capture, we become
3522 * ko master with this move, and hence the above is true.
3523 */
3524 if (owl->lunch_attack_code[lunch] == WIN
3525 || is_illegal_ko_capture(attack_point, owl->color))
3526 owl_add_move(moves, attack_point, value, "eat lunch",
3527 SAME_DRAGON_MAYBE_CONNECTED, owl->lunch[lunch],
3528 0, NO_MOVE, MAX_MOVES, NULL);
3529 else
3530 owl_add_move(moves, attack_point, value, "eat lunch",
3531 SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE, 0, NO_MOVE,
3532 MAX_MOVES, NULL);
3533 num_lunches++;
3534 eyevalue_list[num_eyes++] = e;
3535 }
3536 }
3537 }
3538
3539 /* now, totalize the eye potential */
3540 {
3541 int ne;
3542 for (ne = 0; ne < num_eyes - num_lunches; ne++)
3543 add_eyevalues(probable_eyes, &eyevalue_list[ne], probable_eyes);
3544
3545 *eyemax += max_eyes(probable_eyes);
3546 /* If we have at least two different eyespaces and can create one eye
3547 * in sente, we assume there's a chance to create another one. This is
3548 * needed because optics code don't know about eyespaces influencing
3549 * each other and combination moves (i.e. double threats to create an
3550 * eye).
3551 */
3552 if (num_eyes - num_lunches > 1 && max_eye_threat(probable_eyes) > 1)
3553 *eyemax += 1;
3554
3555 for (; ne < num_eyes; ne++)
3556 add_eyevalues(probable_eyes, &eyevalue_list[ne], probable_eyes);
3557 }
3558
3559 debug = save_debug;
3560}
3561
3562
3563/* The eyespaces we want to evaluate are the ones which
3564 * are adjacent to the dragon (whose stones comprise the
3565 * support of goal) which are not GRAY bordered. These
3566 * are the eyespaces of the dragon. Now we find their
3567 * origins.
3568 *
3569 * It is required that there are at least two distinct connections,
3570 * adjacent or diagonal, between non-marginal eyespace vertices and
3571 * stones of the goal dragon. Otherwise there is a risk that we
3572 * include irrelevant eye spaces.
3573 */
3574
3575static void
3576owl_find_relevant_eyespaces(struct local_owl_data *owl,
3577 int mw[BOARDMAX], int mz[BOARDMAX])
3578{
3579 int pos;
3580 int eye_color;
3581 int k;
3582 struct eye_data *eye = owl->my_eye;
3583
3584 if (owl->color == WHITE)
3585 eye_color = WHITE;
3586 else
3587 eye_color = BLACK;
3588
3589 memset(mw, 0, BOARDMAX * sizeof(mw[0]));
3590 memset(mz, 0, BOARDMAX * sizeof(mz[0]));
3591 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
3592 if (board[pos] == owl->color) {
3593 for (k = 0; k < 8; k++) {
3594 int pos2 = pos + delta[k];
3595 if (ON_BOARD(pos2)
3596 && eye[pos2].color == eye_color
3597 && !eye[pos2].marginal) {
3598 if (owl->goal[pos])
3599 mw[eye[pos2].origin]++;
3600 else
3601 mz[eye[pos2].origin]++;
3602 }
3603 }
3604 }
3605 }
3606}
3607
3608/* Case 1.
3609 *
3610 * The optics code occasionally comes up with stupid vital moves, like
3611 * a in this position:
3612 *
3613 * ----+
3614 * O...|
3615 * OX..|
3616 * OX..|
3617 * O.X.|
3618 * .O.a|
3619 * ....|
3620 *
3621 * This function moves such moves to the second line.
3622 *
3623 * Case 2.
3624 *
3625 * In this position the optics code can suggest the empty 1-2 point as
3626 * vital move for the eyespace on the right edge. That is okay for attack
3627 * but obviously not for defense.
3628 *
3629 * ----+
3630 * XO.O|
3631 * XOOX|
3632 * XXO.|
3633 * .XOO|
3634 * .XXX|
3635 *
3636 * Case 3.
3637 *
3638 * Playing into a snapback is usually not an effective way to destroy
3639 * an eye.
3640 *
3641 * XOOO|
3642 * XOXX|
3643 * XXO.|
3644 * .XXO|
3645 * ....|
3646 *
3647 * This function changes the attack point to NO_MOVE (i.e. removes it).
3648 */
3649static int
3650modify_stupid_eye_vital_point(struct local_owl_data *owl, int *vital_point,
3651 int is_attack_point)
3652{
3653 int up;
3654 int right;
3655 int k;
3656 int libs[2];
3657
3658 /* Case 1. */
3659 for (k = 0; k < 4; k++) {
3660 up = delta[k];
3661 if (ON_BOARD(*vital_point - up))
3662 continue;
3663
3664 if (board[*vital_point + up] != EMPTY)
3665 continue;
3666
3667 right = delta[(k+1) % 4];
3668
3669 if (board[*vital_point + right] != EMPTY
3670 || board[*vital_point - right] != EMPTY)
3671 continue;
3672
3673 if (board[*vital_point + 2 * up] != EMPTY
3674 || board[*vital_point + up + right] != EMPTY
3675 || board[*vital_point + up - right] != EMPTY) {
3676 *vital_point += up;
3677 return 1;
3678 }
3679 }
3680
3681 /* Case 2. */
3682 if (!is_attack_point) {
3683 if (approxlib(*vital_point, OTHER_COLOR(owl->color), 1, NULL) == 0) {
3684 for (k = 4; k < 8; k++) {
3685 int pos = *vital_point + delta[k];
3686 if (board[pos] == OTHER_COLOR(owl->color)
3687 && countlib(pos) == 1) {
3688 findlib(pos, 1, vital_point);
3689 return 1;
3690 }
3691 }
3692 }
3693 }
3694
3695 /* Case 3. */
3696 if (is_attack_point
3697 && does_capture_something(*vital_point, OTHER_COLOR(owl->color))
3698 && accuratelib(*vital_point, OTHER_COLOR(owl->color), 2, libs) == 1
3699 && !attack(libs[0], NULL)) {
3700 *vital_point = NO_MOVE;
3701 return 1;
3702 }
3703
3704 return 0;
3705}
3706
3707
3708/* The purpose of this function is to avoid moves which needlessly
3709 * fill in an eye. A typical example, from ld_owl:188, is
3710 *
3711 * -----+
3712 * .O.OX|
3713 * XOOXX|
3714 * XXOOX|
3715 * .XXO.|
3716 * ..XOO|
3717 * ..XXX|
3718 *
3719 * where various patterns manage to propose the eye-filling move on
3720 * the top edge instead of capturing the opponent stones and get two
3721 * solid eyes. This function modifies the move accordingly.
3722 */
3723static int
3724modify_eyefilling_move(int *move, int color)
3725{
3726 int k;
3727 int r;
3728 int other = OTHER_COLOR(color);
3729 /* Only do this for a small eye. */
3730 for (k = 0; k < 4; k++)
3731 if (ON_BOARD(*move + delta[k]) && board[*move + delta[k]] != color)
3732 return 0;
3733
3734 for (r = 4; r < 8; r++)
3735 if (board[*move + delta[r]] == other
3736 && countlib(*move + delta[r]) == 1) {
3737 for (k = 0; k < 4; k++)
3738 if (board[*move + delta[k]] == color
3739 && countlib(*move + delta[k]) == 1
3740 && !adjacent_strings(*move + delta[r], *move + delta[k]))
3741 break;
3742
3743 if (k == 4) {
3744 int new_move;
3745 findlib(*move + delta[r], 1, &new_move);
3746 TRACE("Changing eyefilling move at %1m to capture at %1m.\n",
3747 *move, new_move);
3748 *move = new_move;
3749 return 1;
3750 }
3751 }
3752
3753 return 0;
3754}
3755
3756
3757/*
3758 * Generates up to max_moves moves, attempting to attack or defend the goal
3759 * dragon. The found moves are put in moves, an array of owl_move_data
3760 * structs, starting in the position 'initial'. The entries in the array are
3761 * sorted by value with moves[initial] having highest priority. When no more
3762 * moves are available this is indicated by value and coordinates in the array
3763 * being -1.
3764 *
3765 * This function automatically initializes the owl_safe_move cache the
3766 * pattern list. WATCH OUT: This has to be matched with a call to
3767 * close_pattern_list(pattern_list)!!!
3768 *
3769 * Returns 1 if at least one move is found, or 0 if no move is found.
3770 */
3771
3772static void
3773owl_shapes(struct matched_patterns_list_data *pattern_list,
3774 struct owl_move_data moves[MAX_MOVES],
3775 int color, struct local_owl_data *owl, struct pattern_db *type)
3776{
3777 SGFTree *save_sgf_dumptree = sgf_dumptree;
3778 int save_count_variations = count_variations;
3779 sgf_dumptree = NULL;
3780 count_variations = 0;
3781
3782 current_owl_data = owl;
3783
3784 clear_owl_move_data(moves);
3785
3786 /* We must reset the owl safe_move_cache before starting the
3787 * pattern matching. The cache is used by owl_shapes_callback().
3788 */
3789 memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache));
3790 init_pattern_list(pattern_list);
3791 matchpat(collect_owl_shapes_callbacks, color, type, pattern_list, owl->goal);
3792
3793 sgf_dumptree = save_sgf_dumptree;
3794 count_variations = save_count_variations;
3795}
3796
3797
3798/* This function contains all the expensive checks for a matched pattern. */
3799static int
3800check_pattern_hard(int move, int color, struct pattern *pattern, int ll)
3801{
3802 int constraint_checked = 0;
3803 int safe_move_checked = 0;
3804
3805 /* The very first check is whether we can disregard the pattern due
3806 * due to an owl safe_move_cache lookup.
3807 */
3808 if (!(pattern->class & CLASS_s))
3809 if (current_owl_data->safe_move_cache[move]) {
3810 if (current_owl_data->safe_move_cache[move] == 1)
3811 return 0;
3812 else
3813 safe_move_checked = 1;
3814 }
3815
3816 /* If the constraint is cheap to check, we do this first. */
3817 if ((pattern->autohelper_flag & HAVE_CONSTRAINT)
3818 && pattern->constraint_cost < 0.45) {
3819 if (!pattern->autohelper(ll, move, color, 0))
3820 return 0;
3821 constraint_checked = 1;
3822 }
3823
3824 /* For sacrifice patterns, the survival of the stone to be played is
3825 * not checked. Otherwise we discard moves which can be captured.
3826 * Illegal ko captures are accepted for ko analysis.
3827 */
3828 if (!(pattern->class & CLASS_s) && !safe_move_checked) {
3829 if (!owl_safe_move(move, color)) {
3830 if (0)
3831 TRACE(" move at %1m wasn't safe, discarded\n", move);
3832 return 0;
3833 }
3834 if (!is_legal(move, color)) {
3835 if (0)
3836 TRACE(" move at %1m wasn't legal, discarded\n", move);
3837 return 0;
3838 }
3839 }
3840
3841 /* For class n patterns, the pattern is contingent on an opponent
3842 * move at * not being captured.
3843 *
3844 * We can't use owl_safe_move() here because we would try the wrong color.
3845 */
3846 if (pattern->class & CLASS_n) {
3847 if (safe_move(move, OTHER_COLOR(color)) == 0) {
3848 if (0)
3849 TRACE(" opponent can't play safely at %1m, move discarded\n", move);
3850 return 0;
3851 }
3852 }
3853
3854 /* If the pattern has a constraint, call the autohelper to see
3855 * if the pattern must be rejected.
3856 */
3857 if ((pattern->autohelper_flag & HAVE_CONSTRAINT) && !constraint_checked)
3858 if (!pattern->autohelper(ll, move, color, 0))
3859 return 0;
3860 return 1;
3861}
3862
3863
3864/* This initializes a pattern list, allocating memory for 200 patterns.
3865 * If more patterns need to be stored, collect_owl_shapes_callbacks will
3866 * dynamically reallocate additional memory.
3867 * The space for list->pattern_list is allocated here.
3868 *
3869 * This function is automatically called from owl_shapes. Every call here
3870 * has to be matched by a call to close_pattern_list below.
3871 */
3872static void
3873init_pattern_list(struct matched_patterns_list_data *list)
3874{
3875 gg_assert(!list->initialized);
3876
3877 list->counter = 0;
3878 list->used = 0;
3879
3880 list->pattern_list = malloc(200 * sizeof(list->pattern_list[0]));
3881 list->list_size = 200;
3882 gg_assert(list->pattern_list != NULL);
3883 list->pattern_heap = NULL;
3884
3885 if (0)
3886 gprintf("List at %x has new array at %x\n", list, list->pattern_list);
3887
3888 list->initialized = 1;
3889}
3890
3891
3892/* This function has to get called before the memory of *list is freed
3893 * in the calling function.
3894 */
3895static void
3896close_pattern_list(int color, struct matched_patterns_list_data *list)
3897{
3898 if (list->initialized) {
3899 if (0)
3900 gprintf("%d patterns matched, %d patterns checked\n", list->counter,
3901 list->used);
3902 if (0)
3903 gprintf("Pattern list at %x freed for list at %x\n",
3904 list->pattern_list, list);
3905 if (allpats && verbose) {
3906 int i;
3907 int found_one = 0;
3908 SGFTree *save_sgf_dumptree = sgf_dumptree;
3909 int save_count_variations = count_variations;
3910 sgf_dumptree = NULL;
3911 count_variations = 0;
3912
3913 if (!current_owl_data->lunches_are_current)
3914 owl_find_lunches(current_owl_data);
3915
3916 if (!list->pattern_heap)
3917 pattern_list_build_heap(list);
3918
3919 for (i = 0; i < list->heap_num_patterns; i++)
3920 if (check_pattern_hard(list->pattern_heap[i]->move, color,
3921 list->pattern_heap[i]->pattern,
3922 list->pattern_heap[i]->ll)) {
3923 if (!found_one) {
3924 TRACE("Remaining valid (but unused) patterns at stack: ");
3925 dump_stack();
3926 found_one = 1;
3927 }
3928 TRACE("Pattern %s found at %1m with value %d\n",
3929 list->pattern_heap[i]->pattern->name,
3930 list->pattern_heap[i]->move,
3931 (int) list->pattern_heap[i]->pattern->value);
3932 }
3933
3934 sgf_dumptree = save_sgf_dumptree;
3935 count_variations = save_count_variations;
3936 }
3937
3938 free(list->pattern_list);
3939 free(list->pattern_heap);
3940 }
3941 list->counter = -1;
3942}
3943
3944
3945/* Can be called from gdb for debugging:
3946 * (gdb) set dump_pattern_list(&shape_patterns)
3947 */
3948void
3949dump_pattern_list(struct matched_patterns_list_data *list)
3950{
3951 int i;
3952 struct matched_pattern_data *matched_pattern;
3953 if (!list->initialized)
3954 return;
3955 gprintf("%oList size %d. %d Patterns in list, %d have been used.",
3956 list->list_size, list->counter, list->used);
3957 for (i = 0; i < list->counter; i++) {
3958 matched_pattern = &list->pattern_list[i];
3959 gprintf("%o\n Pattern %s (orient. %d) at %1m, value %f.",
3960 matched_pattern->pattern->name, matched_pattern->ll,
3961 matched_pattern->move, matched_pattern->pattern->value);
3962 if (matched_pattern->next_pattern_index != -1)
3963 gprintf("%o * ");
3964 }
3965 gprintf("%o\n");
3966
3967 gprintf("%oCurrent heap ordering: \n");
3968 for (i = 0; i < list->heap_num_patterns; i++) {
3969 matched_pattern = list->pattern_heap[i];
3970 gprintf("%o %s (%1m), %f; ", matched_pattern->pattern->name,
3971 matched_pattern->move, matched_pattern->pattern->value);
3972 }
3973 gprintf("\n");
3974}
3975
3976
3977/* This function stores a found pattern in the list for later evaluation.
3978 * The only processing done is computing the position of the move, and
3979 * forgetting the color.
3980 */
3981static void
3982collect_owl_shapes_callbacks(int anchor, int color, struct pattern *pattern,
3983 int ll, void *data)
3984{
3985 struct matched_patterns_list_data *matched_patterns = data;
3986 struct matched_pattern_data *next_pattern;
3987
3988 UNUSED(color); /* The calling function has to remember that. */
3989
3990 if (matched_patterns->counter >= matched_patterns->list_size) {
3991 matched_patterns->list_size += 100;
3992 matched_patterns->pattern_list
3993 = realloc(matched_patterns->pattern_list,
3994 matched_patterns->list_size
3995 * sizeof(matched_patterns->pattern_list[0]));
3996 }
3997
3998 next_pattern = &matched_patterns->pattern_list[matched_patterns->counter];
3999 next_pattern->move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
4000 next_pattern->value = pattern->value;
4001 next_pattern->ll = ll;
4002 next_pattern->anchor = anchor;
4003 next_pattern->pattern = pattern;
4004 next_pattern->next_pattern_index = -1;
4005
4006 matched_patterns->counter++;
4007}
4008
4009
4010#define MAX_STORED_REASONS 4
4011
4012static int
4013valuate_combinable_pattern_chain(struct matched_patterns_list_data *list,
4014 int pos)
4015{
4016 /* FIXME: This is just a first attempt at pattern combination.
4017 * Improve it. The first idea is to differentiate between
4018 * move reason types. For instance, when there is a secure
4019 * eye already, a threat to create another is more severe.
4020 *
4021 * This will certainly involve splitting the function into
4022 * attack and defense versions.
4023 */
4024
4025 int pattern_index = list->first_pattern_index[pos];
4026 int num_capture_threats = 0;
4027 int capture_threats[MAX_STORED_REASONS];
4028 int num_eye_threats = 0;
4029 int eye_threats[MAX_STORED_REASONS];
4030 int num_reverse_sente = 0;
4031 int reverse_sente_against[MAX_STORED_REASONS];
4032 int num_move_reasons;
4033 float full_value = 0.0;
4034
4035 ASSERT1(pattern_index != -1, pos);
4036
4037 do {
4038 struct matched_pattern_data *pattern_data = (list->pattern_list
4039 + pattern_index);
4040 struct pattern_attribute *attribute;
4041
4042 /* Skip patterns that haven't passed constraint validation. */
4043 if (pattern_data->pattern) {
4044 for (attribute = pattern_data->pattern->attributes;
4045 attribute->type != LAST_ATTRIBUTE;
4046 attribute++) {
4047 int k;
4048 int target = AFFINE_TRANSFORM(attribute->offset, pattern_data->ll,
4049 pattern_data->move);
4050
4051 switch (attribute->type) {
4052 case THREATENS_TO_CAPTURE:
4053 if (num_capture_threats < MAX_STORED_REASONS) {
4054 ASSERT1(IS_STONE(board[target]), target);
4055 target = find_origin(target);
4056
4057 for (k = 0; k < num_capture_threats; k++) {
4058 if (capture_threats[k] == target)
4059 break;
4060 }
4061
4062 if (k == num_capture_threats) {
4063 capture_threats[num_capture_threats++] = target;
4064 full_value += pattern_data->pattern->value;
4065 }
4066 }
4067
4068 break;
4069
4070 case THREATENS_EYE:
4071 if (num_eye_threats < MAX_STORED_REASONS) {
4072 target = current_owl_data->my_eye[target].origin;
4073
4074 for (k = 0; k < num_eye_threats; k++) {
4075 if (eye_threats[k] == target)
4076 break;
4077 }
4078
4079 if (k == num_eye_threats) {
4080 eye_threats[num_eye_threats++] = target;
4081 full_value += pattern_data->pattern->value;
4082 }
4083 }
4084
4085 break;
4086
4087 case REVERSE_SENTE:
4088 if (num_reverse_sente < MAX_STORED_REASONS) {
4089 ASSERT1(board[target] == EMPTY, target);
4090
4091 for (k = 0; k < num_reverse_sente; k++) {
4092 if (reverse_sente_against[k] == target)
4093 break;
4094 }
4095
4096 if (k == num_reverse_sente) {
4097 reverse_sente_against[num_reverse_sente++] = target;
4098 full_value += pattern_data->pattern->value;
4099 }
4100 }
4101
4102 break;
4103
4104 default:
4105 gg_assert(0);
4106 }
4107 }
4108 }
4109
4110 pattern_index = pattern_data->next_pattern_index;
4111 } while (pattern_index >= 0);
4112
4113
4114 num_move_reasons = num_capture_threats + num_eye_threats + num_reverse_sente;
4115 if (num_move_reasons <= 1) {
4116 /* Not much to combine, eh? */
4117 return 0;
4118 }
4119
4120 if (num_move_reasons == 2)
4121 return gg_min(gg_normalize_float2int(full_value, 1.0), 75);
4122 if (num_move_reasons == 3)
4123 return gg_min(gg_normalize_float2int(full_value * 0.85, 1.0), 90);
4124 return gg_min(gg_normalize_float2int(full_value * 0.75, 1.0), 99);
4125}
4126
4127
4128#if USE_BDIST
4129
4130/* Compute the squared of the distance of a point on the board to the
4131 * center of the board.
4132 */
4133static int
4134bdist(int move)
4135{
4136 /* i = 0: idist = - (board_size - 1)
4137 * i = board_size -1 : idist = board_size - 1
4138 */
4139 int idist = 2*I(move) - board_size + 1;
4140 int jdist = 2*J(move) - board_size + 1;
4141 return idist*idist + jdist*jdist;
4142}
4143
4144
4145/* NOTICE : In order to stabilize the regression test results,
4146 * arbitrary parameters like pattern memory address and move position
4147 * have been included in the sorting algorithm.
4148 */
4149
4150#define BETTER_PATTERN(a, b) \
4151 ((a)->value > (b)->value \
4152 || ((a)->value == (b)->value \
4153 && ((a)->pattern < (b)->pattern \
4154 || ((a)->pattern == (b)->pattern \
4155 && ((a)->bdist < (b)->bdist \
4156 || ((a)->bdist == (b)->bdist \
4157 && (a)->move < (b)->move))))))
4158
4159#else /* not USE_BDIST */
4160
4161#define BETTER_PATTERN(a, b) \
4162 ((a)->value > (b)->value \
4163 || ((a)->value == (b)->value \
4164 && ((a)->pattern < (b)->pattern \
4165 || ((a)->pattern == (b)->pattern \
4166 && (a)->move < (b)->move))))
4167
4168#endif /* not USE_BDIST */
4169
4170
4171static void
4172pattern_list_prepare(struct matched_patterns_list_data *list)
4173{
4174 int k;
4175 int pos;
4176
4177 list->heap_num_patterns = 0;
4178
4179 /* This is more than needed in case of (combinable) pattern chains,
4180 * but it is easier to allocate more than to count real number of
4181 * heap elements first.
4182 */
4183 if (list->counter > 0) { /* avoid malloc(0) */
4184 list->pattern_heap = malloc(list->counter * sizeof(*(list->pattern_heap)));
4185 gg_assert(list->pattern_heap != NULL);
4186 }
4187 else {
4188 /* free() has defined behaviour for NULL pointer */
4189 list->pattern_heap = NULL;
4190 }
4191
4192 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
4193 list->first_pattern_index[pos] = -1;
4194
4195 for (k = 0; k < list->counter; k++) {
4196 int move = list->pattern_list[k].move;
4197
4198#if USE_BDIST
4199 list->pattern_list[k].bdist = bdist(move);
4200#endif
4201
4202 /* Allocate heap elements for normal patterns. Link combinable
4203 * patterns in chains.
4204 */
4205 if (!(list->pattern_list[k].pattern->class & CLASS_c))
4206 list->pattern_heap[list->heap_num_patterns++] = &list->pattern_list[k];
4207 else {
4208 list->pattern_list[k].next_pattern_index = list->first_pattern_index[move];
4209 list->first_pattern_index[move] = k;
4210 }
4211 }
4212
4213 /* Allocate one heap element for each chain of combinable patterns
4214 * and calculate initial chain values (as if all patterns passed
4215 * constraint validation).
4216 */
4217 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
4218 if (list->first_pattern_index[pos] != -1) {
4219 struct matched_pattern_data *pattern_data
4220 = &list->pattern_list[list->first_pattern_index[pos]];
4221
4222 pattern_data->value = valuate_combinable_pattern_chain(list, pos);
4223 list->pattern_heap[list->heap_num_patterns++] = pattern_data;
4224 }
4225 }
4226
4227 if (list->heap_num_patterns > 0)
4228 pattern_list_build_heap(list);
4229}
4230
4231
4232/* Fast heap building. Takes O(n) only. */
4233static void
4234pattern_list_build_heap(struct matched_patterns_list_data *list)
4235{
4236 int k;
4237 int limit = list->heap_num_patterns / 2;
4238
4239 for (k = limit; --k >= 0;) {
4240 int parent;
4241 int child;
4242 struct matched_pattern_data *pattern_data = list->pattern_heap[k];
4243
4244 for (parent = k; parent < limit; parent = child) {
4245 child = 2 * parent + 1;
4246 if (child + 1 < list->heap_num_patterns
4247 && BETTER_PATTERN(list->pattern_heap[child + 1],
4248 list->pattern_heap[child]))
4249 child++;
4250
4251 if (BETTER_PATTERN(pattern_data, list->pattern_heap[child]))
4252 break;
4253
4254 list->pattern_heap[parent] = list->pattern_heap[child];
4255 }
4256
4257 list->pattern_heap[parent] = pattern_data;
4258 }
4259}
4260
4261
4262/* Pops patterns list's heap once. */
4263static void
4264pattern_list_pop_heap_once(struct matched_patterns_list_data *list)
4265{
4266 int parent;
4267 int child;
4268
4269 list->heap_num_patterns--;
4270 for (parent = 0; 2 * parent + 1 < list->heap_num_patterns; parent = child) {
4271 child = 2 * parent + 1;
4272 if (BETTER_PATTERN(list->pattern_heap[child + 1],
4273 list->pattern_heap[child]))
4274 child++;
4275
4276 if (BETTER_PATTERN(list->pattern_heap[list->heap_num_patterns],
4277 list->pattern_heap[child]))
4278 break;
4279
4280 list->pattern_heap[parent] = list->pattern_heap[child];
4281 }
4282
4283 list->pattern_heap[parent] = list->pattern_heap[list->heap_num_patterns];
4284}
4285
4286
4287/* Sink top element of heap because it got devalued. This happens
4288 * when a combinable pattern doesn't pass check_pattern_hard() -- it
4289 * is no longer counted and its whole chain's value is reduced.
4290 */
4291static void
4292pattern_list_sink_heap_top_element(struct matched_patterns_list_data *list)
4293{
4294 int parent;
4295 int child;
4296 struct matched_pattern_data *heap_top_element = list->pattern_heap[0];
4297
4298 for (parent = 0; 2 * parent + 1 < list->heap_num_patterns; parent = child) {
4299 child = 2 * parent + 1;
4300 if (child + 1 < list->heap_num_patterns
4301 && BETTER_PATTERN(list->pattern_heap[child + 1],
4302 list->pattern_heap[child]))
4303 child++;
4304
4305 if (BETTER_PATTERN(heap_top_element,
4306 list->pattern_heap[child]))
4307 break;
4308
4309 list->pattern_heap[parent] = list->pattern_heap[child];
4310 }
4311
4312 list->pattern_heap[parent] = heap_top_element;
4313}
4314
4315
4316/* Adds all goal strings in the pattern area to the cuts[] list, if there
4317 * is more than one.
4318 */
4319static void
4320generate_cut_list(struct pattern *pattern, int ll, int anchor,
4321 int cuts[MAX_CUTS], struct local_owl_data *owl)
4322{
4323 int k;
4324 int num = 0;
4325 signed char mark[BOARDMAX];
4326
4327 memset(mark, 0, BOARDMAX);
4328 for (k = 0; k < pattern->patlen; k++) {
4329 int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
4330 if (!IS_STONE(board[pos]))
4331 continue;
4332 pos = find_origin(pos);
4333 if (!mark[pos] && board[pos] == owl->color && owl->goal[pos]) {
4334 cuts[num++] = pos;
4335 mark[pos] = 1;
4336 if (num == MAX_CUTS)
4337 return;
4338 }
4339 }
4340 if (num == 1)
4341 cuts[0] = NO_MOVE;
4342 else if ((debug & DEBUG_SPLIT_OWL) && num > 1)
4343 gprintf("Move provokes %d cuts, among them %1m and %1m.\n", num,
4344 cuts[0], cuts[1]);
4345}
4346
4347/* This function searches in the previously stored list of matched
4348 * patterns for the highest valued unused patterns that have a valid
4349 * constraint. It returns the moves at the next empty positions in
4350 * the array moves[]. Empty positions in the moves array are marked
4351 * by having value <= 0. There must be enough empty positions in the
4352 * list.
4353 *
4354 * If the highest valued pattern found has a value less than cutoff,
4355 * no move is returned. Returns 1 if a move is found, 0 otherwise.
4356 *
4357 * This function also dispatches constraint validation of combinable
4358 * pattern chains. Whenever a pattern from a chain fails constraints,
4359 * the chain is reevaluated and most likely drops in value enough to
4360 * let other patterns (or chains) climb to the top of pattern heap.
4361 *
4362 * This function loops until enough moves are found or the end of the
4363 * list is reached.
4364 */
4365
4366static int
4367get_next_move_from_list(struct matched_patterns_list_data *list, int color,
4368 struct owl_move_data *moves, int cutoff,
4369 struct local_owl_data *owl)
4370{
4371 int move_found = 0;
4372 SGFTree *save_sgf_dumptree = sgf_dumptree;
4373 int save_count_variations = count_variations;
4374
4375 sgf_dumptree = NULL;
4376 count_variations = 0;
4377
4378 /* Prepare pattern list if needed. */
4379 if (!list->pattern_heap)
4380 pattern_list_prepare(list);
4381
4382 while (list->heap_num_patterns > 0) {
4383 int k;
4384 struct matched_pattern_data *pattern_data;
4385 struct pattern *pattern;
4386 int move;
4387 int value;
4388 int ll;
4389 int anchor;
4390 int next_pattern_index;
4391
4392 /* Peek top element of heap associated with pattern list. */
4393 if (list->pattern_heap[0]->value < cutoff)
4394 break;
4395
4396 pattern_data = list->pattern_heap[0];
4397 pattern = list->pattern_heap[0]->pattern;
4398 move = list->pattern_heap[0]->move;
4399 value = list->pattern_heap[0]->value;
4400 ll = list->pattern_heap[0]->ll;
4401 anchor = list->pattern_heap[0]->anchor;
4402 next_pattern_index = list->pattern_heap[0]->next_pattern_index;
4403
4404 list->used++;
4405
4406 ASSERT_ON_BOARD1(move);
4407 for (k = 0; k < MAX_MOVES; k++) {
4408 if (moves[k].pos == move || moves[k].value <= 0)
4409 break;
4410 }
4411
4412 if (moves[k].pos == move) {
4413 /* No point in testing this pattern/chain. Throw it out. */
4414 pattern_list_pop_heap_once(list);
4415 continue;
4416 }
4417
4418 /* There has to be an empty space. */
4419 gg_assert(k < MAX_MOVES);
4420
4421 /* If a pattern chain was devalued because its last pattern didn't
4422 * pass constraint validation, `pattern' is set NULL (i.e. nothing
4423 * more to test). Note that devalued chains might still be
4424 * useful, i.e. if 2 of 3 patterns passed check_pattern_hard().
4425 */
4426 if (pattern == NULL
4427 || check_pattern_hard(move, color, pattern, ll)) {
4428 if (next_pattern_index == -1) {
4429 /* Normal pattern or last one in a chain. */
4430 pattern_list_pop_heap_once(list);
4431 }
4432 else {
4433 /* We just validated a non-last pattern in a chain. Since the
4434 * chain remains at the same value, we keep the heap structure
4435 * untouched. However, we need to set heap's top to point to
4436 * next pattern of the chain.
4437 */
4438 list->pattern_heap[0] = list->pattern_list + next_pattern_index;
4439 list->pattern_heap[0]->value = value;
4440 continue;
4441 }
4442
4443 moves[k].pos = move;
4444 moves[k].value = value;
4445 clear_cut_list(moves[k].cuts);
4446 move_found = 1;
4447
4448 if (pattern && !(pattern->class & CLASS_c)) {
4449 moves[k].name = pattern->name;
4450 TRACE("Pattern %s found at %1m with value %d\n",
4451 pattern->name, move, moves[k].value);
4452
4453 if (pattern->class & CLASS_C) {
4454 /* Cut possible. (Only used in attack patterns). Try to find
4455 * goal strings in the pattern area and store them in the cut list
4456 * if there is more than one.
4457 */
4458 DEBUG(DEBUG_SPLIT_OWL,
4459 "Generating cut list for move at %1m.\n", move);
4460 generate_cut_list(pattern, ll, anchor, moves[k].cuts, owl);
4461 }
4462
4463 if (pattern->class & CLASS_B)
4464 moves[k].same_dragon = SAME_DRAGON_NOT_CONNECTED;
4465 else if (pattern->class & CLASS_a) {
4466 moves[k].same_dragon = SAME_DRAGON_ALL_CONNECTED;
4467 moves[k].pattern_data = pattern_data;
4468 }
4469 else if (!(pattern->class & CLASS_b))
4470 moves[k].same_dragon = SAME_DRAGON_CONNECTED;
4471 else {
4472 int i;
4473 enum same_dragon_value same_dragon = SAME_DRAGON_MAYBE_CONNECTED;
4474
4475 /* If we do not yet know whether the move belongs to the
4476 * same dragon, we see whether another pattern can clarify.
4477 */
4478 for (i = 0; i < list->heap_num_patterns; i++) {
4479 pattern_data = list->pattern_heap[i];
4480
4481 if (pattern_data->pattern
4482 && pattern_data->move == move
4483 && ((pattern_data->pattern->class & CLASS_B)
4484 || !(pattern_data->pattern->class & CLASS_b))) {
4485 if (check_pattern_hard(move, color, pattern_data->pattern,
4486 pattern_data->ll)) {
4487 TRACE("Additionally pattern %s found at %1m\n",
4488 pattern_data->pattern->name, move);
4489 if (pattern_data->pattern->class & CLASS_B)
4490 same_dragon = SAME_DRAGON_NOT_CONNECTED;
4491 else if (pattern_data->pattern->class & CLASS_a) {
4492 same_dragon = SAME_DRAGON_ALL_CONNECTED;
4493 moves[k].pattern_data = pattern_data;
4494 }
4495 else
4496 same_dragon = SAME_DRAGON_CONNECTED;
4497
4498 break;
4499 }
4500 }
4501 }
4502
4503 moves[k].same_dragon = same_dragon;
4504 }
4505 }
4506 else {
4507 moves[k].name = "Pattern combination";
4508 if (verbose) {
4509 /* FIXME: write names of all patterns in chain. */
4510 }
4511
4512 /* FIXME: Add handling of CLASS_b.
4513 *
4514 * FIXME: It is silently assumed that all patterns in the
4515 * chain have the same class. When the last pattern in
4516 * chain didn't match, this will not work at all.
4517 */
4518 if (pattern && pattern->class & CLASS_B)
4519 moves[k].same_dragon = SAME_DRAGON_NOT_CONNECTED;
4520 else if (pattern && pattern->class & CLASS_a) {
4521 moves[k].same_dragon = SAME_DRAGON_ALL_CONNECTED;
4522 moves[k].pattern_data = list->pattern_heap[0];
4523 }
4524 else
4525 moves[k].same_dragon = SAME_DRAGON_CONNECTED;
4526 }
4527
4528 if (pattern && pattern->class & CLASS_E)
4529 moves[k].escape = 1;
4530 else
4531 moves[k].escape = 0;
4532
4533 break;
4534 }
4535 else { /* !check_pattern_hard(...) */
4536 if (!(pattern->class & CLASS_c)) {
4537 /* Just forget about it. */
4538 pattern_list_pop_heap_once(list);
4539 }
4540 else {
4541 /* Set this pattern to not matched and advance to next one in
4542 * the chain, if any.
4543 */
4544 list->pattern_heap[0]->pattern = NULL;
4545 if (next_pattern_index != -1)
4546 list->pattern_heap[0] = list->pattern_list + next_pattern_index;
4547
4548 /* Reevaluate chain and adjust heap structure accordingly. */
4549 list->pattern_heap[0]->value = valuate_combinable_pattern_chain(list,
4550 move);
4551 pattern_list_sink_heap_top_element(list);
4552 }
4553 }
4554 }
4555
4556 sgf_dumptree = save_sgf_dumptree;
4557 count_variations = save_count_variations;
4558
4559 return move_found;
4560}
4561
4562
4563/* This function takes an array of already found moves (passed as
4564 * 'data') and looks for moves to replace these. Only moves near
4565 * the goal dragon are considered.
4566 */
4567static void
4568owl_shapes_callback(int anchor, int color, struct pattern *pattern,
4569 int ll, void *data)
4570{
4571 int tval; /* trial move and its value */
4572 int move;
4573 struct owl_move_data *moves = data; /* considered moves passed as data */
4574 enum same_dragon_value same_dragon = SAME_DRAGON_MAYBE_CONNECTED;
4575 int escape = 0;
4576 int defense_pos;
4577
4578 /* Pick up the location of the move */
4579 move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
4580
4581 /* Before we do any expensive reading, check whether this move
4582 * already is known with a higher value or if there are too many
4583 * other moves with higher value.
4584 */
4585 if (!allpats) {
4586 int k;
4587 for (k = 0; k < MAX_MOVES; k++) {
4588 if (moves[k].value == -1)
4589 break;
4590 if (moves[k].pos == move) {
4591 if (moves[k].value >= pattern->value)
4592 return;
4593 else
4594 break;
4595 }
4596 }
4597 if (k == MAX_MOVES && moves[MAX_MOVES - 1].value >= pattern->value)
4598 return;
4599 }
4600
4601 if (!check_pattern_hard(move, color, pattern, ll))
4602 return;
4603
4604 /* and work out the value of this move */
4605 if (pattern->helper) {
4606 /* ask helper function to consider the move */
4607 gg_assert(0);
4608 DEBUG(DEBUG_HELPER, " asking helper to consider '%s'+%d at %1m\n",
4609 pattern->name, ll, move);
4610 tval = pattern->helper(pattern, ll, move, color);
4611
4612 if (tval > 0) {
4613 DEBUG(DEBUG_HELPER, "helper likes pattern '%s' value %d at %1m\n",
4614 pattern->name, tval, move);
4615 }
4616 else {
4617 DEBUG(DEBUG_HELPER, " helper does not like pattern '%s' at %1m\n",
4618 pattern->name, move);
4619 return; /* pattern matcher does not like it */
4620 }
4621 }
4622 else { /* no helper */
4623 tval = (int) pattern->value;
4624 }
4625
4626 /* having made it here, we have made it through all the extra checks */
4627
4628 TRACE("Pattern %s found at %1m with value %d\n", pattern->name, move, tval);
4629
4630 if (pattern->class & CLASS_B)
4631 same_dragon = SAME_DRAGON_NOT_CONNECTED;
4632 else if (pattern->class & CLASS_b)
4633 same_dragon = SAME_DRAGON_MAYBE_CONNECTED;
4634 else if (pattern->class & CLASS_a) {
4635 same_dragon = SAME_DRAGON_ALL_CONNECTED;
4636 /* FIXME: Currently this code is only used with vital attack
4637 * moves, so there is no use for the "a" classification. If it
4638 * would be needed in the future it's necessary to set up a struct
4639 * matched_pattern_data here to be passed to owl_add_move(). This
4640 * is not all that simple with respect to memory management
4641 * however. Notice that a local variable in this function would go
4642 * out of scope too early.
4643 */
4644 gg_assert(0);
4645 }
4646 else
4647 same_dragon = SAME_DRAGON_CONNECTED;
4648
4649 if (pattern->class & CLASS_E)
4650 escape = 1;
4651 else
4652 escape = 0;
4653
4654 /* Finally, check for position of defense move. */
4655 {
4656 int k;
4657 defense_pos = move;
4658 for (k = 0; k < pattern->patlen; k++)
4659 if (pattern->patn[k].att == ATT_not)
4660 defense_pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
4661 }
4662
4663 owl_add_move(moves, move, tval, pattern->name, same_dragon, NO_MOVE,
4664 escape, defense_pos, MAX_MOVES, NULL);
4665}
4666
4667
4668/* Add a move to the list of candidate moves */
4669
4670static void
4671owl_add_move(struct owl_move_data *moves, int move, int value,
4672 const char *reason, enum same_dragon_value same_dragon, int lunch,
4673 int escape, int defense_pos, int max_moves,
4674 struct matched_pattern_data *pattern_data)
4675{
4676 int k;
4677
4678 if (!found_matches[move]) {
4679 found_matches[move] = 1;
4680 matches_found++;
4681 }
4682
4683 /* Add the new move to the list of already found moves, if the value
4684 * is sufficently large. We keep the list sorted.
4685 *
4686 * First we must see if this move already is in the list.
4687 */
4688 for (k = 0; k < max_moves; k++) {
4689 if (moves[k].value == -1)
4690 break;
4691 if (moves[k].pos == move) {
4692 if (same_dragon > moves[k].same_dragon) {
4693 moves[k].same_dragon = same_dragon;
4694 moves[k].pattern_data = pattern_data;
4695 }
4696 if (!moves[k].escape)
4697 escape = 0;
4698 break;
4699 }
4700 }
4701
4702 /* Did we already have this move in the list with a higher value? */
4703 if (k < max_moves && moves[k].value >= value)
4704 return;
4705
4706 /* Insert the move at the right place in the list and adjust other
4707 * entries as needed.
4708 */
4709 for (; k >= 0; k--) {
4710 if (k == 0 || value <= moves[k-1].value) {
4711 /* Can't get higher. Insert the move below this point and quit
4712 * looping.
4713 */
4714 if (k < max_moves) {
4715 moves[k].pos = move;
4716 moves[k].value = value;
4717 moves[k].name = reason;
4718 /* If B or b class pattern, this move shouldn't be added to the
4719 * dragon under consideration.
4720 */
4721 moves[k].same_dragon = same_dragon;
4722 moves[k].pattern_data = pattern_data;
4723 moves[k].lunch = lunch;
4724 moves[k].escape = escape;
4725 moves[k].defense_pos = defense_pos;
4726 }
4727 break;
4728 }
4729 /* Shuffle the passed move one step downwards. */
4730 if (k < max_moves)
4731 moves[k] = moves[k-1]; /* struct copy */
4732 }
4733
4734 /* Assert that the list contains unique moves. */
4735 if (0) {
4736 int l;
4737 for (k = 0; k < max_moves; k++)
4738 for (l = k+1; l < max_moves; l++)
4739 gg_assert(moves[k].pos == 0
4740 || moves[k].pos != moves[l].pos);
4741 }
4742}
4743
4744
4745/* Marks the dragons at apos and bpos. If only one dragon
4746 * needs marking, bpos should be passed as NO_MOVE.
4747 */
4748
4749static void
4750owl_mark_dragon(int apos, int bpos, struct local_owl_data *owl,
4751 int new_dragons[BOARDMAX])
4752{
4753 int pos;
4754 int color = board[apos];
4755
4756 ASSERT1(bpos == NO_MOVE || board[bpos] == color, bpos);
4757
4758 if (new_dragons == NULL) {
4759 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
4760 if (ON_BOARD(pos)) {
4761 if (is_same_dragon(pos, apos) || is_same_dragon(pos, bpos))
4762 owl->goal[pos] = 1;
4763 else
4764 owl->goal[pos] = 0;
4765 }
4766 }
4767 else {
4768 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
4769 if (ON_BOARD(pos)) {
4770 if (IS_STONE(board[pos])
4771 && (new_dragons[pos] == new_dragons[apos]
4772 || new_dragons[pos] == new_dragons[bpos]))
4773 owl->goal[pos] = 1;
4774 else
4775 owl->goal[pos] = 0;
4776 }
4777 }
4778
4779 memcpy(owl->cumulative_goal, owl->goal, sizeof(owl->goal));
4780 owl->color = color;
4781 owl_mark_boundary(owl);
4782}
4783
4784
4785/* Marks the worms at apos and bpos. If only one worm
4786 * needs marking, bpos should be passed as NO_MOVE.
4787 */
4788
4789static void
4790owl_mark_worm(int apos, int bpos, struct local_owl_data *owl)
4791{
4792 int pos;
4793 int color = board[apos];
4794
4795 ASSERT1(bpos == NO_MOVE || board[bpos] == color, bpos);
4796
4797 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
4798 if (ON_BOARD(pos)) {
4799 if (is_same_worm(pos, apos) || is_same_worm(pos, bpos))
4800 owl->goal[pos] = 1;
4801 else
4802 owl->goal[pos] = 0;
4803 }
4804
4805 owl->color = color;
4806}
4807
4808
4809/* Mark the boundary strings of the dragon. A boundary string is marked 2
4810 * if it adjoins a friendly live dragon, 1 otherwise.
4811 */
4812
4813static void
4814owl_mark_boundary(struct local_owl_data *owl)
4815{
4816 int k;
4817 int pos;
4818 int color = owl->color;
4819 int other = OTHER_COLOR(color);
4820
4821 memset(owl->boundary, 0, sizeof(owl->boundary));
4822 memset(owl->neighbors, 0, sizeof(owl->neighbors));
4823
4824 /* Find all friendly neighbors of the dragon in goal. */
4825 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
4826 if (board[pos] == color && owl->goal[pos]) {
4827 for (k = 0; k < 4; k++) {
4828 if (board[pos + delta[k]] == EMPTY
4829 && board[pos + 2 * delta[k]] == color
4830 && !owl->neighbors[pos + 2 * delta[k]])
4831 mark_string(pos + 2 * delta[k], owl->neighbors, 1);
4832 }
4833
4834 for (; k < 8; k++) {
4835 int pos2 = pos + delta[k];
4836
4837 if (board[pos2] == color
4838 && !owl->neighbors[pos2]
4839 && (board[SOUTH(gg_min(pos, pos2))] == EMPTY
4840 || board[NORTH(gg_max(pos, pos2))] == EMPTY))
4841 mark_string(pos2, owl->neighbors, 1);
4842 }
4843 }
4844 }
4845
4846 /* First find all boundary strings (including those adjacent not to
4847 * the goal dragon, but one of its neighbors).
4848 */
4849 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
4850 if (board[pos] == other && !owl->boundary[pos]) {
4851 for (k = 0; k < 8; k++)
4852 if (ON_BOARD(pos + delta[k])
4853 && (owl->goal[pos + delta[k]] || owl->neighbors[pos + delta[k]])) {
4854 mark_string(pos, owl->boundary, 1);
4855 break;
4856 }
4857 }
4858
4859 /* Upgrade the mark of a boundary string if it adjoins a safe
4860 * friendly dragon.
4861 */
4862 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
4863 if (owl->boundary[pos] == 1) {
4864 for (k = 0; k < 8; k++) {
4865 int pos2 = pos + delta[k];
4866 if (board[pos2] == color
4867 && !owl->goal[pos2]
4868 && !owl->neighbors[pos2]
4869 && ((dragon[pos2].crude_status != DEAD && countstones(pos2) > 2)
4870 || dragon[pos2].crude_status == ALIVE)) {
4871 mark_string(pos, owl->boundary, 2);
4872 break;
4873 }
4874 }
4875 }
4876
4877 /* During the owl reading, stones farther away may become parts of
4878 * the boundary. We mark those strings neighboring some other
4879 * friendly dragon with boundary value 2 right away, since we have
4880 * no mechanism for detecting this later.
4881 */
4882 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
4883 if (board[pos] == other && owl->boundary[pos] == 0) {
4884 /* If a lunch has been amalgamated into a larger dragon, we
4885 * have to back out now.
4886 *
4887 * Notice that we assume that no stone of the attacking color
4888 * has been placed on the board with trymove() when this
4889 * function is called. Thus we can (mostly) trust the worm data for
4890 * stones of this color.
4891 */
4892 if (worm[pos].attack_codes[0] != 0
4893 && worm[pos].size != dragon[pos].size)
4894 continue;
4895
4896 /* This can happen if called when stackp > 0 */
4897 if (dragon[pos].id == -1)
4898 continue;
4899
4900 for (k = 0; k < DRAGON2(pos).neighbors; k++) {
4901 int d = DRAGON2(pos).adjacent[k];
4902 int apos = dragon2[d].origin;
4903
4904 if (board[apos] == color && !owl->goal[apos]) {
4905 owl->boundary[pos] = 2;
4906 break;
4907 }
4908 }
4909 }
4910}
4911
4912/* Add the stone just played to the goal dragon if same_dragon is
4913 * SAME_DRAGON_CONNECTED. We also add all stones belonging to the same
4914 * generalized string to the goal. If same_dragon is
4915 * SAME_DRAGON_MAYBE_CONNECTED, we only add the stones if at least one
4916 * stone of the generalized string already was part of the goal. If
4917 * same_dragon is SAME_DRAGON_NOT_CONNECTED, we don't add any stones
4918 * at all.
4919 *
4920 * The SAME_DRAGON_ALL_CONNECTED case is like SAME_DRAGON_CONNECTED
4921 * but additionally all other own stones in the pattern suggesting the
4922 * move are also added to the goal.
4923 */
4924static void
4925owl_update_goal(int pos, enum same_dragon_value same_dragon, int lunch,
4926 struct local_owl_data *owl, int semeai_call,
4927 struct matched_pattern_data *pattern_data)
4928{
4929 int stones[MAX_BOARD * MAX_BOARD];
4930 int num_stones;
4931 int k;
4932 int do_add = 1;
4933 SGFTree *save_sgf_dumptree = sgf_dumptree;
4934 int save_count_variations = count_variations;
4935
4936
4937 /* Turn off sgf output during find_superstring(). */
4938 sgf_dumptree = NULL;
4939 count_variations = 0;
4940
4941 if (same_dragon == SAME_DRAGON_NOT_CONNECTED)
4942 num_stones = findstones(pos, MAX_BOARD * MAX_BOARD, stones);
4943 else if (semeai_call)
4944 find_superstring_conservative(pos, &num_stones, stones);
4945 else
4946 find_superstring(pos, &num_stones, stones);
4947
4948 /* Turn sgf output back on. */
4949 sgf_dumptree = save_sgf_dumptree;
4950 count_variations = save_count_variations;
4951
4952 /* If same_dragon field is 1, only add if the played stone
4953 * clearly is in contact with the goal dragon.
4954 */
4955 if (same_dragon <= SAME_DRAGON_MAYBE_CONNECTED) {
4956 do_add = 0;
4957 for (k = 0; k < num_stones; k++)
4958 if (owl->goal[stones[k]] != 0) {
4959 do_add = 1;
4960 break;
4961 }
4962 }
4963
4964 if (do_add)
4965 for (k = 0; k < num_stones; k++) {
4966 if (owl->goal[stones[k]] == 0) {
4967 if (0)
4968 TRACE("Added %1m to goal.\n", stones[k]);
4969 owl->goal[stones[k]] = 2;
4970 owl->cumulative_goal[stones[k]] = 1;
4971 }
4972 }
4973
4974 /* If this move captures a lunch, we add all it's direct neighbours to the
4975 * goal.
4976 */
4977 if (!semeai_call && lunch != NO_MOVE && board[lunch] != EMPTY) {
4978 int adj, adjs[MAXCHAIN];
4979 int k;
4980 adj = chainlinks(lunch, adjs);
4981 for (k = 0; k < adj; k++)
4982 if (!owl->goal[adjs[k]]) {
4983 mark_string(adjs[k], owl->goal, 2);
4984 mark_string(adjs[k], owl->cumulative_goal, 2);
4985 }
4986 }
4987
4988 /* Now we handle the SAME_DRAGON_ALL_CONNECTED case. The move has
4989 * already been added to the goal above, so it remains to find all
4990 * other friendly stones in the pattern and add them too. We do that
4991 * by a recursive call to this function in SAME_DRAGON_CONNECTED mode.
4992 * This is maybe not the most elegant technique, however.
4993 */
4994 if (same_dragon == SAME_DRAGON_ALL_CONNECTED) {
4995 gg_assert(pattern_data != NULL);
4996 for (k = 0; k < pattern_data->pattern->patlen; k++) {
4997 int pos2;
4998
4999 /* all the following stuff (currently) applies only at occupied cells */
5000 if (pattern_data->pattern->patn[k].att != ATT_O)
5001 continue;
5002
5003 /* transform pattern real coordinate */
5004 pos2 = AFFINE_TRANSFORM(pattern_data->pattern->patn[k].offset,
5005 pattern_data->ll, pattern_data->anchor);
5006
5007 if (!owl->goal[pos2])
5008 owl_update_goal(pos2, SAME_DRAGON_CONNECTED, NO_MOVE, owl, semeai_call,
5009 pattern_data);
5010 }
5011 }
5012
5013 if (1 && verbose)
5014 goaldump(owl->goal);
5015}
5016
5017
5018/* Computes the connected components of a the graph that is given by
5019 * having graph[i][j] = 1 if i and j are connected, and that has size
5020 * graph_size.
5021 *
5022 * This function is generic, but without having the fixed MAX_CUTS
5023 * array size it is ugly to write in ANSI C89 (no variably sized arrays),
5024 * so we leave it here for now.
5025 */
5026static int
5027connected_components(signed char graph[MAX_CUTS][MAX_CUTS], int graph_size,
5028 signed char component[MAX_CUTS])
5029{
5030 int num_components = 0;
5031 int k, j;
5032
5033 if (graph_size <= 0)
5034 return 0;
5035
5036 memset(component, -1, MAX_CUTS);
5037 for (;;) {
5038 int found_one;
5039 /* Find unidentified string. */
5040 for (k = 0; k < graph_size; k++)
5041 if (component[k] == -1)
5042 break;
5043 if (k == graph_size)
5044 break; /* All are identified. */
5045 component[k] = num_components; /* Start new component. */
5046 do { /* Spread new component. */
5047 found_one = 0;
5048 for (j = k+1; j < graph_size; j++)
5049 if (graph[k][j] && component[j] == -1) {
5050 component[j] = num_components;
5051 found_one = 1;
5052 }
5053 } while (found_one);
5054 num_components++;
5055 }
5056 gg_assert(num_components > 0);
5057 return num_components;
5058}
5059
5060/* This functions gets called after a move has been made that threatens
5061 * to cut the owl goal dragon. It cuts the goal if necessary, and sets it
5062 * to the biggest remaining component.
5063 */
5064static void
5065owl_test_cuts(signed char goal[BOARDMAX], int color, int cuts[MAX_CUTS])
5066{
5067 int k, j;
5068 signed char connected[MAX_CUTS][MAX_CUTS];
5069 /* int connect_move[MAX_CUTS][MAX_CUTS]; */
5070 int num_cuts;
5071 int found_cut = 0;
5072 SGFTree *save_sgf_dumptree = sgf_dumptree;
5073 int save_count_variations = count_variations;
5074
5075 sgf_dumptree = NULL;
5076 count_variations = 0;
5077
5078 memset(connected, 1, MAX_CUTS*MAX_CUTS);
5079 if (debug & DEBUG_SPLIT_OWL) {
5080 gprintf("Called for this goal: ");
5081 goaldump(goal);
5082 gprintf("At this position:\n");
5083 showboard(0);
5084 }
5085
5086 /* Delete captured strings from list. */
5087 for (k = 0; k < MAX_CUTS; k++) {
5088 if (cuts[k] == NO_MOVE)
5089 break;
5090 if (board[cuts[k]] == EMPTY) {
5091 for (j = k + 1; j < MAX_CUTS; j++) {
5092 if (cuts[j] == NO_MOVE)
5093 break;
5094 cuts[j-1] = cuts[j];
5095 }
5096 cuts[k] = NO_MOVE;
5097 k--;
5098 }
5099 }
5100 num_cuts = k;
5101
5102 /* Test for each pair of strings in cuts[] whether it can now be
5103 * disconnected.
5104 */
5105 for (k = 0; k < num_cuts; k++) {
5106 ASSERT1(board[cuts[k]] == color, cuts[k]);
5107 for (j = k + 1; j < num_cuts; j++)
5108 if (fast_disconnect(cuts[k], cuts[j], NULL) == WIN) {
5109 found_cut = 1;
5110 connected[k][j] = 0;
5111 connected[j][k] = 0;
5112 }
5113 }
5114
5115 if (found_cut) {
5116 signed char component[MAX_CUTS];
5117 signed char component2[BOARDMAX];
5118 int component_size[MAX_CUTS];
5119 int num_components;
5120 int biggest_component = -1;
5121 struct connection_data *conn_data;
5122 int c_id;
5123 int pos;
5124
5125 /* Start by computing the connected components among the strings
5126 * listed in cuts[].
5127 */
5128 num_components = connected_components(connected, num_cuts, component);
5129 if (num_components <= 1) {
5130 sgf_dumptree = save_sgf_dumptree;
5131 count_variations = save_count_variations;
5132 return;
5133 }
5134
5135 /* Now break up the goal by associating each goal stone to one of
5136 * the connected components.
5137 *
5138 * First we compute the connection distances from each of the
5139 * partial goals we have found.
5140 */
5141 memset(component2, -1, BOARDMAX);
5142 memset(component_size, 0, sizeof(int) * num_components);
5143 conn_data = malloc(sizeof(struct connection_data) * num_components);
5144 for (c_id = 0; c_id < num_components; c_id++) {
5145 signed char this_goal[BOARDMAX];
5146 memset(this_goal, 0, BOARDMAX);
5147
5148 for (k = 0; k < num_cuts; k++)
5149 if (component[k] == c_id) {
5150 mark_string(cuts[k], this_goal, 1);
5151 mark_string(cuts[k], component2, (signed char) c_id);
5152 }
5153 init_connection_data(color, this_goal, NO_MOVE, FP(3.01),
5154 conn_data + c_id, 1);
5155 spread_connection_distances(color, conn_data + c_id);
5156 }
5157
5158 /* Now put each goal string to the component to which it has the
5159 * smallest distance.
5160 */
5161 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
5162 int closest_dist = HUGE_CONNECTION_DISTANCE;
5163 int closest_component = -1;
5164 if (board[pos] != color || !goal[pos])
5165 continue;
5166 if (pos != find_origin(pos))
5167 continue;
5168 for (c_id = 0; c_id < num_components; c_id++) {
5169 if (conn_data[c_id].distances[pos] < closest_dist) {
5170 closest_dist = conn_data[c_id].distances[pos];
5171 closest_component = c_id;
5172 }
5173 }
5174 /* FIXME: What to do if no close component found? */
5175 if (closest_component != -1) {
5176 mark_string(pos, component2, (signed char) closest_component);
5177 component_size[closest_component] += countstones(pos);
5178 }
5179 }
5180
5181 /* Now find the biggest_component. */
5182 {
5183 int biggest_size = 0;
5184 for (c_id = 0; c_id < num_components; c_id++)
5185 if (component_size[c_id] > biggest_size) {
5186 biggest_size = component_size[c_id];
5187 biggest_component = c_id;
5188 }
5189 gg_assert(biggest_component != -1);
5190 }
5191
5192 /* Now delete everything except the biggest component from the goal. */
5193 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
5194 if (component2[pos] != biggest_component)
5195 goal[pos] = 0;
5196 if (debug & DEBUG_SPLIT_OWL) {
5197 gprintf("Split dragon. Biggest component is %d (of %d).\n",
5198 biggest_component, num_components);
5199 showboard(0);
5200 componentdump(component2);
5201 }
5202 free(conn_data);
5203 }
5204 sgf_dumptree = save_sgf_dumptree;
5205 count_variations = save_count_variations;
5206}
5207
5208/* We update the boundary marks. The boundary mark must be
5209 * constant on each string. It is nonzero if the string
5210 * adjoins the goal dragon, or if the string includes a
5211 * stone played in the course of analysis. If the string
5212 * adjoins a live friendly dragon, the boundary mark is 2.
5213 */
5214static void
5215owl_update_boundary_marks(int pos, struct local_owl_data *owl)
5216{
5217 signed char boundary_mark = 0;
5218 int k;
5219
5220 for (k = 0; k < 4; k++) {
5221 int pos2 = pos + delta[k];
5222
5223 if (ON_BOARD(pos2) && owl->boundary[pos2] > boundary_mark)
5224 boundary_mark = owl->boundary[pos2];
5225
5226 if (board[pos2] == owl->color
5227 && dragon[pos2].color == owl->color
5228 && dragon[pos2].status == ALIVE
5229 && !owl->goal[pos2]
5230 && !owl->neighbors[pos2])
5231 boundary_mark = 2;
5232 }
5233
5234 mark_string(pos, owl->boundary, boundary_mark);
5235}
5236
5237/* Lists the goal array. For use in GDB:
5238 * (gdb) set goaldump(goal).
5239 */
5240
5241void
5242goaldump(const signed char goal[BOARDMAX])
5243{
5244 int pos;
5245 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
5246 if (ON_BOARD(pos) && goal[pos])
5247 gprintf("%o%1m (%d) ", pos, (int) goal[pos]);
5248 gprintf("\n");
5249}
5250
5251void
5252componentdump(const signed char component[BOARDMAX])
5253{
5254 int pos;
5255 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
5256 if (ON_BOARD(pos) && component[pos] != -1)
5257 gprintf("%o%1m (%d) ", pos, (int) component[pos]);
5258 gprintf("\n");
5259}
5260
5261/*
5262 * Owl attack moves are ineffective when the dragon can still live in a
5263 * semeai. This function tests whether an owl attack move has this problem.
5264 * If not, an owl attack move reason is added, otherwise we treat the
5265 * move as a strategic attack.
5266 */
5267static void
5268test_owl_attack_move(int pos, int dr, int kworm, int acode)
5269{
5270 int color = OTHER_COLOR(board[dr]);
5271 if (DRAGON2(dr).semeais == 0
5272 || DRAGON2(dr).semeai_defense_point == NO_MOVE
5273 || (DRAGON2(dr).semeais == 1 && semeai_move_reason_known(pos, dr))
5274 || acode == GAIN) {
5275 add_owl_attack_move(pos, dr, kworm, acode);
5276 DEBUG(DEBUG_OWL, "owl: %1m attacks %1m (%s) at move %d\n",
5277 pos, dr, result_to_string(DRAGON2(dr).owl_attack_code),
5278 movenum+1);
5279 }
5280 else {
5281 int dr2 = DRAGON2(dr).semeai_defense_target;
5282 int semeai_result, certain;
5283 int save_verbose = verbose;
5284 if (verbose > 0)
5285 verbose--;
5286 owl_analyze_semeai_after_move(pos, color, dr, dr2, &semeai_result,
5287 NULL, NULL, 1, &certain, 0);
5288 verbose = save_verbose;
5289 if (certain >= DRAGON2(dr).semeai_defense_certain
5290 && (semeai_result >= REVERSE_RESULT(acode))) {
5291 /* Demote the move reasons. */
5292 DEBUG(DEBUG_OWL, "owl: %1m ineffective owl attack on %1m (can live in semeai with %1m)\n", pos, dr, dr2);
5293 add_strategical_attack_move(pos, dr);
5294 }
5295 else {
5296 add_owl_attack_move(pos, dr, kworm, acode);
5297 DEBUG(DEBUG_OWL, "owl: %1m attacks %1m (%s) at move %d\n",
5298 pos, dr, result_to_string(DRAGON2(dr).owl_attack_code),
5299 movenum+1);
5300 }
5301 }
5302}
5303
5304/* Add owl move reasons. This function should be called once during
5305 * genmove. It has to be called after semeai_move_reasons().
5306 */
5307
5308void
5309owl_reasons(int color)
5310{
5311 int pos;
5312
5313 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
5314 if (!IS_STONE(board[pos])
5315 || dragon[pos].origin != pos)
5316 continue;
5317
5318 if (dragon[pos].status == CRITICAL
5319 && DRAGON2(pos).owl_attack_point != NO_MOVE) {
5320 if (board[pos] == color) {
5321 if (DRAGON2(pos).owl_defense_point != NO_MOVE) {
5322 if (DRAGON2(pos).owl_defense_code == LOSS) {
5323 add_loss_move(DRAGON2(pos).owl_defense_point, pos,
5324 DRAGON2(pos).owl_defense_kworm);
5325 DEBUG(DEBUG_OWL, "owl: %1m defends %1m with loss at move %d\n",
5326 DRAGON2(pos).owl_defense_point, pos, movenum+1);
5327 }
5328 else {
5329 add_owl_defense_move(DRAGON2(pos).owl_defense_point, pos,
5330 DRAGON2(pos).owl_defense_code);
5331 DEBUG(DEBUG_OWL, "owl: %1m defends %1m at move %d\n",
5332 DRAGON2(pos).owl_defense_point, pos, movenum+1);
5333 }
5334 }
5335 }
5336 else { /* opponent's dragon */
5337 /* We don't want to add this move reason if the attacker
5338 * dies because the victim only formed a nakade shape.
5339 *
5340 * FIXME: This code overlaps heavily with some code in
5341 * examine_move_safety() in move_reasons.c. The caching
5342 * scheme should minimize the performance hit, but of course
5343 * it's unfortunate to have the code duplication.
5344 */
5345 int move = DRAGON2(pos).owl_attack_point;
5346
5347 /* No worries if we catch something big. */
5348 if (dragon[pos].effective_size < 8) {
5349 /* Look through the neighbors of the victim for dragons of
5350 * our color. If we find at least one being thought alive
5351 * everything is ok. Otherwise we keep track of the
5352 * largest one for further examination.
5353 */
5354 int largest = 0;
5355 int k;
5356 int bpos = NO_MOVE;
5357 int kworm = NO_MOVE;
5358 int safe = 0;
5359 for (k = 0; k < DRAGON2(pos).neighbors; k++) {
5360 int d = DRAGON2(pos).adjacent[k];
5361 if (DRAGON(d).color == color) {
5362 if (DRAGON(d).status == ALIVE) {
5363 safe = 1;
5364 break;
5365 }
5366 if (DRAGON(d).size > largest) {
5367 bpos = dragon2[d].origin;
5368 largest = DRAGON(d).size;
5369 }
5370 }
5371 }
5372
5373 /* It may occasionally happen that no neighbor of our
5374 * color was found. Assume safe in that case.
5375 */
5376 if (bpos == NO_MOVE)
5377 safe = 1;
5378
5379 /* If not yet thought safe, ask the owl code whether the
5380 * owl attack defends the (largest) attacker.
5381 */
5382 if (!safe && owl_does_defend(move, bpos, &kworm) != WIN) {
5383 DEBUG(DEBUG_OWL,
5384 "owl: %1m attacks %1m at move %d, but the attacker dies.\n",
5385 move, pos, movenum+1);
5386 DRAGON2(pos).safety = INESSENTIAL;
5387 continue;
5388 }
5389 }
5390
5391 /* If we've reached this far, it only remains to check the move
5392 * against semeai complications. */
5393 test_owl_attack_move(move, pos, DRAGON2(pos).owl_attack_kworm,
5394 DRAGON2(pos).owl_attack_code);
5395 }
5396 }
5397 else if (DRAGON2(pos).owl_status == DEAD
5398 && DRAGON2(pos).owl_threat_status == CAN_THREATEN_DEFENSE) {
5399 if (board[pos] == color
5400 && DRAGON2(pos).owl_defense_point != NO_MOVE) {
5401 add_owl_defense_threat_move(DRAGON2(pos).owl_defense_point, pos, WIN);
5402 DEBUG(DEBUG_OWL, "owl: %1m threatens to defend %1m at move %d\n",
5403 DRAGON2(pos).owl_defense_point, pos, movenum+1);
5404 }
5405 if (board[pos] == color
5406 && DRAGON2(pos).owl_second_defense_point != NO_MOVE
5407 && is_legal(DRAGON2(pos).owl_second_defense_point, color)) {
5408 add_owl_defense_threat_move(DRAGON2(pos).owl_second_defense_point,
5409 pos, WIN);
5410 DEBUG(DEBUG_OWL, "owl: %1m threatens to defend %1m at move %d\n",
5411 DRAGON2(pos).owl_second_defense_point, pos, movenum+1);
5412 }
5413
5414 /* If the opponent can threaten to live, an attacking
5415 * move gets a small value to make sure it's really dead.
5416 */
5417 if (board[pos] == OTHER_COLOR(color)
5418 && DRAGON2(pos).owl_threat_status == CAN_THREATEN_DEFENSE
5419 && DRAGON2(pos).owl_attack_point != NO_MOVE) {
5420 add_owl_prevent_threat_move(DRAGON2(pos).owl_attack_point, pos);
5421 DEBUG(DEBUG_OWL, "owl: %1m prevents a threat against %1m at move %d\n",
5422 DRAGON2(pos).owl_attack_point, pos, movenum+1);
5423 }
5424 }
5425 else if (DRAGON2(pos).owl_status == ALIVE) {
5426 if (board[pos] == OTHER_COLOR(color)
5427 && DRAGON2(pos).owl_threat_status == CAN_THREATEN_ATTACK) {
5428 if (DRAGON2(pos).owl_attack_point != NO_MOVE) {
5429 add_owl_attack_threat_move(DRAGON2(pos).owl_attack_point, pos, WIN);
5430 DEBUG(DEBUG_OWL, "owl: %1m threatens %1m at move %d\n",
5431 DRAGON2(pos).owl_attack_point, pos, movenum+1);
5432 }
5433 if (DRAGON2(pos).owl_second_attack_point != NO_MOVE
5434 && is_legal(DRAGON2(pos).owl_second_attack_point, color)) {
5435 add_owl_attack_threat_move(DRAGON2(pos).owl_second_attack_point, pos,
5436 WIN);
5437 DEBUG(DEBUG_OWL, "owl: %1m threatens %1m at move %d\n",
5438 DRAGON2(pos).owl_second_attack_point, pos, movenum+1);
5439 }
5440 }
5441 else if (board[pos] == OTHER_COLOR(color)
5442 && DRAGON2(pos).owl_attack_point != NO_MOVE
5443 && DRAGON2(pos).owl_attack_code == GAIN) {
5444 add_owl_attack_move(DRAGON2(pos).owl_attack_point, pos,
5445 DRAGON2(pos).owl_attack_kworm, GAIN);
5446 DEBUG(DEBUG_OWL, "owl: %1m attacks %1m with gain at move %d\n",
5447 DRAGON2(pos).owl_attack_point, pos, movenum+1);
5448 }
5449 else if (board[pos] == color
5450 && DRAGON2(pos).owl_defense_point != NO_MOVE
5451 && DRAGON2(pos).owl_defense_code == LOSS) {
5452 add_loss_move(DRAGON2(pos).owl_defense_point, pos,
5453 DRAGON2(pos).owl_defense_kworm);
5454 DEBUG(DEBUG_OWL, "owl: %1m defends %1m with loss at move %d\n",
5455 DRAGON2(pos).owl_defense_point, pos, movenum+1);
5456 }
5457 else if (board[pos] == color
5458 && DRAGON2(pos).owl_attack_point != NO_MOVE
5459 && DRAGON2(pos).owl_attack_code == GAIN
5460 && DRAGON2(pos).owl_defense_code == WIN
5461 && DRAGON2(pos).owl_defense_point != NO_MOVE) {
5462 add_owl_defense_move(DRAGON2(pos).owl_defense_point, pos,
5463 DRAGON2(pos).owl_defense_code);
5464 DEBUG(DEBUG_OWL, "owl: %1m defends %1m against possible loss at move %d\n",
5465 DRAGON2(pos).owl_defense_point, pos, movenum+1);
5466
5467 }
5468 /* The owl code found the friendly dragon alive, but was uncertain,
5469 * and an extra point of defense was found, so this might
5470 * be a good place to play.
5471 */
5472 else if (board[pos] == color
5473 && !DRAGON2(pos).owl_attack_certain
5474 && DRAGON2(pos).owl_defense_certain
5475 && ON_BOARD(DRAGON2(pos).owl_defense_point)) {
5476 add_owl_uncertain_defense_move(DRAGON2(pos).owl_defense_point, pos);
5477 DEBUG(DEBUG_OWL,
5478 "owl: %1m defends the uncertain dragon at %1m at move %d\n",
5479 DRAGON2(pos).owl_defense_point, pos, movenum+1);
5480 }
5481 }
5482
5483 /* The owl code found the dragon dead, but was uncertain,
5484 * and an extra point of attack was found, so this might
5485 * be a good place to play.
5486 */
5487 else if (DRAGON2(pos).owl_status == DEAD
5488 && board[pos] == OTHER_COLOR(color)
5489 && !DRAGON2(pos).owl_attack_certain
5490 && ON_BOARD(DRAGON2(pos).owl_attack_point)) {
5491 add_owl_uncertain_defense_move(DRAGON2(pos).owl_attack_point, pos);
5492 DEBUG(DEBUG_OWL,
5493 "owl: %1m might defend the uncertain dragon at %1m at move %d\n",
5494 DRAGON2(pos).owl_attack_point, pos, movenum+1);
5495 }
5496 }
5497}
5498
5499/* Use the owl code to determine whether the move at (move) makes
5500 * the dragon at (target) owl safe. This is used to test whether
5501 * tactical defenses are strategically viable and whether a vital eye
5502 * point does kill an owl critical dragon.
5503 *
5504 * Should be called only when stackp==0.
5505 */
5506
5507int
5508owl_does_defend(int move, int target, int *kworm)
5509{
5510 int color = board[target];
5511 int result = 0;
5512 struct local_owl_data *owl;
5513 int reading_nodes_when_called = get_reading_node_counter();
5514 int tactical_nodes;
5515 int origin;
5516 int acode;
5517 int wpos = NO_MOVE;
5518 int wid = MAX_GOAL_WORMS;
5519 double start = 0.0;
5520
5521 if (debug & DEBUG_OWL_PERFORMANCE)
5522 start = gg_cputime();
5523
5524 if (worm[target].unconditional_status == DEAD)
5525 return 0;
5526
5527 origin = dragon[target].origin;
5528 TRACE("owl_does_defend %1m %1m(%1m)\n", move, target, origin);
5529
5530 if (search_persistent_owl_cache(OWL_DOES_DEFEND, move, target, 0,
5531 &result, kworm, NULL, NULL))
5532 return result;
5533
5534 if (trymove(move, color, "owl_does_defend", target)) {
5535 /* Check if a compatible owl_attack() is cached. */
5536 if (search_persistent_owl_cache(OWL_ATTACK, origin, 0, 0,
5537 &result, NULL, kworm, NULL)) {
5538 popgo();
5539 return REVERSE_RESULT(result);
5540 }
5541
5542 /*
5543 * FIXME: (move) will be added to the goal dragon although we
5544 * do not know whether it is really connected.
5545 */
5546 init_owl(&owl, target, NO_MOVE, move, 1, NULL);
5547 prepare_goal_list(target, owl, owl_goal_worm, &goal_worms_computed,
5548 kworm, 0);
5549 acode = do_owl_attack(target, NULL, &wid, owl, 0);
5550 finish_goal_list(&goal_worms_computed, &wpos, owl_goal_worm, wid);
5551 result = REVERSE_RESULT(acode);
5552 popgo();
5553 }
5554 else
5555 return 0; /* Don't cache anything in this case. */
5556
5557 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
5558
5559 DEBUG(DEBUG_OWL_PERFORMANCE,
5560 "owl_does_defend %1m %1m(%1m), result %d (%d, %d nodes, %f seconds)\n",
5561 move, target, origin, result, local_owl_node_counter,
5562 tactical_nodes, gg_cputime() - start);
5563
5564 store_persistent_owl_cache(OWL_DOES_DEFEND, move, target, 0,
5565 result, wpos, 0, 0,
5566 tactical_nodes, owl->goal, board[target]);
5567
5568 if (kworm)
5569 *kworm = wpos;
5570 return result;
5571}
5572
5573
5574/* Use the owl code to determine whether the dragon at (target) is owl
5575 * safe after an own move at (move). This is used to detect
5576 * blunders. In case the dragon is not safe, it also tries to find a
5577 * defense point making (target) safe in a later move.
5578 *
5579 * Should be called only when stackp==0.
5580 */
5581
5582int
5583owl_confirm_safety(int move, int target, int *defense_point, int *kworm)
5584{
5585 int color = board[target];
5586 int result = 0;
5587 struct local_owl_data *owl;
5588 int reading_nodes_when_called = get_reading_node_counter();
5589 int tactical_nodes;
5590 int origin;
5591 int defense = 0;
5592 double start = 0.0;
5593 int acode;
5594 int wpos = NO_MOVE;
5595 int wid = MAX_GOAL_WORMS;
5596
5597 if (debug & DEBUG_OWL_PERFORMANCE)
5598 start = gg_cputime();
5599
5600 if (worm[target].unconditional_status == DEAD)
5601 return 0;
5602
5603 origin = dragon[target].origin;
5604 TRACE("owl_confirm_safety %1m %1m(%1m)\n", move, target, origin);
5605
5606 if (search_persistent_owl_cache(OWL_CONFIRM_SAFETY, move, target, 0,
5607 &result, defense_point, kworm, NULL))
5608 return result;
5609
5610 if (trymove(move, color, "owl_confirm_safety", target)) {
5611 /* Check if a compatible owl_attack() is cached. */
5612 if (search_persistent_owl_cache(OWL_ATTACK, origin, 0, 0,
5613 &result, defense_point, kworm, NULL)) {
5614 popgo();
5615 if (result == 0)
5616 return WIN;
5617 else if (result == GAIN)
5618 return LOSS;
5619 else
5620 return 0;
5621 }
5622
5623 init_owl(&owl, target, NO_MOVE, move, 1, NULL);
5624 prepare_goal_list(target, owl, owl_goal_worm, &goal_worms_computed,
5625 kworm, 0);
5626 acode = do_owl_attack(target, &defense, &wid, owl, 0);
5627 finish_goal_list(&goal_worms_computed, &wpos, owl_goal_worm, wid);
5628 if (acode == 0)
5629 result = WIN;
5630 else if (acode == GAIN)
5631 result = LOSS;
5632 popgo();
5633 }
5634 else
5635 return 0; /* Don't cache anything in this case. */
5636
5637 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
5638
5639 DEBUG(DEBUG_OWL_PERFORMANCE,
5640 "owl_confirm_safety %1m %1m(%1m), result %d %1m (%d, %d nodes, %f seconds)\n",
5641 move, target, origin, result, defense,
5642 local_owl_node_counter, tactical_nodes,
5643 gg_cputime() - start);
5644
5645 store_persistent_owl_cache(OWL_CONFIRM_SAFETY, move, target, 0,
5646 result, defense, wpos, 0,
5647 tactical_nodes, owl->goal, board[target]);
5648
5649 if (defense_point)
5650 *defense_point = defense;
5651 if (kworm)
5652 *kworm = wpos;
5653
5654 return result;
5655}
5656
5657
5658/* Use the owl code to determine whether the attack move at (move) of
5659 * the dragon (target) is effective, i.e. whether it kills the stones.
5660 *
5661 * Should be called only when stackp==0.
5662 */
5663
5664int
5665owl_does_attack(int move, int target, int *kworm)
5666{
5667 int color = board[target];
5668 int other = OTHER_COLOR(color);
5669 int result = 0;
5670 struct local_owl_data *owl;
5671 int reading_nodes_when_called = get_reading_node_counter();
5672 int tactical_nodes;
5673 int origin;
5674 int dcode;
5675 int wpos = NO_MOVE;
5676 int wid = MAX_GOAL_WORMS;
5677 double start = 0.0;
5678
5679 if (debug & DEBUG_OWL_PERFORMANCE)
5680 start = gg_cputime();
5681
5682 if (worm[target].unconditional_status == ALIVE)
5683 return 0;
5684
5685 origin = dragon[target].origin;
5686 TRACE("owl_does_attack %1m %1m(%1m)\n", move, target, origin);
5687
5688 if (search_persistent_owl_cache(OWL_DOES_ATTACK, move, target, 0,
5689 &result, kworm, NULL, NULL))
5690 return result;
5691
5692 /* FIXME: We want to do this after the trymove(), but currently
5693 * owl_mark_dragon() may crash if the trymove() happens to remove
5694 * some stones of the goal dragon from the board.
5695 */
5696#if 1
5697 init_owl(&owl, target, NO_MOVE, NO_MOVE, 1, NULL);
5698#endif
5699
5700 if (trymove(move, other, "owl_does_attack", target)) {
5701 /* Check if a compatible owl_defend() is cached. */
5702 if (search_persistent_owl_cache(OWL_DEFEND, origin, 0, 0,
5703 &result, NULL, kworm, NULL)) {
5704 popgo();
5705 return REVERSE_RESULT(result);
5706 }
5707
5708#if 0
5709 local_owl_node_counter = 0;
5710 owl->lunches_are_current = 0;
5711 owl_mark_dragon(target, NO_MOVE, owl);
5712#endif
5713 owl_update_boundary_marks(move, owl);
5714#if 0
5715 compute_owl_escape_values(owl);
5716#endif
5717 /* FIXME: Should also check if part of the dragon was captured,
5718 * like do_owl_attack() does.
5719 */
5720 if (board[target] == EMPTY)
5721 dcode = 0;
5722 else {
5723 prepare_goal_list(target, owl, owl_goal_worm, &goal_worms_computed,
5724 kworm, 0);
5725 dcode = do_owl_defend(target, NULL, &wid, owl, 0);
5726 finish_goal_list(&goal_worms_computed, &wpos, owl_goal_worm, wid);
5727 }
5728 result = REVERSE_RESULT(dcode);
5729 owl->lunches_are_current = 0;
5730 popgo();
5731 }
5732 else
5733 return 0; /* Don't cache anything in this case. */
5734
5735 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
5736
5737 DEBUG(DEBUG_OWL_PERFORMANCE,
5738 "owl_does_attack %1m %1m(%1m), result %d (%d, %d nodes, %f seconds)\n",
5739 move, target, origin, result, local_owl_node_counter,
5740 tactical_nodes, gg_cputime() - start);
5741
5742 store_persistent_owl_cache(OWL_DOES_ATTACK, move, target, 0,
5743 result, wpos, 0, 0,
5744 tactical_nodes, owl->goal, board[target]);
5745
5746 if (kworm)
5747 *kworm = wpos;
5748 return result;
5749}
5750
5751
5752/* Use the owl code to determine whether connecting the two dragons
5753 * (target1) and (target2) by playing at (move) results in a living
5754 * dragon. Should be called only when stackp==0.
5755 */
5756
5757int
5758owl_connection_defends(int move, int target1, int target2)
5759{
5760 int color = board[target1];
5761 int result = 0;
5762 int reading_nodes_when_called = get_reading_node_counter();
5763 int tactical_nodes;
5764 double start = 0.0;
5765 struct local_owl_data *owl;
5766
5767 if (debug & DEBUG_OWL_PERFORMANCE)
5768 start = gg_cputime();
5769
5770 ASSERT1(board[target2] == color, target2);
5771 TRACE("owl_connection_defends %1m %1m %1m\n", move, target1, target2);
5772
5773 if (worm[target1].unconditional_status == DEAD)
5774 return 0;
5775 if (worm[target2].unconditional_status == DEAD)
5776 return 0;
5777
5778 if (search_persistent_owl_cache(OWL_CONNECTION_DEFENDS, move, target1,
5779 target2, &result, NULL, NULL, NULL))
5780 return result;
5781
5782 init_owl(&owl, target1, target2, NO_MOVE, 1, NULL);
5783
5784 if (trymove(move, color, "owl_connection_defends", target1)) {
5785 owl_update_goal(move, SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE, owl, 0, NULL);
5786 if (!do_owl_attack(move, NULL, NULL, owl, 0))
5787 result = WIN;
5788 owl->lunches_are_current = 0;
5789 popgo();
5790 }
5791 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
5792
5793 DEBUG(DEBUG_OWL_PERFORMANCE,
5794 "owl_conn_defends %1m %1m %1m, result %d (%d, %d nodes, %f seconds)\n",
5795 move, target1, target2, result, local_owl_node_counter,
5796 tactical_nodes, gg_cputime() - start);
5797
5798 store_persistent_owl_cache(OWL_CONNECTION_DEFENDS, move, target1, target2,
5799 result, 0, 0, 0, tactical_nodes,
5800 owl->goal, color);
5801
5802 return result;
5803}
5804
5805
5806/* This function attempts to make a list of dead strings
5807 * which may be relevant to the life of the goal dragon.
5808 * Such strings are called owl lunches. They are ignored
5809 * (treated as invisible) during the running of make_domains.
5810 *
5811 * In certain cases we also need to identify tactically safe strings
5812 * which should be included in the eyespace, e.g. in this position:
5813 *
5814 * -------
5815 * OXXOOXO
5816 * OX.O.XO
5817 * OXX.XXO
5818 * OOXXXOO
5819 * .OOOOO.
5820 *
5821 * The three O stones cannot be captured, but they can't live
5822 * independently without capturing the surrounding stones. We call
5823 * such stones INESSENTIAL and identify them by the condition that for
5824 * each liberty of the corresponding superstring, the following must
5825 * hold:
5826 *
5827 * 1. At least one neighbor of the liberty is the goal dragon.
5828 * 2. No neighbor of the liberty is the same color as the tested string,
5829 * unless part of the same superstring.
5830 * 3. No neighbor of the liberty of the same color as the goal dragon
5831 * does not belong to the goal dragon.
5832 * 4. No neighbor of the liberty belonging to the goal dragon can be
5833 * tactically captured.
5834 *
5835 * There is a weakness with this characterization though, which can be
5836 * seen in this position:
5837 *
5838 * --------
5839 * OX..OOX.
5840 * OX.X.XOO
5841 * OX.XX.O.
5842 * O.XXOOO.
5843 * .OOOO...
5844 *
5845 * The two O stones intruding in X's eyespace cannot be tactically
5846 * captured and their liberties satisfy the requirements above. Still
5847 * it doesn't make any sense to count those stones as
5848 * inessential. Therefore we add another requirement on the stones
5849 * themself:
5850 *
5851 * 5. No neighbor of the stones does not belong to the goal or can be
5852 * tactically captured.
5853 *
5854 * A second weakness can be noticed in this position:
5855 *
5856 * |OOOO.
5857 * |XXXO.
5858 * |O.XOO
5859 * |OXXXO
5860 * |.O.XO
5861 * +-----
5862 *
5863 * The white stones in the corner should qualify as inessential but
5864 * the corner liberty doesn't satisfy requirement 1. Therefore we add
5865 * an alternative requirement:
5866 *
5867 * 1b. The liberty is a topologically false eye with respect to the
5868 * goal dragon.
5869 *
5870 * This is not quite good enough though, as shown in this position:
5871 *
5872 * ----------
5873 * OX.X.OO...
5874 * OXX.OOX.O.
5875 * O.XXXXX.O.
5876 * OOOOOOOOO.
5877 *
5878 * The four O stones are regarded as inessential after inclusion of
5879 * rule 1b, which is clearly inappropriate. To solve this problem we
5880 * modify the rule:
5881 *
5882 * 1b'. The liberty is a topologically false eye with respect to the
5883 * goal dragon and is adjacent to no empty vertex.
5884 */
5885
5886static void
5887owl_find_lunches(struct local_owl_data *owl)
5888{
5889 int k;
5890 int pos;
5891 int lunches = 0;
5892 int prevlunch;
5893 int lunch;
5894 int acode;
5895 int apos;
5896 int dcode;
5897 int dpos;
5898 int color = owl->color;
5899 int other = OTHER_COLOR(color);
5900 signed char already_checked[BOARDMAX];
5901
5902 SGFTree *save_sgf_dumptree = sgf_dumptree;
5903 int save_count_variations = count_variations;
5904
5905 sgf_dumptree = NULL;
5906 count_variations = 0;
5907 for (prevlunch = 0; prevlunch < MAX_LUNCHES; prevlunch++)
5908 owl->lunch[prevlunch] = NO_MOVE;
5909 memset(owl->inessential, 0, sizeof(owl->inessential));
5910
5911 memset(already_checked, 0, sizeof(already_checked));
5912 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
5913 if (board[pos] == color && owl->goal[pos]) {
5914 /* Loop over the eight neighbors. */
5915 for (k = 0; k < 8; k++) {
5916 int pos2 = pos + delta[k];
5917
5918 /* If the immediate neighbor is empty, we look two steps away. */
5919 if (k < 4 && board[pos2] == EMPTY)
5920 pos2 += delta[k];
5921
5922 if (board[pos2] != other)
5923 continue;
5924
5925 lunch = find_origin(pos2);
5926 if (already_checked[lunch])
5927 continue;
5928 already_checked[lunch] = 1;
5929
5930 attack_and_defend(lunch, &acode, &apos, &dcode, &dpos);
5931 if (acode != 0) {
5932 owl->lunch[lunches] = lunch;
5933 owl->lunch_attack_code[lunches] = acode;
5934 owl->lunch_attack_point[lunches] = apos;
5935 owl->lunch_defend_code[lunches] = dcode;
5936 ASSERT1(board[apos] == EMPTY, lunch);
5937 if (dcode != 0) {
5938 owl->lunch_defense_point[lunches] = dpos;
5939 ASSERT1(board[dpos] == EMPTY, lunch);
5940 }
5941 else
5942 owl->lunch_defense_point[lunches] = NO_MOVE;
5943 lunches++;
5944 if (lunches == MAX_LUNCHES) {
5945 sgf_dumptree = save_sgf_dumptree;
5946 count_variations = save_count_variations;
5947 owl->lunches_are_current = 1;
5948 return;
5949 }
5950 }
5951 else if (!owl->inessential[lunch]) {
5952 /* Test for inessentiality. */
5953 int adj;
5954 int adjs[MAXCHAIN];
5955 int num_stones;
5956 int stones[MAX_BOARD * MAX_BOARD];
5957 int liberties;
5958 int libs[MAXLIBS];
5959 int r;
5960 int essential = 0;
5961 int superstring[BOARDMAX];
5962
5963 /* First check the neighbors of the string. */
5964 adj = chainlinks(lunch, adjs);
5965 for (r = 0; r < adj; r++) {
5966 if (!owl->goal[adjs[r]] || attack(adjs[r], NULL) != 0) {
5967 essential = 1;
5968 break;
5969 }
5970 }
5971
5972 if (essential)
5973 continue;
5974
5975 find_superstring_stones_and_liberties(lunch, &num_stones, stones,
5976 &liberties, libs, 0);
5977
5978 memset(superstring, 0, sizeof(superstring));
5979 for (r = 0; r < num_stones; r++)
5980 superstring[stones[r]] = 1;
5981
5982 for (r = 0; r < liberties; r++) {
5983 int bpos = libs[r];
5984 int goal_found = 0;
5985 int s;
5986
5987 for (s = 0; s < 4; s++) {
5988 int cpos = bpos + delta[s];
5989
5990 if (!ON_BOARD(cpos))
5991 continue;
5992 if (board[cpos] == color) {
5993 if (attack(cpos, NULL) != 0) {
5994 essential = 1;
5995 break;
5996 }
5997 else if (owl->goal[cpos])
5998 goal_found = 1;
5999 else {
6000 essential = 1;
6001 break;
6002 }
6003 }
6004 else if (board[cpos] == other
6005 && !superstring[cpos]) {
6006 essential = 1;
6007 break;
6008 }
6009 }
6010 if (!goal_found) {
6011 /* Requirement 1 not satisfied. Test requirement 1b.
6012 * N.B. This is a simplified topological eye test.
6013 * The simplification may be good, bad, or neutral.
6014 */
6015 int off_board = 0;
6016 int diagonal_goal = 0;
6017 for (s = 4; s < 8; s++) {
6018 if (!ON_BOARD(bpos + delta[s]))
6019 off_board++;
6020 else if (owl->goal[bpos + delta[s]])
6021 diagonal_goal++;
6022 }
6023 if (diagonal_goal + (off_board >= 2) < 2)
6024 essential = 1;
6025 else {
6026 /* Check that the liberty is adjacent to no empty
6027 * vertex, as required by 1b'.
6028 */
6029 for (s = 0; s < 4; s++) {
6030 if (board[bpos + delta[s]] == EMPTY) {
6031 essential = 1;
6032 break;
6033 }
6034 }
6035 }
6036 }
6037
6038 if (essential)
6039 break;
6040 }
6041
6042 if (!essential) {
6043 TRACE("Inessential string found at %1m.\n", lunch);
6044 for (r = 0; r < num_stones; r++)
6045 owl->inessential[stones[r]] = 1;
6046 }
6047 }
6048 }
6049 }
6050 }
6051
6052 owl->lunches_are_current = 1;
6053 sgf_dumptree = save_sgf_dumptree;
6054 count_variations = save_count_variations;
6055}
6056
6057
6058/* Try to improve the move to attack a lunch. Essentially we try to avoid
6059 * unsafe moves when there are less risky ways to attack.
6060 *
6061 * This function also improves lunch attack point in a special case when
6062 * we capture a one- or two-stone lunch on the first line. If we eat it
6063 * with a first line move, there is a huge risk we'll end up with a false
6064 * eye. Therefore, we move the attack to the second line when it works.
6065 *
6066 * .*OO .*OOO .*OOOO
6067 * .,XO .,X.O .,XX.O
6068 * ---- ----- ------
6069 *
6070 * In all these position the attack point is moved from ',' to '*'.
6071 */
6072static int
6073improve_lunch_attack(int lunch, int attack_point)
6074{
6075 int color = OTHER_COLOR(board[lunch]);
6076 int defense_point;
6077 int k;
6078
6079 if (safe_move(attack_point, color)) {
6080 if (is_edge_vertex(lunch)
6081 && is_edge_vertex(attack_point)
6082 && neighbor_of_string(attack_point, lunch)) {
6083 int stones = countstones(lunch);
6084 int libs[2];
6085
6086 if (stones == 1
6087 || (stones == 2
6088 && findlib(lunch, 2, libs) == 2
6089 && is_edge_vertex(libs[0])
6090 && is_edge_vertex(libs[1]))) {
6091 for (k = 0; k < 4; k++) {
6092 int apos = attack_point + delta[k];
6093 if (!ON_BOARD(attack_point - delta[k]) && board[apos] == EMPTY) {
6094 if (does_attack(apos, lunch) && safe_move(apos, color))
6095 return apos;
6096 break;
6097 }
6098 }
6099 }
6100 }
6101
6102 return attack_point;
6103 }
6104
6105 for (k = 0; k < 4; k++) {
6106 int pos = attack_point + delta[k];
6107 if (board[pos] == color
6108 && attack(pos, NULL)
6109 && find_defense(pos, &defense_point)
6110 && defense_point != NO_MOVE
6111 && does_attack(defense_point, lunch)) {
6112 TRACE("Moved attack of lunch %1m from %1m to %1m.\n",
6113 lunch, attack_point, defense_point);
6114 return defense_point;
6115 }
6116 }
6117
6118 return attack_point;
6119}
6120
6121/* Try to improve the move to defend a lunch.
6122 *
6123 * An example where this is useful is the position below, where the
6124 * defense of A is moved from b to c. This is a possible variation in
6125 * ld_owl:182.
6126 *
6127 * ...X..| ...X..|
6128 * ...X..| ...Xc.|
6129 * ..XXO.| ..XXOb|
6130 * XXXOOX| XXXOOA|
6131 * XOOOX.| XOOOX.|
6132 * .XOX.X| .XOX.X|
6133 * ------+ ------+
6134 */
6135static int
6136improve_lunch_defense(int lunch, int defense_point)
6137{
6138 int color = board[lunch];
6139 int k;
6140
6141 for (k = 0; k < 4; k++) {
6142 int pos = defense_point + delta[k];
6143 if (board[pos] == OTHER_COLOR(color)
6144 && countlib(pos) == 2) {
6145 int libs[2];
6146 int pos2;
6147
6148 findlib(pos, 2, libs);
6149 if (libs[0] == defense_point)
6150 pos2 = libs[1];
6151 else
6152 pos2 = libs[0];
6153
6154 if (accuratelib(pos2, color, MAXLIBS, NULL)
6155 > accuratelib(defense_point, color, MAXLIBS, NULL)
6156 && does_defend(pos2, lunch)) {
6157 TRACE("Moved defense of lunch %1m from %1m to %1m.\n",
6158 lunch, defense_point, pos2);
6159 return pos2;
6160 }
6161 }
6162 }
6163
6164 return defense_point;
6165}
6166
6167
6168/* Wrapper for make domains. The second set of owl data is optional.
6169 * Use a null pointer if it is not needed. Otherwise, make_domains
6170 * is run separately for the two owl data, but information about
6171 * tactically dead lunches is used from *both* sources through
6172 * the owl_lively() calls.
6173 */
6174
6175static void
6176owl_make_domains(struct local_owl_data *owla, struct local_owl_data *owlb)
6177{
6178 /* We need to set this so that owl_lively() can be used. */
6179 struct eye_data *black_eye = NULL;
6180 struct eye_data *white_eye = NULL;
6181
6182 current_owl_data = owla;
6183 other_owl_data = owlb;
6184
6185 if (!owla->lunches_are_current)
6186 owl_find_lunches(owla);
6187 if (owla->color == BLACK)
6188 black_eye = owla->my_eye;
6189 else
6190 white_eye = owla->my_eye;
6191
6192 if (owlb) {
6193 gg_assert(owla->color == OTHER_COLOR(owlb->color));
6194 if (!owlb->lunches_are_current)
6195 owl_find_lunches(owlb);
6196 if (owlb->color == BLACK)
6197 black_eye = owlb->my_eye;
6198 else
6199 white_eye = owlb->my_eye;
6200 }
6201 make_domains(black_eye, white_eye, 1);
6202}
6203
6204/* True unless (pos) is EMPTY or occupied by a lunch for the goal dragon.
6205 * Used during make_domains (see optics.c: lively macro). A ``lively''
6206 * worm is one that might be alive, hence cannot be ignored in
6207 * determining eye spaces.
6208 */
6209
6210int
6211owl_lively(int pos)
6212{
6213 int origin;
6214 int lunch;
6215 ASSERT_ON_BOARD1(pos);
6216
6217 if (board[pos] == EMPTY)
6218 return 0;
6219 origin = find_origin(pos);
6220
6221 /* When reading a semeai there is a second set of owl data to consider.
6222 * Strings of the second owl are considered lively no matter what,
6223 * since declaring such a string dead prematurely can prevent the
6224 * semeai code from finishing its job.
6225 *
6226 * On the other hand a friendly string which is a lunch of the
6227 * other dragon and can't be saved is not lively.
6228 */
6229 if (other_owl_data) {
6230
6231 if (include_semeai_worms_in_eyespace && other_owl_data->goal[pos])
6232 return 0;
6233
6234 if (other_owl_data->goal[pos] && !semeai_trust_tactical_attack(pos))
6235 return 1;
6236 /* FIXME: Shouldn't we check other_owl_data->inessential[origin] here? */
6237 for (lunch = 0; lunch < MAX_LUNCHES; lunch++)
6238 if (other_owl_data->lunch[lunch] == origin
6239 && other_owl_data->lunch_defense_point[lunch] == NO_MOVE)
6240 return 0;
6241 }
6242
6243 /* Inessential stones are not lively. */
6244 if (current_owl_data->inessential[origin])
6245 return 0;
6246
6247 /* Lunches that can't be saved are dead, so don't report them as lively. */
6248 for (lunch = 0; lunch < MAX_LUNCHES; lunch++)
6249 if (current_owl_data->lunch[lunch] == origin
6250 && current_owl_data->lunch_defense_point[lunch] == NO_MOVE)
6251 return 0;
6252
6253 return 1;
6254}
6255
6256
6257/* Caching version of safe_move for the callback. This function has
6258 * its own cache, separate from the global safe move cache. Note that
6259 * since the cache is reset by owl_shapes before starting pattern
6260 * matching, and since (unlike safe_move) this function is always
6261 * called from the same place in owl_shapes_callback, the color will
6262 * be the same each time it is called. So there is no need to have
6263 * separate caches for B and W.
6264 */
6265
6266static int
6267owl_safe_move(int move, int color)
6268{
6269 int acode, safe = 0;
6270
6271 if (trymove(move, color, "owl_safe_move", 0)) {
6272 acode = attack(move, NULL);
6273 if (acode != WIN)
6274 safe = 1;
6275 else
6276 safe = 0;
6277 popgo();
6278 }
6279 current_owl_data->safe_move_cache[move] = safe+1;
6280 return safe;
6281}
6282
6283
6284/* This function, called when stackp==0, returns true if capturing
6285 * the string at (str) results in a live group.
6286 */
6287
6288#define MAX_SUBSTANTIAL_LIBS 10
6289
6290int
6291owl_substantial(int str)
6292{
6293 int k;
6294 int libs[MAX_SUBSTANTIAL_LIBS + 1];
6295 int liberties = findlib(str, MAX_SUBSTANTIAL_LIBS+1, libs);
6296 int reading_nodes_when_called = get_reading_node_counter();
6297 int tactical_nodes;
6298 int result;
6299 double start = 0.0;
6300 struct local_owl_data *owl;
6301 int num_moves = 0;
6302
6303 if (debug & DEBUG_OWL_PERFORMANCE)
6304 start = gg_cputime();
6305
6306 /* FIXME: We want to use the full init_owl here too (cf. similar
6307 * remark below).
6308 */
6309 reduced_init_owl(&owl, 1);
6310
6311 owl->color = OTHER_COLOR(board[str]);
6312 local_owl_node_counter = 0;
6313
6314 /* Big strings are always substantial since the biggest nakade is
6315 * six stones. (There are probably rare exceptions to this
6316 * rule, but they are unlikely to come up in a game.)
6317 */
6318 if (countstones(str) > 6)
6319 return 1;
6320
6321 if (liberties > MAX_SUBSTANTIAL_LIBS)
6322 return 0;
6323
6324 memset(owl->goal, 0, sizeof(owl->goal));
6325 /* Mark the neighbors of the string. If one is found which is alive, return
6326 * true. */
6327 {
6328 int adjs[MAXCHAIN];
6329 int adj;
6330
6331 adj = chainlinks(str, adjs);
6332 for (k = 0; k < adj; k++) {
6333 if (dragon[adjs[k]].status == ALIVE)
6334 return 1;
6335 mark_dragon(adjs[k], owl->goal, 1);
6336 }
6337 }
6338
6339 /* We must check the cache while stackp == 0, but we wait until the
6340 * trivial tests have been done.
6341 */
6342 if (search_persistent_owl_cache(OWL_SUBSTANTIAL, str, 0, 0,
6343 &result, NULL, NULL, NULL))
6344 return result;
6345
6346 /* fill all the liberties */
6347 for (k = 0; k < liberties; k++) {
6348 if (trymove(libs[k], owl->color, NULL, 0)) {
6349 if (get_level() >= 8)
6350 increase_depth_values();
6351 owl->goal[libs[k]] = 1;
6352 num_moves++;
6353 }
6354 else {
6355 /* if we can't fill, try swapping with the next liberty */
6356 if (k < liberties-1
6357 && trymove(libs[k+1], owl->color, NULL, 0)) {
6358 if (get_level() >= 8)
6359 increase_depth_values();
6360 owl->goal[libs[k+1]] = 1;
6361 libs[k+1] = libs[k];
6362 num_moves++;
6363 }
6364 else {
6365 /* Can't fill the liberties. Give up! */
6366 while (num_moves-- > 0) {
6367 if (get_level() >= 8)
6368 decrease_depth_values();
6369 popgo();
6370 }
6371 return 0;
6372 }
6373 }
6374 }
6375 /* FIXME: We would want to use init_owl() here too, but it doesn't
6376 * fit very well with the construction of the goal array above.
6377 */
6378 memcpy(owl->cumulative_goal, owl->goal, BOARDMAX);
6379 compute_owl_escape_values(owl);
6380 owl_mark_boundary(owl);
6381 owl->lunches_are_current = 0;
6382
6383 if (do_owl_attack(libs[0], NULL, NULL, owl, 0))
6384 result = 0;
6385 else
6386 result = 1;
6387 while (num_moves-- > 0) {
6388 if (get_level() >= 8)
6389 decrease_depth_values();
6390 popgo();
6391 }
6392
6393 tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
6394 DEBUG(DEBUG_OWL_PERFORMANCE,
6395 "owl_substantial %1m, result %d (%d, %d nodes, %f seconds)\n",
6396 str, result, local_owl_node_counter,
6397 tactical_nodes, gg_cputime() - start);
6398
6399 store_persistent_owl_cache(OWL_SUBSTANTIAL, str, 0, 0, result, 0, 0, 0,
6400 tactical_nodes, owl->goal, owl->color);
6401
6402 return result;
6403}
6404
6405
6406
6407/* Returns true if and only if (i, j) is a 1-2 vertex, i.e. next to a
6408 * corner.
6409 */
6410static int
6411one_two_point(int pos)
6412{
6413 int i = I(pos);
6414 int j = J(pos);
6415
6416 if ((i == 0 || i == board_size-1 || j == 0 || j == board_size-1)
6417 && (i == 1 || i == board_size-2 || j == 1 || j == board_size-2))
6418 return 1;
6419
6420 return 0;
6421}
6422
6423
6424
6425/* Reports the number of eyes gotten by capturing a boundary string.
6426 * This implementation tends to give an optimistic view of the
6427 * chances, so if it tells that the lunch is worthless, it truly
6428 * should be. The converse is not true.
6429 */
6430
6431static void
6432sniff_lunch(int lunch, int *min, int *probable, int *max,
6433 struct local_owl_data *owl)
6434{
6435 int other = OTHER_COLOR(board[lunch]);
6436 int libs[MAXLIBS];
6437 int liberties;
6438 int r;
6439
6440 ASSERT1(IS_STONE(board[lunch]), lunch);
6441
6442 if (owl->boundary[lunch] == 2) {
6443 *min = 2;
6444 *probable = 2;
6445 *max = 2;
6446 return;
6447 }
6448
6449 /* Do we believe this capture would help escaping? */
6450 liberties = findlib(lunch, MAXLIBS, libs);
6451 for (r = 0; r < liberties; r++) {
6452 if (owl->escape_values[libs[r]] > 0
6453 && !is_self_atari(libs[r], other)) {
6454 int k;
6455 for (k = 0; k < 8; k++)
6456 if (ON_BOARD(libs[r] + delta[k]) && owl->goal[libs[r] + delta[k]])
6457 break;
6458 if (k == 8) {
6459 *min = 2;
6460 *probable = 2;
6461 *max = 2;
6462 return;
6463 }
6464 }
6465 }
6466
6467 estimate_lunch_eye_value(lunch, min, probable, max, 1);
6468
6469 if (*min < 2) {
6470 int bonus = estimate_lunch_half_eye_bonus(lunch, owl->half_eye);
6471 *min += bonus/2;
6472 *probable += bonus;
6473 *max += (bonus + 1)/2;
6474 }
6475
6476 if (*probable < 2)
6477 eat_lunch_escape_bonus(lunch, min, probable, max, owl);
6478}
6479
6480/* Capturing a lunch can give eyes by turning a false eye into a proper one,
6481 * etc. This function returns the likely increase in half eyes
6482 * by capturing the string at (lunch).
6483 */
6484static int
6485estimate_lunch_half_eye_bonus(int lunch,
6486 struct half_eye_data half_eye[BOARDMAX])
6487{
6488 int stones[10];
6489 int k;
6490 int size = findstones(lunch, 10, stones);
6491 int half_eyes = 0;
6492
6493 ASSERT1(size < 10, lunch);
6494
6495 for (k = 0; k < size; k++) {
6496 int stone = stones[k];
6497 int d;
6498 for (d = 4; d < 8; d++) {
6499 int pos = stone + delta[d];
6500 if (ON_BOARD(pos)
6501 && (is_halfeye(half_eye, pos) || is_false_eye(half_eye, pos)))
6502 half_eyes++;
6503 }
6504 }
6505 return half_eyes;
6506}
6507
6508
6509void
6510estimate_lunch_eye_value(int lunch, int *min, int *probable, int *max,
6511 int appreciate_one_two_lunches)
6512{
6513 int other = OTHER_COLOR(board[lunch]);
6514 int size = countstones(lunch);
6515
6516 if (size > 6) {
6517 *min = 2;
6518 *probable = 2;
6519 *max = 2;
6520 }
6521 else if (size > 4) {
6522 *min = 1;
6523 *probable = 2;
6524 *max = 2;
6525 }
6526 else if (size > 2) {
6527 *min = 0;
6528 *probable = 1;
6529 *max = 2;
6530 }
6531 else if (size == 2) {
6532 int stones[2];
6533 findstones(lunch, 2, stones);
6534 /* A lunch on a 1-2 point tends always to be worth contesting. */
6535 if ((obvious_false_eye(stones[0], other)
6536 || obvious_false_eye(stones[1], other))
6537 && (!appreciate_one_two_lunches
6538 || !(one_two_point(stones[0]) || one_two_point(stones[1])))) {
6539 *min = 0;
6540 *probable = 0;
6541 *max = 0;
6542 }
6543 else {
6544 *min = 0;
6545 *probable = 1;
6546 *max = 1;
6547 }
6548 }
6549 else if (size == 1) {
6550 if (!obvious_false_eye(lunch, other)) {
6551 *min = 0;
6552 *probable = 1;
6553 *max = 1;
6554 }
6555 else {
6556 *min = 0;
6557 *probable = 0;
6558 *max = 0;
6559 }
6560 }
6561}
6562
6563/* Gives a bonus for a lunch capture which joins a (or some) friendly
6564 * string(s) to the goal dragon and improves the escape potential at
6565 * the same time. This is indicated in some situations where the owl
6566 * code would stop the analysis because of various cutoffs. See
6567 * do_owl_defend()
6568 *
6569 * The following implementation tries to get a precise idea of the
6570 * escape potential improvement by calling dragon_escape() twice.
6571 */
6572static void
6573eat_lunch_escape_bonus(int lunch, int *min, int *probable, int *max,
6574 struct local_owl_data *owl)
6575{
6576 int adjacent[MAXCHAIN];
6577 int neighbors;
6578 int adjoins = 0;
6579 int n;
6580 /* Be very careful before touching this value.
6581 * See owl_estimate_life() for details.
6582 */
6583 UNUSED(min);
6584
6585 /* Don't mess up with kos */
6586 if (is_ko_point(lunch))
6587 return;
6588
6589 neighbors = chainlinks(lunch, adjacent);
6590 for (n = 0; n < neighbors; n++)
6591 adjoins |= !owl->goal[adjacent[n]];
6592
6593 if (adjoins) {
6594 int before, after;
6595 before = dragon_escape(owl->goal, owl->color, owl->escape_values);
6596 /* if the escape route is already large enough to be considered
6597 * a WIN by the owl code, then no need for more */
6598 if (before < 5) {
6599 signed char new_goal[BOARDMAX];
6600 memcpy(new_goal, owl->goal, sizeof(new_goal));
6601 for (n = 0; n < neighbors; n++)
6602 if (!owl->goal[adjacent[n]])
6603 mark_string(adjacent[n], new_goal, 2);
6604 after = dragon_escape(new_goal, owl->color, owl->escape_values);
6605
6606 /* Following is completely ad hoc. Another set of tests might
6607 * very well get better results. */
6608 if (after - before >= 3) {
6609 if (after >= 8 || (before == 0 && after >= 5)) {
6610 *probable = 2;
6611 *max = 2;
6612 }
6613 else if (*max < 2)
6614 (*max)++;
6615 }
6616 }
6617 }
6618}
6619
6620
6621/* Find a new origin when it has been captured or cut out of the
6622 * goal. Used in do_owl_attack()
6623 */
6624static int
6625select_new_goal_origin(int origin, struct local_owl_data *owl)
6626{
6627 int pos;
6628 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
6629 if (board[pos] == owl->color && owl->goal[pos] == 1)
6630 return find_origin(pos);
6631
6632 return origin;
6633}
6634
6635
6636/* Retrieve topological eye values stored in the half_eye[] array of
6637 * the current owl data.
6638 *
6639 * FIXME: Sooner or later we'll want this to return a non-rounded
6640 * value. When we change this, we have to review all patterns using
6641 * the autohelper owl_topological_eye().
6642 */
6643int
6644owl_topological_eye(int pos, int color)
6645{
6646 float value;
6647 UNUSED(color);
6648 value = current_owl_data->half_eye[pos].value;
6649 if (value > 2.0 && value < 4.0)
6650 return 3;
6651 else if (value <= 2.0)
6652 return (int) (value + 0.99); /* Round up. */
6653 else
6654 return (int) value; /* Round down. */
6655}
6656
6657/* This function returns true if it is judged that the capture of the
6658 * string at (pos) is sufficient to create one eye.
6659 *
6660 * Update: Now it instead returns the max number of eyes.
6661 */
6662
6663int
6664vital_chain(int pos)
6665{
6666 int min;
6667 int probable;
6668 int max;
6669 sniff_lunch(pos, &min, &probable, &max, current_owl_data);
6670
6671 return max;
6672}
6673
6674
6675static void
6676compute_owl_escape_values(struct local_owl_data *owl)
6677{
6678 int pos;
6679 int m, n;
6680 signed char safe_stones[BOARDMAX];
6681 SGFTree *save_sgf_dumptree = sgf_dumptree;
6682 int save_count_variations = count_variations;
6683 signed char mx[BOARDMAX];
6684 memset(mx, 0, sizeof(mx));
6685
6686 sgf_dumptree = NULL;
6687 count_variations = 0;
6688 get_lively_stones(OTHER_COLOR(owl->color), safe_stones);
6689 sgf_dumptree = save_sgf_dumptree;
6690 count_variations = save_count_variations;
6691
6692 compute_escape_influence(owl->color, safe_stones, NULL, NULL,
6693 owl->escape_values);
6694
6695 DEBUG(DEBUG_ESCAPE, "Owl escape values:\n");
6696 for (m = 0; m < board_size; m++) {
6697 for (n = 0; n < board_size; n++) {
6698 pos = POS(m, n);
6699 if (dragon[pos].color == owl->color && !owl->goal[pos]) {
6700 if (dragon[pos].crude_status == ALIVE)
6701 owl->escape_values[pos] = 6;
6702 else if (dragon[pos].crude_status == UNKNOWN) {
6703 if (DRAGON2(pos).moyo_size > 5)
6704 owl->escape_values[pos] = 4;
6705 else if (DRAGON2(pos).escape_route > 5) {
6706 if (mx[dragon[pos].origin])
6707 owl->escape_values[pos] = owl->escape_values[dragon[pos].origin];
6708 else {
6709 int pos2;
6710 signed char escape_values[BOARDMAX];
6711 signed char dragon_stones[BOARDMAX];
6712
6713 compute_escape_influence(owl->color, safe_stones, owl->goal,
6714 NULL, escape_values);
6715
6716 /* mark_dragon() can't be used here in case a string of
6717 * the dragon was captured by the initial move in
6718 * owl_does_attack(). Actually it isn't really proper to
6719 * use is_same_dragon() at stackp>0 either but it's more
6720 * robust at least.
6721 */
6722 for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
6723 if (ON_BOARD(pos2))
6724 dragon_stones[pos2] = is_same_dragon(pos2, pos);
6725 }
6726
6727 if (dragon_escape(dragon_stones, owl->color, escape_values) > 5)
6728 owl->escape_values[dragon[pos].origin] = 4;
6729
6730 mx[dragon[pos].origin] = 1;
6731 }
6732 }
6733 }
6734 }
6735 DEBUG(DEBUG_ESCAPE, "%o%d", owl->escape_values[pos]);
6736 }
6737 DEBUG(DEBUG_ESCAPE, "%o\n");
6738 }
6739}
6740
6741
6742/* Used by autohelpers. */
6743int
6744owl_escape_value(int pos)
6745{
6746 /* FIXME: Should have a more robust mechanism to avoid
6747 * escaping inwards. Returning a negative value is just a kludge.
6748 */
6749 int k;
6750 ASSERT_ON_BOARD1(pos);
6751 if (current_owl_data->goal[pos])
6752 return -10;
6753
6754 if (board[pos] == EMPTY)
6755 for (k = 0; k < 8; k++)
6756 if (ON_BOARD(pos + delta[k]) && current_owl_data->goal[pos + delta[k]])
6757 return -10;
6758
6759 return current_owl_data->escape_values[pos];
6760}
6761
6762
6763/* Used by autohelpers. */
6764int
6765owl_goal_dragon(int pos)
6766{
6767 return current_owl_data->goal[pos] != 0;
6768}
6769
6770/* Used by autohelpers.
6771 * Returns 1 if (pos) is an eyespace for the color of the dragon currently
6772 * under owl investigation.
6773 */
6774int
6775owl_eyespace(int pos)
6776{
6777 int origin;
6778 ASSERT_ON_BOARD1(pos);
6779
6780 origin = current_owl_data->my_eye[pos].origin;
6781 return (ON_BOARD(origin)
6782 && (current_owl_data->my_eye[origin].color
6783 == current_owl_data->color)
6784 && max_eyes(&current_owl_data->my_eye[origin].value) > 0);
6785}
6786
6787
6788/* Used by autohelpers.
6789 * Returns 1 if (pos) is an eyespace for the color of the dragon currently
6790 * under owl investigation, which is possibly worth (at least) 2 eyes.
6791 */
6792int
6793owl_big_eyespace(int pos)
6794{
6795 int origin;
6796 ASSERT_ON_BOARD1(pos);
6797
6798 origin = current_owl_data->my_eye[pos].origin;
6799 return (ON_BOARD(origin)
6800 && (current_owl_data->my_eye[origin].color
6801 == current_owl_data->color)
6802 && max_eyes(&current_owl_data->my_eye[origin].value) >= 2);
6803}
6804
6805
6806/* Used by autohelpers.
6807 * Returns 1 if (pos) is an eyespace for the color of the dragon currently
6808 * under owl investigation.
6809 */
6810int
6811owl_mineye(int pos)
6812{
6813 int origin;
6814 ASSERT_ON_BOARD1(pos);
6815
6816 origin = current_owl_data->my_eye[pos].origin;
6817 if (!ON_BOARD(origin)
6818 || (current_owl_data->my_eye[origin].color
6819 != current_owl_data->color))
6820 return 0;
6821
6822 return min_eyes(&current_owl_data->my_eye[origin].value);
6823}
6824
6825
6826/* Used by autohelpers.
6827 * Returns 1 if (pos) is an eyespace for the color of the dragon currently
6828 * under owl investigation.
6829 */
6830int
6831owl_maxeye(int pos)
6832{
6833 int origin;
6834 ASSERT_ON_BOARD1(pos);
6835
6836 origin = current_owl_data->my_eye[pos].origin;
6837 if (!ON_BOARD(origin)
6838 || (current_owl_data->my_eye[origin].color
6839 != current_owl_data->color))
6840 return 0;
6841
6842 return max_eyes(&current_owl_data->my_eye[origin].value);
6843}
6844
6845
6846/* Used by autohelpers.
6847 * Returns 1 if (pos) is a non-marginal eyespace for the color of the
6848 * dragon currently under owl investigation.
6849 */
6850int
6851owl_proper_eye(int pos)
6852{
6853 ASSERT_ON_BOARD1(pos);
6854
6855 return ((current_owl_data->my_eye[pos].color
6856 == current_owl_data->color)
6857 && !current_owl_data->my_eye[pos].marginal);
6858}
6859
6860
6861/* Used by autohelpers.
6862 * Returns the effective size of the eyespace at pos.
6863 */
6864int
6865owl_eye_size(int pos)
6866{
6867 int origin;
6868 ASSERT_ON_BOARD1(pos);
6869
6870 origin = current_owl_data->my_eye[pos].origin;
6871 return current_owl_data->my_eye[origin].esize
6872 - current_owl_data->my_eye[origin].msize;
6873}
6874
6875
6876/* Used by autohelpers.
6877 * Returns whether str is a lunch.
6878 */
6879int
6880owl_lunch(int str)
6881{
6882 int k;
6883 int origin;
6884 ASSERT_ON_BOARD1(str);
6885 ASSERT1(current_owl_data->lunches_are_current, str);
6886 origin = find_origin(str);
6887
6888 for (k = 0; k < MAX_LUNCHES; k++) {
6889 if (current_owl_data->lunch[k] == NO_MOVE)
6890 break;
6891 if (current_owl_data->lunch[k] == origin)
6892 return 1;
6893 }
6894
6895 return 0;
6896}
6897
6898
6899/* Used by autohelpers.
6900
6901 * Returns 1 if (pos) is considered to be a strong dragon. This is
6902 * intended to be used to decide whether connecting to some external
6903 * stones is an easy way to live. The current implementation is fairly
6904 * conservative, requiring that (pos) was part of a dragon with two
6905 * eyes according to the static analysis. This requirement may be
6906 * relaxed considerably in the future.
6907 *
6908 * (pos) must not be part of the goal dragon.
6909 */
6910int
6911owl_strong_dragon(int pos)
6912{
6913 ASSERT_ON_BOARD1(pos);
6914 ASSERT1(IS_STONE(board[pos]), pos);
6915
6916 return (!current_owl_data->goal[pos]
6917 && dragon[pos].color == board[pos]
6918 && dragon[pos].crude_status == ALIVE);
6919}
6920
6921
6922static int
6923owl_escape_route(struct local_owl_data *owl)
6924{
6925 signed char modified_escape[BOARDMAX];
6926 int pos;
6927 memcpy(modified_escape, owl->escape_values, sizeof(modified_escape));
6928 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
6929 if (ON_BOARD(pos) && owl->cumulative_goal[pos])
6930 modified_escape[pos] = 0;
6931 return dragon_escape(owl->goal, owl->color, modified_escape);
6932}
6933
6934
6935/****************************
6936 * Initialization of owl data
6937 ****************************/
6938
6939/* This is a temporary solution. We want to be able to use the full
6940 * init_owl() also in owl_substantial.
6941 */
6942static void
6943reduced_init_owl(struct local_owl_data **owl, int at_bottom_of_stack)
6944{
6945 if (at_bottom_of_stack)
6946 owl_stack_pointer = 0;
6947 else
6948 owl_stack_pointer++;
6949
6950 check_owl_stack_size();
6951 *owl = owl_stack[owl_stack_pointer];
6952 VALGRIND_MAKE_WRITABLE(*owl, sizeof(struct local_owl_data));
6953}
6954
6955
6956/* Initialize owl data. Set at_bottom_of_stack to 1 the first time you
6957 * call init_owl() and to 0 any following time (only relevant if you
6958 * need more than one set of owl data).
6959 */
6960static void
6961init_owl(struct local_owl_data **owl, int target1, int target2, int move,
6962 int at_bottom_of_stack, int new_dragons[BOARDMAX])
6963{
6964 reduced_init_owl(owl, at_bottom_of_stack);
6965
6966 local_owl_node_counter = 0;
6967 (*owl)->lunches_are_current = 0;
6968 owl_mark_dragon(target1, target2, *owl, new_dragons);
6969 if (move != NO_MOVE)
6970 owl_update_goal(move, SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE, *owl, 0, NULL);
6971 compute_owl_escape_values(*owl);
6972}
6973
6974
6975/***********************
6976 * Storage of owl data
6977 ***********************/
6978
6979/* Check the size of the owl stack and extend it if too small. */
6980static void
6981check_owl_stack_size(void)
6982{
6983 while (owl_stack_size <= owl_stack_pointer) {
6984 owl_stack[owl_stack_size] = malloc(sizeof(*owl_stack[0]));
6985 gg_assert(owl_stack[owl_stack_size] != NULL);
6986 owl_stack_size++;
6987 }
6988}
6989
6990/* Push owl data one step upwards in the stack. Gets called from
6991 * push_owl.
6992 */
6993static void
6994do_push_owl(struct local_owl_data **owl)
6995{
6996 struct local_owl_data *new_owl = owl_stack[owl_stack_pointer];
6997
6998 /* Mark all the data in *new_owl as uninitialized. */
6999 VALGRIND_MAKE_WRITABLE(new_owl, sizeof(struct local_owl_data));
7000 /* Copy the owl data. */
7001 memcpy(new_owl->goal, (*owl)->goal, sizeof(new_owl->goal));
7002 memcpy(new_owl->cumulative_goal, (*owl)->cumulative_goal,
7003 sizeof(new_owl->cumulative_goal));
7004 memcpy(new_owl->boundary, (*owl)->boundary, sizeof(new_owl->boundary));
7005 memcpy(new_owl->neighbors, (*owl)->neighbors, sizeof(new_owl->neighbors));
7006 memcpy(new_owl->escape_values, (*owl)->escape_values,
7007 sizeof(new_owl->escape_values));
7008 new_owl->color = (*owl)->color;
7009
7010 new_owl->lunches_are_current = 0;
7011
7012 /* Needed for stack organization. Since there may be one or two sets
7013 * of owl data active at we don't know whether to restore from the
7014 * previos stack entry or two steps back.
7015 */
7016 new_owl->restore_from = *owl;
7017
7018 /* Finally move the *owl pointer. */
7019 *owl = new_owl;
7020}
7021
7022
7023/* Push owl data one step upwards in the stack. The stack is extended
7024 * with dynamically allocated memory if it is too small.
7025 *
7026 * This function no longer may move existing owl data around, so
7027 * existing pointers do not risk becoming invalid.
7028 */
7029static void
7030push_owl(struct local_owl_data **owl)
7031{
7032 owl_stack_pointer++;
7033 check_owl_stack_size();
7034 do_push_owl(owl);
7035}
7036
7037
7038/* Retrieve owl data from the stack. */
7039static void
7040pop_owl(struct local_owl_data **owl)
7041{
7042 *owl = (*owl)->restore_from;
7043 owl_stack_pointer--;
7044}
7045
7046
7047/*
7048 * List worms in order to track captures during owl reading
7049 * (GAIN/LOSS codes)
7050 */
7051static int
7052list_goal_worms(struct local_owl_data *owl, int goal_worm[MAX_GOAL_WORMS])
7053{
7054 int pos, k;
7055 int w = 0;
7056
7057 for (k = 0; k < MAX_GOAL_WORMS; k++)
7058 goal_worm[k] = NO_MOVE;
7059
7060 for (pos = BOARDMIN; pos < BOARDMAX && w < MAX_GOAL_WORMS; pos++) {
7061 if (ON_BOARD(pos)
7062 && board[pos]
7063 && owl->goal[pos] == 1) {
7064 int origin = find_origin(pos);
7065 for (k = 0; k < w; k++)
7066 if (goal_worm[k] == origin)
7067 break;
7068 if (k == w)
7069 goal_worm[w++] = pos;
7070 }
7071 }
7072
7073 /* experimental: let's try to fill up the array with other neighboring
7074 * opponent worms
7075 */
7076 if (1 && (w > 0) && (w < MAX_GOAL_WORMS)) {
7077 pos = goal_worm[0];
7078 for (k = 0; k < DRAGON2(pos).neighbors && w < MAX_GOAL_WORMS; k++) {
7079 int ii;
7080 int d = DRAGON2(pos).adjacent[k];
7081 if (DRAGON(d).color != owl->color)
7082 continue;
7083
7084 for (ii = BOARDMIN; ii < BOARDMAX && w < MAX_GOAL_WORMS; ii++)
7085 if (ON_BOARD(ii) && board[ii] && worm[ii].origin == ii
7086 && worm[ii].size >= 3 && dragon[ii].id == d)
7087 goal_worm[w++] = ii;
7088 }
7089 }
7090
7091 return w;
7092}
7093
7094static void
7095prepare_goal_list(int str, struct local_owl_data *owl,
7096 int list[MAX_GOAL_WORMS], int *flag,
7097 int *kworm, int do_list)
7098{
7099 gg_assert(flag != NULL);
7100
7101 if (kworm) {
7102 if (do_list)
7103 list_goal_worms(owl, list);
7104 /* N.B. We cannot use sizeof(list) below because a formal array
7105 * parameter implicitly is converted to a pointer and sizeof(list)
7106 * thus equals sizeof(int *), which is not what we want.
7107 */
7108 memcpy(dragon_goal_worms[dragon[str].id], list,
7109 sizeof(dragon_goal_worms[dragon[str].id]));
7110 *flag = 1;
7111 }
7112 else
7113 *flag = 0;
7114}
7115
7116static void
7117finish_goal_list(int *flag, int *wpos, int list[MAX_GOAL_WORMS], int index)
7118{
7119 gg_assert(flag != NULL);
7120 gg_assert(wpos != NULL);
7121
7122 *flag = 0;
7123 if (index == MAX_GOAL_WORMS)
7124 *wpos = NO_MOVE;
7125 else
7126 *wpos = list[index];
7127}
7128
7129
7130/* Returns the number of worms in the goal dragon, and a pointer to each */
7131
7132#if 0
7133static int
7134catalog_goal(struct local_owl_data *owl, int goal_worm[MAX_GOAL_WORMS])
7135{
7136 int pos;
7137 int worms = 0;
7138 int k;
7139
7140 for (k = 0; k < MAX_WORMS; k++)
7141 goal_worm[k] = NO_MOVE;
7142
7143 for (pos = BOARDMIN; pos < BOARDMAX && worms < MAX_WORMS; pos++)
7144 if (ON_BOARD(pos)
7145 && board[pos]
7146 && (owl->goal)[pos]) {
7147 int origin = find_origin(pos);
7148 if (pos == origin) {
7149 if (0) {
7150 DEBUG(DEBUG_SEMEAI, "goal worm: %1m\n", pos);
7151 }
7152 goal_worm[worms++] = pos;
7153 }
7154 }
7155 return worms;
7156}
7157#endif
7158
7159/***********************/
7160
7161/* Clear statistics. */
7162void
7163reset_owl_node_counter()
7164{
7165 global_owl_node_counter = 0;
7166}
7167
7168
7169/* Retrieve statistics. */
7170int
7171get_owl_node_counter()
7172{
7173 return global_owl_node_counter;
7174}
7175
7176
7177/*
7178 * Local Variables:
7179 * tab-width: 8
7180 * c-basic-offset: 2
7181 * End:
7182 */