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 #include <stdio.h>
25 #include "liberty.h"
26 #include "patterns.h"
27 
28 
29 #define TRYMOVE(pos, color) trymove(pos, color, "helper", NO_MOVE)
30 #define OFFSET_BY(x, y) AFFINE_TRANSFORM(OFFSET(x, y), trans, move)
31 #define ARGS struct pattern *pattern, int trans, int move, int color
32 
33 
34 /* This file contains helper functions which assist the pattern matcher.
35  * They are invoked with (move) = the position on the board marked with '*'.
36  * They are invoked with color = WHITE or BLACK: any pieces on the
37  * board marked with 'O' in the pattern will always contain color,
38  * and 'X's contain OTHER_COLOR(color)
39  *
40  * The helper must return 0 if the pattern is rejected and 1 otherwise.
41  */
42 
43 
44 
45 
46 /* Jump out into nothingness. To avoid jumping into our own territory,
47  * we use the "area" measure. Also we never ever jump into our own
48  * established eyespace.
49  */
50 
51 int
jump_out_helper(ARGS)52 jump_out_helper(ARGS)
53 {
54   int own_eyespace;
55 
56   UNUSED(trans); UNUSED(pattern);
57 
58   own_eyespace = (white_eye[move].color == color);
59 
60   if (whose_area(OPPOSITE_INFLUENCE(color), move) != color && !own_eyespace)
61     return 1;
62   else
63     return 0;
64 }
65 
66 
67 /* Make a long jump into nothingness. Since these jumps are not
68  * securely connected we don't use them to jump into the opponent's
69  * zone of control.
70  */
71 
72 int
jump_out_far_helper(ARGS)73 jump_out_far_helper(ARGS)
74 {
75   if (whose_area(OPPOSITE_INFLUENCE(color), move) != OTHER_COLOR(color))
76     return jump_out_helper(pattern, trans, move, color);
77   else
78     return 0;
79 }
80 
81 
82 /* Active until the opponent has played his first stone.
83  */
84 
85 int
high_handicap_helper(ARGS)86 high_handicap_helper(ARGS)
87 {
88   UNUSED(trans); UNUSED(pattern); UNUSED(move);
89 
90   return !doing_scoring && stones_on_board(OTHER_COLOR(color)) == 0;
91 }
92 
93 
94 /* Active when the opponent is thought to be everywhere dead. This
95  * typically happens early in high handicap games on small boards.
96  * This helper is used by patterns intended to reinforce possible
97  * weaknesses in the position.
98  */
99 
100 int
reinforce_helper(ARGS)101 reinforce_helper(ARGS)
102 {
103   UNUSED(trans); UNUSED(pattern);
104 
105   return (!doing_scoring
106 	  && !lively_dragon_exists(OTHER_COLOR(color))
107 	  && safe_move(move, color));
108 }
109 
110 
111 /*
112  *
113  *  XXO      XXc            decrease eye space in sente (unless it kills)
114  *  .*X      e*a
115  *  ---      ---
116  *
117  * or
118  *
119  *  XXO      XXc            decrease eye space in sente (unless it kills)
120  *  .*X      e*a
121  *  XXO      XXd
122  *
123  * or
124  *
125  *  |XXO     |XXc           decrease eye space in sente (unless it kills)
126  *  |.*X     |e*a
127  *  |XXO     |XXd
128  *
129  * or
130  *
131  *  |XXO     |XXc           decrease eye space in sente (unless it kills)
132  *  |.*X     |e*a
133  *  +---     +---
134  *
135  */
136 
137 int
throw_in_atari_helper(ARGS)138 throw_in_atari_helper(ARGS)
139 {
140   int apos, bpos, cpos, dpos;
141   int success = 0;
142   int other = OTHER_COLOR(color);
143   int libs[2];
144   UNUSED(pattern);
145 
146   apos = OFFSET_BY(0, 1);
147   cpos = OFFSET_BY(-1, 1);
148   dpos = OFFSET_BY(1, 1);
149 
150   /* Find second liberty of the stone a. */
151   findlib(apos, 2, libs);
152   if (libs[0] != move)
153     bpos = libs[0];
154   else
155     bpos = libs[1];
156 
157   if (TRYMOVE(move, color)) {
158     if (!attack(cpos, NULL) && !(ON_BOARD(dpos) && attack(dpos, NULL))) {
159       if (TRYMOVE(bpos, other)) {
160 	if (attack(apos, NULL))
161 	  success = 1;
162 	popgo();
163       }
164       else {
165 	success = 1; /* X move at (bpos) would have been suicide */
166       }
167     }
168     popgo();
169   }
170 
171   /* The followup is to capture the "a" string. Estimate the value to
172    * twice the size.
173    */
174   add_followup_value(move, 2 * worm[apos].effective_size);
175   TRACE("...followup value %f\n", 2 * worm[apos].effective_size);
176 
177   return success;
178 }
179 
180 
181 /* This is intended for use in autohelpers. */
182 
183 /* Check whether the string at (str) can attack any surrounding
184  * string. If so, return false as the move to create a seki (probably)
185  * wouldn't work.
186  */
187 
188 int
seki_helper(int str)189 seki_helper(int str)
190 {
191   int r;
192   int adj;
193   int adjs[MAXCHAIN];
194 
195   adj = chainlinks(str, adjs);
196   for (r = 0; r < adj; r++)
197     if (worm[adjs[r]].attack_codes[0] != 0)
198       return 0;
199 
200   return 1;
201 }
202 
203 
204 /*
205  *  XO     aO
206  *  O*     O*
207  *
208  * Increase the cutstone2 field if * is a potential cutting point,
209  * i.e.  if it does work as a cutting point once 'a' has been
210  * defended. This helper is expected to always return 0.
211  */
212 
213 int
cutstone2_helper(ARGS)214 cutstone2_helper(ARGS)
215 {
216   int apos;
217   int bpos;
218   int cpos;
219   int dpos;
220   UNUSED(pattern);
221   UNUSED(color);
222 
223   if (stackp > 0)
224     return 0;
225 
226   apos = OFFSET_BY(-1, -1);
227   bpos = OFFSET_BY(-1,  0);
228   cpos = OFFSET_BY( 0, -1);
229 
230   if (worm[apos].defense_codes[0] == 0)
231     return 0;
232 
233   dpos = worm[apos].defense_points[0];
234 
235   if (TRYMOVE(dpos, board[apos])) {
236     if (!board[bpos] || attack(bpos, NULL)
237 	|| !board[cpos] || attack(cpos, NULL)
238 	|| safe_move(move, board[apos]) != 0) {
239       popgo();
240       worm[worm[apos].origin].cutstone2++;
241       propagate_worm(worm[apos].origin);
242       return 0;
243     }
244     popgo();
245   }
246 
247   return 0;
248 }
249 
250 /*
251  *  ?x??   ?x??
252  *  ?X..   ?Xb.
253  *  O*..   c*a.
254  *
255  * Is the push at * sente? c must have exactly two liberties. This is
256  * called edge_double_sente_helper because it mainly called for edge
257  * hanes, but it can be used anywhere on the board.
258  */
259 
260 int
edge_double_sente_helper(int move,int apos,int bpos,int cpos)261 edge_double_sente_helper(int move, int apos, int bpos, int cpos)
262 {
263   int color = board[cpos];
264   int success = 0;
265   ASSERT1((color == BLACK || color == WHITE), move);
266 
267   if (TRYMOVE(move, color)) {
268     ASSERT1(countlib(move) == 2, move);
269     success = connect_and_cut_helper(move, apos, bpos);
270     popgo();
271   }
272 
273   return success;
274 }
275 
276 /*
277  * This is intended for use in autohelpers.
278  *
279  * Give a conservative estimate of the value of saving the string (str)
280  * by capturing one opponent stone.
281  */
282 
283 void
threaten_to_save_helper(int move,int str)284 threaten_to_save_helper(int move, int str)
285 {
286   add_followup_value(move, 2.0 + 2.0 * worm[str].effective_size);
287   TRACE("...followup value %f\n", 2.0 + 2.0 * worm[str].effective_size);
288 }
289 
290 
291 /* For use in autohelpers.
292  *
293  * Adds a reverse followup value if the opponent's move here would threaten
294  * to capture (str).
295  */
296 void
prevent_attack_threat_helper(int move,int str)297 prevent_attack_threat_helper(int move, int str)
298 {
299   add_reverse_followup_value(move, 2.0 * worm[str].effective_size);
300   TRACE("...reverse followup value %f\n", 2.0 * worm[str].effective_size);
301 }
302 
303 
304 /* This function is obsolete.  Code in `value_moves.c' is more general. */
305 #if 0
306 
307 /*
308  * This is intended for use in autohelpers.
309  *
310  * Estimate the value of capturing the string (str) and add this as
311  * a followup value. We don't do this for too stupid looking threats,
312  * however, e.g. in a position like
313  *
314  * OOOO..
315  * XXX.*.
316  * XOOOX.
317  * XXXXO.
318  *
319  * where X can get out of atari with profit by capturing three O stones.
320  *
321  * Another case where we don't award the followup value is when the
322  * opponent can defend with a threat against our move, e.g. in this
323  * position:
324  *
325  * .OOOXX.
326  * .OXXO.X
327  * ..*.X..
328  * ..XX...
329  *
330  */
331 
332 void
333 threaten_to_capture_helper(int move, int str)
334 {
335   int adj, adjs[MAXCHAIN];
336   int defense_move;
337   int k;
338 
339   adj = chainlinks2(str, adjs, 1);
340   for (k = 0; k < adj; k++)
341     if (worm[adjs[k]].defense_codes[0] != 0
342 	&& !does_defend(move, adjs[k]))
343       return;
344 
345   if (!TRYMOVE(move, OTHER_COLOR(board[str])))
346     return;
347   if (find_defense(str, &defense_move) != 0
348       && defense_move != NO_MOVE
349       && TRYMOVE(defense_move, board[str])) {
350     if (board[move] == EMPTY || attack(move, NULL) != 0) {
351       popgo();
352       popgo();
353       return;
354     }
355     popgo();
356   }
357 
358   /* In addition to the move found by find_defense(), also try all
359    * chain breaking moves in the same way.
360    */
361   adj = chainlinks2(str, adjs, 1);
362   for (k = 0; k < adj; k++) {
363     int lib;
364     findlib(adjs[k], 1, &lib);
365     if (TRYMOVE(lib, board[str])) {
366       if (!attack(str, NULL)
367 	  && (board[move] == EMPTY || attack(move, NULL) != 0)) {
368 	popgo();
369 	popgo();
370 	return;
371       }
372       popgo();
373     }
374   }
375 
376   popgo();
377 
378   add_followup_value(move, 2.0 * worm[str].effective_size);
379   TRACE("...followup value %f\n", 2.0 * worm[str].effective_size);
380 }
381 
382 #endif
383 
384 
385 /*
386  * This is intended for use in autohelpers.
387  *
388  * Estimate the value of defending a string which can be put into
389  * atari and add this as a reverse followup value.
390  */
391 
392 void
defend_against_atari_helper(int move,int str)393 defend_against_atari_helper(int move, int str)
394 {
395   int adj, adjs[MAXCHAIN];
396   int libs[2];
397   int k;
398 
399   ASSERT1(countlib(str) == 2, str);
400 
401   /* No value if the string can capture out of atari. */
402   adj = chainlinks2(str, adjs, 1);
403   for (k = 0; k < adj; k++)
404     if (worm[adjs[k]].defense_codes[0] != 0
405 	&& !does_defend(move, adjs[k]))
406       return;
407 
408   /* No value if opponent has no safe atari. */
409   findlib(str, 2, libs);
410   if (!safe_move(libs[0], OTHER_COLOR(board[str]))
411       && !safe_move(libs[1], OTHER_COLOR(board[str])))
412     return;
413 
414   TRACE("...reverse followup value %f\n", 2.0 * worm[str].effective_size);
415   add_reverse_followup_value(move, 2.0 * worm[str].effective_size);
416 }
417 
418 
419 /*
420  * This is intended for use in conn.db autohelpers.
421  *
422  * Amalgamate either a with b or c with b, depending on which of the
423  * two dragons a and c is largest.
424  *
425  * If either of these pairs already have been amalgamated somehow,
426  * do nothing.
427  */
428 
429 void
amalgamate_most_valuable_helper(int apos,int bpos,int cpos)430 amalgamate_most_valuable_helper(int apos, int bpos, int cpos)
431 {
432   if (!is_same_dragon(apos, bpos) && !is_same_dragon(bpos, cpos)) {
433     if (dragon[apos].effective_size >= dragon[cpos].effective_size)
434       join_dragons(apos, bpos);
435     else
436       join_dragons(bpos, cpos);
437   }
438 }
439 
440 
441 /*
442  * This is intended for use in autohelpers.
443  *
444  * Returns 1 if (pos) is adjacent to a stone which can be captured by ko.
445  */
446 
447 int
finish_ko_helper(int pos)448 finish_ko_helper(int pos)
449 {
450   int adj, adjs[MAXCHAIN];
451   int lib;
452   int k;
453 
454   adj = chainlinks2(pos, adjs, 1);
455   for (k = 0; k < adj; k++) {
456     if (countstones(adjs[k]) == 1) {
457       findlib(adjs[k], 1, &lib);
458       if (is_ko(lib, board[pos], NULL))
459 	return 1;
460     }
461   }
462   return 0;
463 }
464 
465 
466 /*
467  * This is intended for use in autohelpers.
468  *
469  * Returns 1 if (ai, aj) is next to a ko point.
470  */
471 
472 int
squeeze_ko_helper(int pos)473 squeeze_ko_helper(int pos)
474 {
475   int libs[2];
476   int liberties;
477   int k;
478 
479   liberties = findlib(pos, 2, libs);
480   ASSERT1(liberties == 2, pos);
481 
482   for (k = 0; k < liberties; k++) {
483     int aa = libs[k];
484     if (is_ko(aa, OTHER_COLOR(board[pos]), NULL))
485       return 1;
486   }
487 
488   return 0;
489 }
490 
491 /*
492  * This is intended for use in autohelpers.
493  *
494  * If after playing a and b, the string at c can be attacked, this
495  * function adds a small fixed move value for a move which defends
496  * c.
497  */
498 
499 int
backfill_helper(int apos,int bpos,int cpos)500 backfill_helper(int apos, int bpos, int cpos)
501 {
502   int color = board[cpos];
503   int other = OTHER_COLOR(color);
504   int dpos  = NO_MOVE;
505 
506   if (TRYMOVE(apos, color)) {
507     if (TRYMOVE(bpos, other)) {
508       if (attack(cpos, NULL) && find_defense(cpos, &dpos)) {
509 	set_minimum_move_value(dpos, 0.1);
510 	TRACE("%o...setting min move value of %1m to 0.1\n", dpos);
511       }
512       popgo();
513     }
514     popgo();
515   }
516 
517   return 0;
518 }
519 
520 
521 /* Returns true if (apos) kills or threatens to kill (bpos). */
522 
523 int
owl_threatens_attack(int apos,int bpos)524 owl_threatens_attack(int apos, int bpos)
525 {
526   if (DRAGON2(bpos).owl_status == CRITICAL
527       && DRAGON2(bpos).owl_attack_point == apos)
528     return 1;
529 
530   if (DRAGON2(bpos).owl_threat_status == CAN_THREATEN_ATTACK)
531     if (DRAGON2(bpos).owl_attack_point == apos
532 	|| DRAGON2(bpos).owl_second_attack_point == apos)
533       return 1;
534 
535   return 0;
536 }
537 
538 
539 /* Returns true if O needs to connect at c in the position below after
540  * O at b and X at d, because X can cut at c. In general d is the
541  * second liberty of A, which must have exactly two liberties.
542  *
543  * |.X   |dX
544  * |XO	 |AO
545  * |XO	 |Ae
546  * |..	 |bc
547  */
548 
549 int
connect_and_cut_helper(int Apos,int bpos,int cpos)550 connect_and_cut_helper(int Apos, int bpos, int cpos)
551 {
552   int dpos;
553   int epos = NO_MOVE;
554   int other = board[Apos];
555   int color = OTHER_COLOR(other);
556   int libs[2];
557   int liberties = findlib(Apos, 2, libs);
558   int result = 0;
559   int k;
560 
561   gg_assert(IS_STONE(color));
562   gg_assert(liberties == 2);
563 
564   if (libs[0] == bpos)
565     dpos = libs[1];
566   else
567     dpos = libs[0];
568 
569   for (k = 0; k < 4; k++)
570     if (board[cpos + delta[k]] == color
571 	&& neighbor_of_string(cpos + delta[k], Apos)) {
572       epos = cpos + delta[k];
573       break;
574     }
575 
576   gg_assert(epos != NO_MOVE);
577 
578   if (TRYMOVE(bpos, color)) {
579     if (TRYMOVE(dpos, other)) {
580       if (TRYMOVE(cpos, other)) {
581 	if (board[bpos] == EMPTY
582 	    || board[epos] == EMPTY
583 	    || !defend_both(bpos, epos))
584 	  result = 1;
585 	popgo();
586       }
587       popgo();
588     }
589     popgo();
590   }
591 
592   return result;
593 }
594 
595 
596 
597 /*
598  * This is similar to connect_and_cut_helper(), except it starts with
599  * a move at A and that d is found as a general defense point for A. A
600  * is no longer restricted to two liberties.
601  *
602  * |.X   |dX
603  * |XO	 |XO
604  * |.O	 |Ae
605  * |..	 |bc
606  */
607 
608 int
connect_and_cut_helper2(int Apos,int bpos,int cpos,int color)609 connect_and_cut_helper2(int Apos, int bpos, int cpos, int color)
610 {
611   int dpos;
612   int epos = NO_MOVE;
613   int other = OTHER_COLOR(color);
614   int result = 0;
615   int k;
616 
617   gg_assert(IS_STONE(color));
618 
619 
620   if (TRYMOVE(Apos, color)) {
621     for (k = 0; k < 4; k++)
622       if (board[cpos + delta[k]] == other
623 	  && neighbor_of_string(cpos + delta[k], Apos)) {
624 	epos = cpos + delta[k];
625 	break;
626       }
627 
628     gg_assert(epos != NO_MOVE);
629 
630     if (TRYMOVE(bpos, other)) {
631       if (!find_defense(Apos, &dpos) || dpos == NO_MOVE) {
632 	popgo();
633 	popgo();
634 	return 0;
635       }
636 
637       if (TRYMOVE(dpos, color)) {
638 	if (TRYMOVE(cpos, color)) {
639 	  if (board[bpos] == EMPTY
640 	      || board[epos] == EMPTY
641 	      || !defend_both(bpos, epos))
642 	    result = 1;
643 	  popgo();
644 	}
645 	popgo();
646       }
647       popgo();
648     }
649     popgo();
650   }
651 
652   return result;
653 }
654 
655 
656 
657 void
test_attack_either_move(int move,int color,int worma,int wormb)658 test_attack_either_move(int move, int color, int worma, int wormb)
659 {
660   ASSERT_ON_BOARD1(move);
661   ASSERT1(board[move] == EMPTY, move);
662   ASSERT1(board[worma] == OTHER_COLOR(color)
663           && board[wormb] == OTHER_COLOR(color), move);
664 
665   if (!defend_both(worma, wormb)) {
666     if (0)
667       gprintf("%1m: Reject attack_either_move for %1m, %1m (can't defend both)\n",
668 	      move, worma, wormb);
669     return;
670   }
671   if (trymove(move, color, "test_attack_either_move", worma)) {
672     if (board[worma] == OTHER_COLOR(color)
673 	&& board[wormb] == OTHER_COLOR(color)) {
674       if (!find_defense(worma, NULL) || !find_defense(wormb, NULL)) {
675 	if (0)
676 	  gprintf("%1m: Rej. attack_either_move for %1m & %1m (regular attack)\n",
677 		  move, worma, wormb);
678       }
679       else if (!defend_both(worma, wormb))
680         add_either_move(move, ATTACK_STRING, worma, ATTACK_STRING, wormb);
681       else {
682 	if (0)
683 	  gprintf("%1m: Rej. attack_either_move for %1m & %1m (doesn't work)\n",
684 		  move, worma, wormb);
685       }
686     }
687     else
688       if (0)
689 	gprintf("%1m: Rej. attack_either_move for %1m & %1m (captured directly)\n",
690 		move, worma, wormb);
691     popgo();
692   }
693 }
694 
695 /* True if str is adjacent to a stone in atari, which is tactically
696  * attackable (to exclude pointless captures of snapback stones).
697  */
698 int
adjacent_to_stone_in_atari(int str)699 adjacent_to_stone_in_atari(int str)
700 {
701   int adj;
702   int adjs[MAXCHAIN];
703   int k;
704 
705   adj = chainlinks2(str, adjs, 1);
706   for (k = 0; k < adj; k++)
707     if (attack(adjs[k], NULL))
708       return 1;
709 
710   return 0;
711 }
712 
713 
714 /* True if str is adjacent to a stone in atari, which is tactically
715  * defendable.
716  */
717 int
adjacent_to_defendable_stone_in_atari(int str)718 adjacent_to_defendable_stone_in_atari(int str)
719 {
720   int adj;
721   int adjs[MAXCHAIN];
722   int k;
723 
724   adj = chainlinks2(str, adjs, 1);
725   for (k = 0; k < adj; k++)
726     if (attack_and_defend(adjs[k], NULL, NULL, NULL, NULL))
727       return 1;
728 
729   return 0;
730 }
731 
732 void
backfill_replace(int move,int str)733 backfill_replace(int move, int str)
734 {
735   int defense_move = NO_MOVE;
736 
737   if (TRYMOVE(move, OTHER_COLOR(board[str]))) {
738     if (attack_and_defend(str, NULL, NULL, NULL, &defense_move)) {
739       /* Must undo the trymove before adding the replacement move. */
740       popgo();
741       add_replacement_move(move, defense_move, board[str]);
742     }
743     else
744       popgo();
745   }
746 }
747 
748 
749 /* True if
750  * 1. White to move.
751  * 2. All white stones look dead.
752  * 3. Less than 40% of the board is filled or less than 20% of the
753  *    board is filled with white stones.
754  *
755  * This is intended for patterns forcing white to thrash around early
756  * in high handicap games, instead of passing because it looks like no
757  * stones can live.
758  */
759 int
thrash_around_helper(ARGS)760 thrash_around_helper(ARGS)
761 {
762   UNUSED(pattern);
763   UNUSED(trans);
764   UNUSED(move);
765 
766   /* Do not generate these moves when doing scoring or if fuseki move
767    * generation is disabled (typically used when solving life and
768    * death problems embedded on a big board).
769    */
770   if (doing_scoring
771       || disable_fuseki
772       || (stones_on_board(BLACK | WHITE) > board_size * board_size * 2 / 5
773 	  && stones_on_board(WHITE) > board_size * board_size / 5)
774       || color == BLACK
775       || lively_dragon_exists(WHITE))
776     return 0;
777 
778   return 1;
779 }
780 
781 
782 /* Returns true if
783  *
784  * 1. The board size is odd.
785  * 2. A white move is being generated.
786  * 3. The komi is less than or equal to zero.
787  * 4. str is placed at tengen.
788  * 5. At least 10 moves have been played.
789  * 6. The board is currently mirror symmetric.
790  *
791  * This is intended for patterns to break mirror go when black starts at
792  * tengen and then mirrors white. We only care about breaking the mirroring
793  * if komi is non-positive, otherwise the mirroring is to our advantage.
794  */
795 int
break_mirror_helper(int str,int color)796 break_mirror_helper(int str, int color)
797 {
798   if (board_size % 2 == 1
799       && color == WHITE
800       && komi <= 0.0
801       && I(str) == (board_size - 1) / 2
802       && J(str) == (board_size - 1) / 2
803       && stones_on_board(BLACK | WHITE) > 10
804       && test_symmetry_after_move(PASS_MOVE, EMPTY, 1))
805     return 1;
806 
807   return 0;
808 }
809 
810 
811 /* This helper is intended to detect semeai kind of positions where
812  * the tactical reading can't be trusted enough to allow amalgamation
813  * over presumably tactically dead strings.
814  *
815  * It has turned out to be best not to trust tactical reading of three
816  * and four liberty strings at all. Not trusting two liberty strings
817  * leads to an underamalgamation and unnecessarily many dragons on the
818  * board. Therefore we try to detect two liberty strings with an
819  * enclosed nakade, which after capturing leads to an unreliable
820  * reading at three or four liberties.
821  *
822  * More specifically we check whether the string has a neighbor with
823  * the following properties:
824  * 1. At least three stones in size.
825  * 2. All its liberties are common liberties with the string.
826  * 3. It has no second order liberties.
827  * 4. Its liberties are adjacent to no other strings than itself and
828  *    the primary string.
829  *
830  * If we find such a neighbor 1 is returned, otherwise 0.
831  */
distrust_tactics_helper(int str)832 int distrust_tactics_helper(int str)
833 {
834   int color = board[str];
835   int adj;
836   int adjs[MAXCHAIN];
837   int k;
838   int r;
839   int s;
840   int lib = countlib(str);
841 
842   ASSERT1(IS_STONE(board[str]), str);
843 
844   if (lib > 2)
845     return 1;
846   else if (lib == 1)
847     return 0;
848 
849   adj = chainlinks3(str, adjs, lib);
850   for (r = 0; r < adj; r++) {
851     int nakade = 1;
852     int adjlib;
853     int adjlibs[3];
854     if (countstones(adjs[r]) < 3)
855       continue;
856     adjlib = findlib(adjs[r], 3, adjlibs);
857     for (s = 0; s < adjlib; s++) {
858       int str_found = 0;
859       for (k = 0; k < 4; k++) {
860 	int pos = adjlibs[s] + delta[k];
861 	if (board[pos] == EMPTY
862 	    && !liberty_of_string(pos, adjs[r]))
863 	  nakade = 0;
864 	else if (board[pos] == color) {
865 	  if (same_string(pos, str))
866 	    str_found = 1;
867 	  else
868 	    nakade = 0;
869 	}
870 	else if (board[pos] == OTHER_COLOR(color)
871 		 && !same_string(pos, adjs[r]))
872 	  nakade = 0;
873       }
874       if (!str_found)
875 	nakade = 0;
876     }
877     if (nakade)
878       return 1;
879   }
880 
881   return 0;
882 }
883 
884 /*
885  * LOCAL Variables:
886  * tab-width: 8
887  * c-basic-offset: 2
888  * End:
889  */
890