gnugo-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnugo-devel] Big patch


From: Gunnar Farneback
Subject: [gnugo-devel] Big patch
Date: Wed, 07 Jan 2004 01:13:13 +0100
User-agent: EMH/1.14.1 SEMI/1.14.3 (Ushinoya) FLIM/1.14.2 (Yagi-Nishiguchi) APEL/10.3 Emacs/20.7 (sparc-sun-solaris2.7) (with unibyte mode)

This patch includes a lot of changes I made while Savannah was down.
Although it might be somewhat unwieldy I think it's better to get them
all now than lose time by trying to split it up.

- bugfix in dragon_invincible()
- compute_crude_status() revised to consider dragons with big
  territorial moyo value as alive
- semeai moves considered safe in mark_changed_dragon
- compare number of eyes when both colors pass in
  do_owl_analyze_semeai() instead of always consider it a seki
- do not use the attack point from owl if owl considers a dragon dead
  but semeai revises it to critical
- bugfix in break_through_helper() in reading.c
- new static function close_enough_for_proper_semeai() in semeai.c
- liberty_of_dragon() transformed into neighbor_of_dragon() in semeai.c
- in semeai(), be more careful when considering two dragons involved
  in a semeai
- new static function max_lunch_eye_value() in value_moves.c
- when restraining thrashing dragons, do not bother connecting
  inessential strings which cannot provide an eye (in
  estimate_strategical_value()) 
- new autohelper function adjacent_to_stone_in_atari
- influence tuning
- eye tuning
- owl tuning
- tuning

The regression delta (compared to CVS of January 1):

ld_owl:10       pass (fails in CVS)
blunder:17      PASS R7 [R7]
blunder:21      FAIL O4 [L9]
rosebud:1       PASS E16 [E16]
lazarus:13      FAIL M12 [R13|M8|L9]
trevorb:100     FAIL C4 [B1]
strategy2:80    PASS Q4 [P4|Q4|Q3|S8]
nicklas4:1103   PASS C3 [C2|C3]
nngs:220        FAIL R4 [L1|E7|G13|K9]
nngs:320        PASS B16 [B15|B16]
nngs:380        PASS H3 [!H2|S1]
nngs:710        fail (passes in CVS)
nngs:1090       PASS B16 [B17|B16]
trevorc:550     pass (fails in CVS)
trevorc:1360    FAIL G5 [F12]
global:36       pass (fails in CVS)
13x13:37        FAIL D7 [E10]
13x13:38        PASS G11 [G11]
13x13:60        PASS K5 [K5|L5]
strategy4:198   FAIL F1 [C10|S18]
owl1:330        PASS 1 R1 [1 R1]
owl1:331        PASS 1 R1 [1 (R1|S1|T2)]   
owl1:334        pass (fails in CVS)
owl1:335        pass (fails in CVS)
handtalk:18     pass (fails in CVS)
handtalk:20     PASS N18 [N18]
nngs2:270       PASS S19 [S19]
nngs2:300       PASS L10 [!Q13]
nngs2:460       PASS L2 [J4|K2|K3|K4|K5|L2]
nngs2:500       pass (fails in CVS)
nngs3:1110      PASS B7 [B7]
nngs4:40        PASS H3 [H3|F4]
nngs4:330       fail (passes in CVS)
nngs4:630       PASS B6 [B6]
nngs4:750       FAIL D5 [C7]
strategy5:230   pass (fails in CVS)
ninestones:40   fail (passes in CVS)
ninestones:50   PASS R13 [R13]
ninestones:190  pass (fails in CVS)
ninestones:670  PASS H7 [H7]
tactics1:106    PASS F8 [F8|F6]
gunnar:8        PASS P10 [!O13]
gunnar:45       pass (fails in CVS)
arend2:150      FAIL D7 [D6|C6]
arend2:230      PASS G14 [!H14]
nando:27        fail (passes in CVS)
thrash:3        PASS O5 [O5|N5|N4]
thrash:11       PASS S3 [S3]
gifu03:205      PASS P5 [P5]
gifu03:302      PASS B6 [C1|B6]
9x9:70          pass (fails in CVS)
9x9:110         pass (fails in CVS)
9x9:290         FAIL E2 [D2]

In total 39 new passes and 14 failures. No detailed analysis of the
failures this time but I've checked that they are acceptable.

/Gunnar

Index: engine/dragon.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v
retrieving revision 1.127
diff -u -r1.127 dragon.c
--- engine/dragon.c     31 Dec 2003 14:38:24 -0000      1.127
+++ engine/dragon.c     1 Jan 2004 12:42:37 -0000
@@ -1023,7 +1023,12 @@
   }
 
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (mx[pos] == 1)
+    /* Necessary to check eye margins here since the loop above only
+     * considers margins which are directly adjacent to some stone of
+     * the dragon.
+     */
+    if (mx[pos] == 1
+       && eye[pos].msize == 0)
       strong_eyes++;
   }
 
@@ -1665,6 +1670,9 @@
       return CRITICAL;
   }
 
+  if (DRAGON2(pos).moyo_territorial_value > 9.99)
+    return ALIVE;
+  
   return UNKNOWN;
 }
 
Index: engine/move_reasons.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/move_reasons.c,v
retrieving revision 1.119
diff -u -r1.119 move_reasons.c
--- engine/move_reasons.c       18 Nov 2003 08:55:46 -0000      1.119
+++ engine/move_reasons.c       1 Jan 2004 12:42:39 -0000
@@ -1524,7 +1524,7 @@
              worm_is_safe = 1;
            popgo();
        }
-       if (worm_is_safe) {
+       if (worm_is_safe || move_reason_type == SEMEAI_MOVE) {
          /* This string can now be considered safe. Hence we mark the
           * whole string as such:
           */
Index: engine/owl.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.186
diff -u -r1.186 owl.c
--- engine/owl.c        31 Dec 2003 07:03:39 -0000      1.186
+++ engine/owl.c        1 Jan 2004 12:42:42 -0000
@@ -335,9 +335,10 @@
   int save_verbose = verbose;
   int dummy_resulta;
   int dummy_resultb;
+  int dummy_semeai_move;
   double start = 0.0;
   int reading_nodes_when_called = get_reading_node_counter();
-
+  
   struct local_owl_data *owla;
   struct local_owl_data *owlb;
   
@@ -345,7 +346,9 @@
     resulta = &dummy_resulta;
   if (!resultb)
     resultb = &dummy_resultb;
-
+  if (!semeai_move)
+    semeai_move = &dummy_semeai_move;
+  
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
   
@@ -474,14 +477,14 @@
   if (move == PASS_MOVE) {
     DEBUG(DEBUG_OWL_PERFORMANCE,
          "analyze_semeai %1m vs. %1m, result %d %d %1m (%d, %d nodes, %f 
seconds)\n",
-         apos, bpos, *resulta, *resultb, semeai_move, local_owl_node_counter,
+         apos, bpos, *resulta, *resultb, *semeai_move, local_owl_node_counter,
          get_reading_node_counter() - reading_nodes_when_called,
          gg_cputime() - start);
   }
   else {
     DEBUG(DEBUG_OWL_PERFORMANCE,
          "analyze_semeai_after_move %C %1m: %1m vs. %1m, result %d %d %1m (%d, 
%d nodes, %f seconds)\n",
-         color, move, apos, bpos, *resulta, *resultb, semeai_move,
+         color, move, apos, bpos, *resulta, *resultb, *semeai_move,
          local_owl_node_counter,
          get_reading_node_counter() - reading_nodes_when_called,
          gg_cputime() - start);
@@ -547,6 +550,11 @@
   int dummy_move;
   int tested_moves;
   int critical_semeai_worms[MAX_SEMEAI_WORMS];
+  int sworm;
+  int we_might_be_inessential;
+  struct eyevalue probable_eyes_a;
+  struct eyevalue probable_eyes_b;
+  struct eyevalue dummy_eyes;
   
   SETUP_TRACE_INFO2("do_owl_analyze_semeai", apos, bpos);
 
@@ -614,8 +622,7 @@
 
   {
     int upos;
-    int sworm;
-
+    
     for (sworm = 0; sworm < s_worms; sworm++) {
       critical_semeai_worms[sworm] = 0;
       if (board[semeai_worms[sworm]] == other) {
@@ -644,14 +651,19 @@
      * threatened, try to save it.
      */
 
+    we_might_be_inessential = 1;
     for (sworm = 0; sworm < s_worms; sworm++)
-      if (board[semeai_worms[sworm]] == color
-         && attack(semeai_worms[sworm], NULL)
-         && find_defense(semeai_worms[sworm], &upos)) {
-       critical_semeai_worms[sworm] = 1;
-       owl_add_move(moves, upos, 85, "defend semeai worm", 1, 0, NO_MOVE,
-                    MAX_SEMEAI_MOVES);
-       TRACE("Added %1m %d (0)\n", upos, 85);
+      if (board[semeai_worms[sworm]] == color) {
+       if (important_semeai_worms[sworm])
+         we_might_be_inessential = 0;
+       
+       if (attack(semeai_worms[sworm], NULL)
+           && find_defense(semeai_worms[sworm], &upos)) {
+         critical_semeai_worms[sworm] = 1;
+         owl_add_move(moves, upos, 85, "defend semeai worm", 1, 0, NO_MOVE,
+                      MAX_SEMEAI_MOVES);
+         TRACE("Added %1m %d (0)\n", upos, 85);
+       }
       }
   }
 
@@ -662,13 +674,15 @@
    * of filling liberties until one of the dragons may be removed,
    * or a seki results. The first stage we call the owl phase.
    */
-  if (owl_phase) {
+  if (!owl_phase) {
+    set_eyevalue(&probable_eyes_a, 0, 0, 0, 0);
+    set_eyevalue(&probable_eyes_b, 0, 0, 0, 0);
+  }
+  else {
     /* First the vital moves. These include moves to attack or
      * defend the eyespace (e.g. nakade, or hane to reduce the
      * number of eyes) or moves to capture a lunch. 
      */
-    struct eyevalue probable_eyes_a;
-    struct eyevalue probable_eyes_b;
     int eyemin_a;
     int eyemin_b;
     int eyemax_a;
@@ -795,10 +809,10 @@
      * opponent semeai worms are allowed to be included for vital
      * moves.
      */
-    if (moves[0].pos == NO_MOVE) {
+    if (moves[0].pos == NO_MOVE || we_might_be_inessential) {
       include_semeai_worms_in_eyespace = 1;
       if (!owl_estimate_life(owlb, owla, vital_offensive_moves,
-                            &live_reasonb, komaster, 1, &probable_eyes_b,
+                            &live_reasonb, komaster, 1, &dummy_eyes,
                             &eyemin_b, &eyemax_b))
        semeai_review_owl_moves(vital_offensive_moves, owla, owlb, color,
                                &safe_outside_liberty_found,
@@ -1002,10 +1016,8 @@
    */
   if (tested_moves == 0) {
     const char *live_reasona;
-    struct eyevalue probable_eyes_a;
     int eyemin_a;
     int eyemax_a;
-    int sworm;
     for (sworm = 0; sworm < s_worms; sworm++) {
       if (board[semeai_worms[sworm]] == other) {
        if (important_semeai_worms[sworm])
@@ -1016,7 +1028,7 @@
     if (sworm == s_worms) {
       include_semeai_worms_in_eyespace = 1;
       if (!owl_estimate_life(owla, owlb, vital_defensive_moves,
-                            &live_reasona, komaster, 0, &probable_eyes_a,
+                            &live_reasona, komaster, 0, &dummy_eyes,
                             &eyemin_a, &eyemax_a)) {
        include_semeai_worms_in_eyespace = 0;
        *resulta = 0;
@@ -1029,14 +1041,34 @@
     }
   }
 
-  /* If we can't find a move and opponent passed, it's seki */
+  /* If we can't find a move and opponent passed, it's seki, unless
+   * one dragon has more eyes than the other.
+   */
   if (tested_moves == 0 && pass == 1) {
-    *resulta = WIN;
-    *resultb = 0;
-    *move = PASS_MOVE;
-    TRACE("Seki\n");
-    SGFTRACE_SEMEAI(PASS_MOVE, WIN, 0, "Seki");
-    READ_RETURN_SEMEAI(read_result, move, PASS_MOVE, WIN, 0);
+    if (max_eyes(&probable_eyes_a) < min_eyes(&probable_eyes_b)) {
+      *resulta = 0;
+      *resultb = 0;
+      *move = PASS_MOVE;
+      TRACE("You have more eyes.\n");
+      SGFTRACE_SEMEAI(PASS_MOVE, 0, 0, "You have more eyes");
+      READ_RETURN_SEMEAI(read_result, move, PASS_MOVE, 0, 0);
+    }
+    else if (max_eyes(&probable_eyes_b) < min_eyes(&probable_eyes_a)) {
+      *resulta = WIN;
+      *resultb = WIN;
+      *move = PASS_MOVE;
+      TRACE("I have more eyes\n");
+      SGFTRACE_SEMEAI(PASS_MOVE, WIN, WIN, "I have more eyes");
+      READ_RETURN_SEMEAI(read_result, move, PASS_MOVE, WIN, WIN);
+    }
+    else {
+      *resulta = WIN;
+      *resultb = 0;
+      *move = PASS_MOVE;
+      TRACE("Seki\n");
+      SGFTRACE_SEMEAI(PASS_MOVE, WIN, 0, "Seki");
+      READ_RETURN_SEMEAI(read_result, move, PASS_MOVE, WIN, 0);
+    }
   }
   
   /* If no move was found, then pass. */
@@ -1489,7 +1521,7 @@
   int result;
   struct local_owl_data *owl;
   int reading_nodes_when_called = get_reading_node_counter();
-  double start = 0;
+  double start = 0.0;
   int tactical_nodes;
   int move = NO_MOVE;
   int wpos = NO_MOVE;
@@ -2011,7 +2043,7 @@
   int result = 0;
   int reading_nodes_when_called = get_reading_node_counter();
   char saved_boundary[BOARDMAX];
-  double start = 0;
+  double start = 0.0;
   int tactical_nodes;
   int move = 0;
   int move2 = 0;
@@ -2137,7 +2169,7 @@
   int result;
   static struct local_owl_data *owl;
   int reading_nodes_when_called = get_reading_node_counter();
-  double start = 0;
+  double start = 0.0;
   int tactical_nodes;
   int move = NO_MOVE;
   int wpos = NO_MOVE;
@@ -2343,7 +2375,6 @@
       break;
 
     case 3:
-#if 1
       {
        int goalcount = 0;
 
@@ -2384,7 +2415,6 @@
        if (!moves)
          continue;
       }
-#endif
     } /* switch (pass) */
 
     /* For the up to MAX_MOVES best moves with value equal to
@@ -2531,7 +2561,7 @@
   struct local_owl_data *owl;
   int reading_nodes_when_called = get_reading_node_counter();
   char saved_goal[BOARDMAX];
-  double start = 0;
+  double start = 0.0;
   int tactical_nodes;
   int move = 0;
   int move2 = 0;
@@ -4182,6 +4212,16 @@
            continue;
          }
        }
+
+       /* If owl thinks the dragon is dead but the semeai code has
+         * revised the status to critical, then the owl attack point
+         * tends to be unreliable. Don't add it in that case.
+        *
+        * FIXME: Instead of just discarding it, we may want to test
+        *        whether it also wins the semeai.
+        */
+       if (DRAGON2(pos).owl_status != CRITICAL)
+         continue;
        
        /* If we've reached this far, the attack is okay. */
        if (DRAGON2(pos).owl_attack_code == GAIN) {
@@ -4318,7 +4358,7 @@
   int acode;
   int wpos = NO_MOVE;
   int wid = MAX_GOAL_WORMS;
-  double start = 0;
+  double start = 0.0;
 
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
Index: engine/reading.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/reading.c,v
retrieving revision 1.130
diff -u -r1.130 reading.c
--- engine/reading.c    24 Nov 2003 21:15:20 -0000      1.130
+++ engine/reading.c    1 Jan 2004 12:42:46 -0000
@@ -919,7 +919,7 @@
       /* If d is safe too, we have at least managed to break through. */
       if (!attack(dpos, &gpos))
        success = CUT;
-
+      
       /* Too bad, d could be attacked. We let O play the attack and
        * then try to make a second cut at e. But first we must test if
        * O at e is sufficient to capture d.
@@ -939,7 +939,7 @@
          popgo();
          return 0;
        }
-
+       
        if (trymove(gpos, color, "break_through_helper-F", Fpos,
                    EMPTY, NO_MOVE)) {
          if (trymove(epos, other, "break_through_helper-G", Fpos,
@@ -967,55 +967,62 @@
            }
            popgo();
          }
+         else {
+           /* Failed to cut at all. */
+           popgo();
+           popgo();
+           return 0;
+         }
          popgo();
        }
       }
       
       /* By now, we're sure a cut works, so now we can try 
-       * to capture something. */
-       if (!board[apos] || !board[bpos] || !defend_both(apos, bpos))
-         success = WIN;
-       else {
-         /* Both a and b could be defended, or didn't need to be.
-          * Let's see if a move at e is sufficient for O.
-          */
-         int attack_on_b = 0;
-         int attack_on_a = 0;
-
-         if (trymove(epos, color, "break_through_helper-B", Fpos, 
-                     EMPTY, NO_MOVE)) {
-           if (attack(bpos, NULL))
-             attack_on_b = 1;
-           else if (attack(apos, NULL))
-             attack_on_a = 1;
-           popgo();
-         }
-
-         /* Let O find a defense and play it. */
-         if (attack_on_a || attack_on_b) {
-           int hpos = NO_MOVE;
-
-           if (((attack_on_a && find_defense(apos, &hpos))
-               || (attack_on_b && find_defense(bpos, &hpos)))
-               && hpos != NO_MOVE
-               && trymove(hpos, color, "break_through_helper-C", Fpos,
-                          EMPTY, NO_MOVE)) {
-             /* Now we make a second cut at e, trying to capture
-              * either b or c.
-              */
-             if (trymove(epos, other, "break_through_helper-D", Fpos,
-                         EMPTY, NO_MOVE)) {
-               if (!board[bpos]
-                   || !board[cpos] 
-                   || !defend_both(bpos, cpos))
-                 success = WIN;
-               popgo();
-             }
+       * to capture something.
+       */
+      if (!board[apos] || !board[bpos] || !defend_both(apos, bpos))
+       success = WIN;
+      else {
+       /* Both a and b could be defended, or didn't need to be.
+        * Let's see if a move at e is sufficient for O.
+        */
+       int attack_on_b = 0;
+       int attack_on_a = 0;
+       
+       if (trymove(epos, color, "break_through_helper-B", Fpos, 
+                   EMPTY, NO_MOVE)) {
+         if (attack(bpos, NULL))
+           attack_on_b = 1;
+         else if (attack(apos, NULL))
+           attack_on_a = 1;
+         popgo();
+       }
+       
+       /* Let O find a defense and play it. */
+       if (attack_on_a || attack_on_b) {
+         int hpos = NO_MOVE;
+         
+         if (((attack_on_a && find_defense(apos, &hpos))
+              || (attack_on_b && find_defense(bpos, &hpos)))
+             && hpos != NO_MOVE
+             && trymove(hpos, color, "break_through_helper-C", Fpos,
+                        EMPTY, NO_MOVE)) {
+           /* Now we make a second cut at e, trying to capture
+            * either b or c.
+            */
+           if (trymove(epos, other, "break_through_helper-D", Fpos,
+                       EMPTY, NO_MOVE)) {
+             if (!board[bpos]
+                 || !board[cpos] 
+                 || !defend_both(bpos, cpos))
+               success = WIN;
              popgo();
            }
-           else
-             success = WIN; /* This should have been covered by
-                             * defend_both(), so probably unnecessary. */
+           popgo();
+         }
+         else
+           success = WIN; /* This should have been covered by
+                           * defend_both(), so probably unnecessary. */
        }
       }
     }
Index: engine/semeai.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/semeai.c,v
retrieving revision 1.65
diff -u -r1.65 semeai.c
--- engine/semeai.c     29 Nov 2003 08:56:33 -0000      1.65
+++ engine/semeai.c     1 Jan 2004 12:42:47 -0000
@@ -32,7 +32,7 @@
 static void find_moves_to_make_seki(void);
 static void update_status(int dr, enum dragon_status new_status, 
                          enum dragon_status new_safety);
-
+static int close_enough_for_proper_semeai(int apos, int bpos);
 
 /* semeai() searches for pairs of dragons of opposite color which
  * have safety DEAD. If such a pair is found, owl_analyze_semeai is
@@ -94,6 +94,15 @@
          || DRAGON2(bpos).safety == INESSENTIAL)
        continue;
 
+      /* Sometimes the dragons are considered neighbors but are too
+       * distant to constitute a proper semeai, e.g. in nngs4:650, P2
+       * vs. R3. Then the result of semeai reading may be meaningless
+       * and can confuse the analysis. In order to avoid this we check
+       * that the dragons either are directly adjacent or at least
+       * have one common liberty.
+       */
+      if (!close_enough_for_proper_semeai(apos, bpos))
+       continue;
 
       /* The array semeai_results_first[d1][d2] will contain the status
        * of d1 after the d1 d2 semeai, giving d1 the first move.
@@ -235,7 +244,7 @@
        && DRAGON2(str).hostile_neighbors == 1) {
       int k;
       int color = board[str];
-      int opponent;
+      int opponent = NO_MOVE;
       int certain;
       
       for (k = 0; k < DRAGON2(str).neighbors; k++) {
@@ -244,6 +253,8 @@
          break;
       }
 
+      ASSERT1(opponent != NO_MOVE, opponent);
+
       if (dragon[opponent].status != ALIVE)
        continue;
       
@@ -284,19 +295,16 @@
 }
 
 
-/* liberty_of_dragon(pos, origin) returns true if the vertex at (pos) is a
- * liberty of the dragon with origin at (origin).
+/* neighbor_of_dragon(pos, origin) returns true if the vertex at (pos) is a
+ * neighbor of the dragon with origin at (origin).
  */
 static int 
-liberty_of_dragon(int pos, int origin)
+neighbor_of_dragon(int pos, int origin)
 {
   int k;
   if (pos == NO_MOVE)
     return 0;
 
-  if (board[pos] != EMPTY)
-    return 0;
-
   for (k = 0; k < 4; k++)
     if (ON_BOARD(pos + delta[k]) && dragon[pos + delta[k]].origin == origin)
       return 1;
@@ -304,6 +312,28 @@
   return 0;
 }
 
+/* Check whether two dragons are directly adjacent or have at least
+ * one common liberty.
+ */
+static int
+close_enough_for_proper_semeai(int apos, int bpos)
+{
+  int pos;
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    if (board[pos] == EMPTY
+       && neighbor_of_dragon(pos, apos)
+       && neighbor_of_dragon(pos, bpos))
+      return 1;
+    else if (IS_STONE(board[pos])) {
+      if (is_same_dragon(pos, apos) && neighbor_of_dragon(pos, bpos))
+       return 1;
+      if (is_same_dragon(pos, bpos) && neighbor_of_dragon(pos, apos))
+       return 1;
+    }
+  }
+  
+  return 0;
+}
 
 /* This function adds the semeai related move reasons, using the information
  * stored in the dragon2 array.
@@ -332,10 +362,10 @@
        add_semeai_move(dragon2[d].semeai_defense_point, dragon2[d].origin);
        DEBUG(DEBUG_SEMEAI, "Adding semeai defense move for %1m at %1m\n",
              DRAGON(d).origin, dragon2[d].semeai_defense_point);
-       if (liberty_of_dragon(dragon2[d].semeai_defense_point,
-                             dragon2[d].semeai_target)
-           && !liberty_of_dragon(dragon2[d].semeai_defense_point,
-                                 dragon2[d].origin)
+       if (neighbor_of_dragon(dragon2[d].semeai_defense_point,
+                              dragon2[d].semeai_target)
+           && !neighbor_of_dragon(dragon2[d].semeai_defense_point,
+                                  dragon2[d].origin)
            && !is_self_atari(dragon2[d].semeai_defense_point, color)) {
          
          /* If this is a move to fill the non-common liberties of the
@@ -347,7 +377,7 @@
           liberties = findlib(dragon2[d].semeai_target, MAXLIBS, libs);
 
           for (r = 0; r < liberties; r++) {
-            if (!liberty_of_dragon(libs[r], dragon2[d].origin)
+            if (!neighbor_of_dragon(libs[r], dragon2[d].origin)
                && !is_self_atari(libs[r], color)
                && libs[r] != dragon2[d].semeai_defense_point) {
               owl_analyze_semeai_after_move(libs[r], color,
@@ -375,16 +405,16 @@
        add_semeai_move(dragon2[d].semeai_attack_point, dragon2[d].origin);
        DEBUG(DEBUG_SEMEAI, "Adding semeai attack move for %1m at %1m\n",
              DRAGON(d).origin, dragon2[d].semeai_attack_point);
-       if (liberty_of_dragon(dragon2[d].semeai_attack_point,
-                             dragon2[d].origin)
-           && !liberty_of_dragon(dragon2[d].semeai_attack_point,
+       if (neighbor_of_dragon(dragon2[d].semeai_attack_point,
+                              dragon2[d].origin)
+           && !neighbor_of_dragon(dragon2[d].semeai_attack_point,
                                  dragon2[d].semeai_target)
            && !is_self_atari(dragon2[d].semeai_attack_point, color)) {
 
           liberties = findlib(dragon2[d].origin, MAXLIBS, libs);
 
           for (r = 0; r < liberties; r++) {
-            if (!liberty_of_dragon(libs[r], dragon2[d].semeai_target)
+            if (!neighbor_of_dragon(libs[r], dragon2[d].semeai_target)
                && !is_self_atari(libs[r], color)
                && libs[r] != dragon2[d].semeai_attack_point) {
               owl_analyze_semeai_after_move(libs[r], color, dragon2[d].origin,
Index: engine/value_moves.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v
retrieving revision 1.114
diff -u -r1.114 value_moves.c
--- engine/value_moves.c        19 Nov 2003 07:53:49 -0000      1.114
+++ engine/value_moves.c        1 Jan 2004 12:42:47 -0000
@@ -1345,6 +1345,16 @@
   return result;
 }
 
+static int
+max_lunch_eye_value(int pos)
+{
+  int min;
+  int probable;
+  int max;
+  
+  estimate_lunch_eye_value(pos, &min, &probable, &max, 0);
+  return max;
+}
 
 /*
  * Estimate the direct territorial value of a move at (pos).
@@ -2097,15 +2107,8 @@
          break;
 
        /* If the lunch has no potential to create eyes, no points. */
-       {
-         int min;
-         int probable;
-         int max;
-
-         estimate_lunch_eye_value(aa, &min, &probable, &max, 0);
-         if (max == 0)
-           break;
-       }
+       if (max_lunch_eye_value(aa) == 0)
+         break;
        
        /* Can't use k in this loop too. */
        for (l = 0; l < next_lunch; l++)
@@ -2232,8 +2235,6 @@
         * This does not apply if we are doing scoring.
         *
         * FIXME: The margin of victory limit is not implemented.
-        * FIXME: We need some heuristic whether this connection is
-        * relevant at all, see e.g. thrash:4.
         */
       
        if (!doing_scoring) {
@@ -2241,7 +2242,7 @@
          aa = dragon[conn_worm1[move_reasons[r].what]].origin;
          bb = dragon[conn_worm2[move_reasons[r].what]].origin;
          cc = get_last_opponent_move(color);
-         
+
          if (cc != NO_MOVE
              && dragon[cc].status == DEAD
              && are_neighbor_dragons(aa, cc)
@@ -2249,8 +2250,15 @@
            if (aa == bb)
              this_value = 1.6 * dragon[cc].effective_size;
            else if (DRAGON2(aa).safety == INESSENTIAL
-                    || DRAGON2(bb).safety == INESSENTIAL)
-             this_value = 0.8 * dragon[cc].effective_size;
+                    || DRAGON2(bb).safety == INESSENTIAL) {
+             if ((DRAGON2(aa).safety == INESSENTIAL
+                  && max_lunch_eye_value(aa) == 0)
+                 || (DRAGON2(bb).safety == INESSENTIAL
+                     && max_lunch_eye_value(bb) == 0))
+               this_value = 0.0;
+             else
+               this_value = 0.8 * dragon[cc].effective_size;
+           }
            else
              this_value = 1.7 * dragon[cc].effective_size;
            
Index: patterns/barriers.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/barriers.db,v
retrieving revision 1.59
diff -u -r1.59 barriers.db
--- patterns/barriers.db        19 Nov 2003 07:53:49 -0000      1.59
+++ patterns/barriers.db        7 Jan 2004 00:02:38 -0000
@@ -3255,7 +3255,7 @@
 >non_oterritory(d);
 
 
-Pattern Nonterritory51
+Pattern Nonterritory49
 # gf New pattern. (3.5.3)
 # See gifu03:205.
 
@@ -3274,7 +3274,7 @@
 >non_xterritory(d);
 
 
-Pattern Nonterritory52
+Pattern Nonterritory50
 # gf New pattern. (3.5.3)
 # See gifu03:205.
 
@@ -3293,7 +3293,7 @@
 >non_xterritory(d);
 
 
-Pattern Nonterritory54
+Pattern Nonterritory51
 # gf New pattern. (3.5.3)
 # See gifu03:206.
 
@@ -3310,5 +3310,65 @@
 ;!safe_omove(a) && !oplay_defend_both(b,a,?,c,b,d)
 
 >non_oterritory(c);
+
+
+Pattern Nonterritory52
+# gf New pattern. (3.5.3)
+# See blunder:17.
+
+O??
+.XO
+?.?
+
+:8,t
+
+O??
+aCb
+?d?
+
+;lib(C)==2 && !adjacent_to_stone_in_atari(C) && !oplay_attack_either(a,a,b)
+
+>non_xterritory(d);
+
+
+Pattern Nonterritory53
+# gf New pattern. (3.5.3)
+# See gifu03:205.
+
+O.O
+.XO
+?.?
+
+:8,t
+
+Obc
+aXc
+?d?
+
+;oplay_attack(a,b,b) && !oplay_attack_either(a,a,c)
+
+>non_xterritory(d);
+
+
+Pattern Nonterritory54
+# gf New pattern. (3.5.3)
+# See nicklas4:1103
+
+OX.
+...
+...
+---
+
+:8,t
+
+ODc
+eab
+...
+---
+
+;oplay_defend_both(a,b,c,D,b) && oplay_attack(a,b,a)
+
+>non_oterritory(e);
+
 
 # END OF FILE
Index: patterns/eyes.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/eyes.db,v
retrieving revision 1.44
diff -u -r1.44 eyes.db
--- patterns/eyes.db    19 Nov 2003 07:53:49 -0000      1.44
+++ patterns/eyes.db    7 Jan 2004 00:02:39 -0000
@@ -5539,13 +5539,22 @@
 Pattern 78505
 
 ----
+..*.
+.XX
+
+:1122
+
+
+Pattern 78506
+
+----
 X.*.
 xX.
 
 :1122
 
 
-Pattern 78506
+Pattern 78507
 
 ----
 *.X.
@@ -5554,7 +5563,7 @@
 :1122
 
 
-Pattern 78507
+Pattern 78508
 
 ----
 *.X.
@@ -5563,7 +5572,7 @@
 :1122
 
 
-Pattern 78508
+Pattern 78509
 
 ----
 X.X.
@@ -5572,7 +5581,7 @@
 :1122
 
 
-Pattern 78509
+Pattern 78510
 
 ----
 X.X.
@@ -5594,7 +5603,7 @@
 
 Pattern 78521
 
-|X.
+|xx
 |XX
 |.X.
 +---
@@ -5610,6 +5619,16 @@
 +---
 
 :1111
+
+
+Pattern 78523
+
+|xx
+|XX
+|.*.
++---
+
+:1122
 
 
 Pattern 78550
Index: patterns/helpers.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/helpers.c,v
retrieving revision 1.57
diff -u -r1.57 helpers.c
--- patterns/helpers.c  13 Nov 2003 22:48:44 -0000      1.57
+++ patterns/helpers.c  7 Jan 2004 00:02:39 -0000
@@ -685,6 +685,25 @@
 }
 
 /* True if str is adjacent to a stone in atari, which is tactically
+ * attackable (to exclude pointless captures of snapback stones).
+ */
+int
+adjacent_to_stone_in_atari(int str)
+{
+  int adj;
+  int adjs[MAXCHAIN];
+  int k;
+
+  adj = chainlinks2(str, adjs, 1);
+  for (k = 0; k < adj; k++)
+    if (attack(adjs[k], NULL))
+      return 1;
+  
+  return 0;
+}
+
+
+/* True if str is adjacent to a stone in atari, which is tactically
  * defendable.
  */
 int
Index: patterns/mkpat.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/mkpat.c,v
retrieving revision 1.127
diff -u -r1.127 mkpat.c
--- patterns/mkpat.c    18 Nov 2003 00:00:02 -0000      1.127
+++ patterns/mkpat.c    7 Jan 2004 00:02:41 -0000
@@ -366,6 +366,8 @@
   {"surround_map",             2, 0, 0.01, "surround_map(%s, %s)"},
   {"oracle_threatens",         2, 0, 0.01, "oracle_threatens(%s, %s)"},
   {"value",                    0, 2, 0.0,  "(%s->value)"},
+  {"adjacent_to_stone_in_atari",1, 0, 1.0,
+                "adjacent_to_stone_in_atari(%s)"},
   {"adjacent_to_defendable_stone_in_atari", 1, 0, 1.0,
                 "adjacent_to_defendable_stone_in_atari(%s)"},
   {"good_attack_threat",       2, 0, 0.01, "register_good_attack_threat(%s, 
%s)"}
Index: patterns/owl_attackpats.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/owl_attackpats.db,v
retrieving revision 1.100
diff -u -r1.100 owl_attackpats.db
--- patterns/owl_attackpats.db  29 Nov 2003 08:56:33 -0000      1.100
+++ patterns/owl_attackpats.db  7 Jan 2004 00:02:42 -0000
@@ -1186,6 +1186,26 @@
 ;!oplay_disconnect(*,a,b)
 
 
+Pattern A242
+# gf New pattern. (3.5.3).
+# See e.g. nngs:1090.
+
+
+...o?
+..*O?
+...Xx
+-----
+
+:8,-,value(35)
+
+...o?
+ba*c?
+...Xx
+-----
+
+;xplay_disconnect(*,a,a,c) && xplay_disconnect(*,b,b,c)
+
+
 #########################################################
 #                                                       #
 #          Limiting moves on the first line             #
@@ -1448,11 +1468,30 @@
 
 
 Pattern A407
+# gf Added constraint. (3.5.3)
 
-O.X
-*Y.
-...
-...
+?O.X
+?*Y.
+?...
+?...
+
+:8,-,value(45)
+
+aO.X
+b*Y.
+c...
+?...
+
+;!(o_somewhere(a) && o_somewhere(b)) || x_somewhere(c)
+
+
+Pattern A407b
+# gf New pattern. (3.5.3)
+
+OO.X
+O.Y.
+o*..
+?...
 
 :8,-,value(45)
 
@@ -2124,6 +2163,18 @@
 :8,-,value(5)
 
 
+Pattern A518
+# gf New pattern. (3.5.3)
+# See nngs2:460
+
+O.xx?      destroye eye
+.*.XX
+....X
+-----
+
+:8,-,value(45)
+
+
 #########################################################
 #                                                       #
 #          Eye reducing moves on the first line         #
@@ -2501,6 +2552,24 @@
 ;lib(A)<3 && owl_eyespace(*)
 
 
+Pattern A622
+# gf New patterm. (3.5.3)
+# Compare D704b. See nngs3:450.
+
+xX.O       half eye sometimes missed
+X.*o
+----
+
+:8,-,value(35)
+
+bXaO
+X.*o
+----
+
+; xplay_attack(*,a,a)
+; && (x_somewhere(b) || !safe_omove(b))
+
+
 #########################################################
 #                                                       #
 #          Eye reducing moves in the center             #
@@ -3237,6 +3306,7 @@
 
 
 Pattern A910
+# gf Revised constraint. (3.5.3)
 
 XYX|          try nakade in corner
 .*.|
@@ -3248,7 +3318,7 @@
 a*.|
 ---+
 
-;!obvious_false_xeye(a)
+;!obvious_false_xeye(a) && owl_maxeye(*)>1
 
 
 Pattern A911
@@ -4432,18 +4502,20 @@
 
 
 Pattern A1126
-# tm New Pattern (3.1.23)  (see Pattern D1378)
+# tm New Pattern (3.1.23)
+# gf Revised constraint. (3.5.3)
+# See also D1378.
 
 O*O   prevent breakout & attack
 ?Y?
 
 :|,-,value(55)
 
-A*B
+a*b
 ?Y?
 
-; vital_chain(A) && vital_chain(B)
-; && xplay_attack_either(*,A,B)
+; vital_chain(a) && vital_chain(b)
+; && xplay_attack_either(*,a,b) && !xplay_connect(*,a,b)
 
 
 Pattern A1127
@@ -4598,18 +4670,68 @@
 Pattern A1134
 # pp New pattern (3.5.3).  See trevorb:120.
 # FIXME: is it better to do this algorithmically with owl boundaries?
+# gf Added explicit anchoring. (3.5.3)
 
-XOX        prevent escaping by capturing
+XOY        prevent escaping by capturing
 .*O
 ---
 
 :8,-,value(75)
 
-BOX
-.*A
+BOY
+.*a
+---
+
+; lib(a) == 1 && owl_escape_value(B) > 0
+
+
+Pattern A1134b
+# gf New pattern. (3.5.3).
+
+YOX        prevent escaping by capturing
+.*O
+---
+
+:8,-,value(75)
+
+YOB
+.*a
+---
+
+; lib(a) == 1 && owl_escape_value(B) > 0
+
+
+Pattern A1134c
+# gf New pattern. (3.5.3).
+
+XOY        prevent escaping by capturing
+.*O
+---
+
+:8,-,value(40)
+
+BOY
+.*a
+---
+
+; lib(a) == 1
+
+
+Pattern A1134d
+# gf New pattern. (3.5.3).
+# See 13x13b:23
+
+YOX        prevent escaping by capturing
+.*O
+---
+
+:8,-,value(40)
+
+YOB
+.*a
 ---
 
-; lib(A) == 1 && owl_escape_value(B) > 0
+; lib(a) == 1
 
 
 Pattern A1135
@@ -4644,6 +4766,25 @@
 ?A?
 
 ;owl_escape_value(A)>0 && !xplay_disconnect(*,A,B) && !oplay_connect(*,A,B)
+
+
+Pattern A1137
+# gf New pattern. (3.5.3)
+# Converse to D1125.
+
+xxx?
+...x
+.*O.
+?XXO
+
+:8,-,value(79)
+
+abc?
+...x
+.*O.
+?XXO
+
+;owl_escape_value(a) + owl_escape_value(b) + owl_escape_value(c) > 0
 
 
 #########################################################
Index: patterns/owl_defendpats.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/owl_defendpats.db,v
retrieving revision 1.109
diff -u -r1.109 owl_defendpats.db
--- patterns/owl_defendpats.db  29 Nov 2003 08:56:33 -0000      1.109
+++ patterns/owl_defendpats.db  7 Jan 2004 00:02:47 -0000
@@ -715,6 +715,7 @@
 
 
 Pattern D212
+# gf FIXME: This is not a second line move. Move the pattern.
 
 ??O???     capture one stone to improve eye space
 ?..OX?
@@ -894,6 +895,17 @@
 :8,-,value(35)
 
 
+Pattern D221b
+# gf New pattern. (3.5.3)
+
+oo?x        jump along second line
+O.*.
+O...
+----
+
+:8,-,value(45)
+
+
 Pattern D222
 # tm Pattern revised. (3.1.13)
 
@@ -1025,6 +1037,7 @@
 Pattern D230
 # tm New Pattern (3.1.16)
 # gf Not down to edge. (3.3.20)
+# gf Not if it can be cut off. Constraint added. (3.5.3)
 
 ?OO...?   expand along edge.
 o....*?
@@ -1033,6 +1046,13 @@
 
 :8,-,value(80)
 
+?Ob...?
+o...a*?
+?.....?
+-------
+
+;oplay_connect(*,a,*,b)
+
 
 Pattern D231
 # tm New Pattern (3.1.20) (see nngs:1320 owl_does_attack L15 M17)
@@ -1089,6 +1109,26 @@
 :8,n,value(35)
 
 
+Pattern D234
+# gf New pattern. (3.5.3).
+# See e.g. nngs:1090.
+
+
+...x?
+..*X?
+...Oo
+-----
+
+:8,-,value(35)
+
+...x?
+ba*C?
+...Oo
+-----
+
+;oplay_disconnect(*,a,a,C) && oplay_disconnect(*,b,b,C)
+
+
 #########################################################
 #                                                       #
 #          Expanding moves in the center                #
@@ -4133,6 +4173,7 @@
 
 Pattern D1102
 # tm reduced value (3.1.16)
+# gf Revised constraint. (3.5.3)
 
 ...        create cutting points
 X*X
@@ -4140,11 +4181,11 @@
 
 :|,-,value(50)
 
-...
+c.d
 A*B
 ?O?
 
-;lib(A)<=3 || lib(B)<=3
+;(lib(A)<=3 && olib(c)>2) || (lib(B)<=3 && olib(d)>2)
 
 
 Pattern D1102a
@@ -4876,6 +4917,60 @@
 ; && (oplay_attack(*,B) || oplay_attack(*,C)) && !oplay_connect(*,B,C)
 
 
+Pattern D1143
+# gf New pattern. (3.5.3).
+# See e.g. nngs:1090.
+
+
+.*XO
+XOXO
+..Oo
+----
+
+:8,-,value(65)
+
+.*Ac
+BOAc
+..do
+----
+
+;lib(A)==2 && lib(c)>1 && lib(d)>1 && oplay_attack(*,B)
+
+
+Pattern D1144
+# gf New pattern. (3.5.3).
+# See 13x13b:23.
+
+OXO        escape by capturing
+.*X
+---
+
+:8,-,value(82)
+
+bXc
+.*A
+---
+
+; lib(A) == 1 && (owl_escape_value(b) > 0 || owl_escape_value(c) > 0)
+
+
+Pattern D1144b
+# gf New pattern. (3.5.3).
+# See 13x13b:23.
+
+OXO        escape by capturing
+.*X
+---
+
+:8,-,value(40)
+
+bXc
+.*A
+---
+
+; lib(A) == 1
+
+
 ########################################################
 #                                                       #
 #                       Kikashi                         #
@@ -6193,6 +6288,28 @@
 ; && oplay_disconnect(*,d,*)
 
 
+Pattern D1356b
+# gf New pattern. (3.5.3)
+# See nngs4:40
+
+?....         jump towards safety
+O..*.
+o....
+.....
+-----
+
+:8,E,value(91)
+
+?..a.
+c..*.
+o..b.
+.....
+-----
+
+; (owl_escape_value(a) + owl_escape_value(*) + owl_escape_value(b) > 0)
+; && !oplay_disconnect(*,c,*)
+
+
 Pattern D1357
 
 o...o         block/connect to escape
@@ -6514,6 +6631,7 @@
 Pattern D1378
 # tm reduced value (3.1.17)
 # gf Revised constraint. (3.3.18)
+# See also A1126.
 
 X*X   breakout & attack
 ?O?
Index: patterns/owl_vital_apats.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/owl_vital_apats.db,v
retrieving revision 1.41
diff -u -r1.41 owl_vital_apats.db
--- patterns/owl_vital_apats.db 13 Nov 2003 22:48:44 -0000      1.41
+++ patterns/owl_vital_apats.db 7 Jan 2004 00:02:47 -0000
@@ -754,6 +754,7 @@
 # tm New Pattern (3.1.17)
 # gf Fixed symmetry. (3.3.6)
 # nn Modified constraint (3.3.14)
+# gf Revised constraint. (3.5.3)
 
 XoX
 o*o
@@ -766,7 +767,7 @@
 ; owl_proper_eye(*)
 ; && (owl_proper_eye(a) + owl_proper_eye(b) + owl_proper_eye(c) > 2)
 ; && safe_xmove(*)
-; && (owl_eye_size(*) <= 8 || !oplay_attack(*,*))
+; && ((owl_eye_size(*) <= 8 && owl_maxeye(*)>1) || !oplay_attack(*,*))
 
 
 Pattern VA45
Index: patterns/patterns.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/patterns.db,v
retrieving revision 1.120
diff -u -r1.120 patterns.db
--- patterns/patterns.db        29 Nov 2003 08:56:33 -0000      1.120
+++ patterns/patterns.db        7 Jan 2004 00:02:47 -0000
@@ -4088,6 +4088,7 @@
 
 
 Pattern EB407
+# gf Added constraint. (3.5.3)
 
 oO....        jump along edge
 O...*.
@@ -4096,6 +4097,13 @@
 
 :8,Oe,jump_out_helper
 
+oa....
+O...*.
+......
+------
+
+;!oplay_disconnect(*,*,a)
+
 
 Pattern EB408
 
@@ -5117,7 +5125,7 @@
 X*a..
 -----
 
-;(xplay_attack(*,a,a) || weak(b))
+;xplay_attack(*,a,a) || weak(b)
 
 
 Pattern EB706
@@ -5335,6 +5343,23 @@
 ;!oplay_defend_both(b,c,a,b) && oplay_defend_both(*,c,a,*)
 
 
+Pattern EB719
+# gf New pattern. (3.5.3)
+# Inexact followup but usually big.
+
+.XXO             block
+XOO*
+----
+
+:8,Xe,followup(6)
+
+aBBd
+Cee*
+----
+
+;alive(d) && critical(e) && !oplay_defend_both(*,?,a,B,C)
+
+
 ############################################################
 # Monkey jump and other intrusions on first and second lines
 ############################################################
@@ -13472,6 +13497,19 @@
 |..XOO..
 
 :8,jda
+
+
+Pattern EJ101
+# gf New pattern. (3.5.3)
+# See nngs:1020.
+
+......X
+.O..OX.
+.....*O
+.......
+-------
+
+:8,jcd
 
 
 ######################################################################
Index: patterns/patterns.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/patterns.h,v
retrieving revision 1.59
diff -u -r1.59 patterns.h
--- patterns/patterns.h 13 Nov 2003 22:48:44 -0000      1.59
+++ patterns/patterns.h 7 Jan 2004 00:02:47 -0000
@@ -297,6 +297,7 @@
 int connect_and_cut_helper2(int Apos, int bpos, int cpos, int color);
 int edge_double_sente_helper(int move, int apos, int bpos, int cpos);
 void test_attack_either_move(int move, int color, int worma, int wormb);
+int adjacent_to_stone_in_atari(int str);
 int adjacent_to_defendable_stone_in_atari(int str);
 void backfill_replace(int move, int str);
 
Index: patterns/patterns2.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/patterns2.db,v
retrieving revision 1.67
diff -u -r1.67 patterns2.db
--- patterns/patterns2.db       11 Nov 2003 21:48:59 -0000      1.67
+++ patterns/patterns2.db       7 Jan 2004 00:02:48 -0000
@@ -1070,6 +1070,22 @@
 ;(alive(a) || alive(b)) && !xplay_disconnect(*,C,D) && !oplay_connect(*,C,D)
 
 
+Pattern Cut304
+# gf New pattern. (3.5.3)
+
+?OO
+X..         cut through keima
+?*X
+
+:8,OB
+
+?OO
+Dab
+?*C
+
+;!oplay_defend_both(*,a,b,C,D) && !oplay_connect(*,C,D)
+
+
 #######################################
 #
 # Cut of one space jump from two stones
@@ -2371,6 +2387,7 @@
 Pattern Shape66
 # db increased negative shape (3.1.7)
 # ab added ??? lines added as jump is often good on 3rd line
+# gf This is way too general. Added constraint. (3.5.3)
 
 xX.         often bad to leave a gap
 O.*
@@ -2380,6 +2397,14 @@
 
 :8,-,shape(-3)
 
+xX.
+ca*
+.b.
+???
+???
+
+;oplay_disconnect(*,a,b,*,c)
+
 
 Pattern Shape67
 # gf New pattern. (3.1.3)
@@ -2985,6 +3010,7 @@
 Pattern Sente13b
 # gf Revised constraint. (3.1.10)
 # gf Revised constraint. (3.3.16)
+# gf Revised constraint. (3.5.3)
 
 .O
 *?
@@ -2992,11 +3018,12 @@
 :8,sO
 
 ba
-*?
+*c
 
 ;lib(a) == 2 && !attack(a) && olib(b) > 2 && safe_omove(*)
 ;&& (safe_xmove(*) || safe_xmove(b))
-;&& oplay_attack(*,b,b)==WIN
+;&& (oplay_attack(*,b,b)==WIN
+;    || (x_somewhere(c) && oplay_attack_either(*,b,b,c)))
 # Action adds a reverse followup value.
 >defend_against_atari(a)
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]