gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] owl.c cleaning


From: Paul Pogonyshev
Subject: [gnugo-devel] owl.c cleaning
Date: Sun, 27 Apr 2003 00:50:39 -0400
User-agent: KMail/1.5.9

- owl_determine_life() bugfixed
- owl.c made completely 1D

minor changes include:
- two FIXMEs fixed, two new added ;)
- num_lunch renamed num_lunches to be consistent with num_eyes
  (in owl_determine_life())
- some minor code swapping which saves some 0.001% runtime ;)

the bug was in this piece of code:

        /* If this eyespace includes an owl inessential string, we
         * must assume that the pessimistic min is 0.
         */
        for (i = 0; i < board_size; i++)
          for (j = 0; j < board_size; j++)
            if (mw[POS(i, j)] > 1
                && eye[POS(i, j)].origin == pos
                && owl->inessential[POS(i, j)])
              pessimistic_min = 0;

if you look at how mw[] array is filled, you'll understand that the
above `if' can only fire up in eye origins. that is, `pessimistic_min'
was only reduced to zero if eyespace included an owl inessential
string in its origin.

fixing the bug above had brought a single pass:

owl1:304        PASS 0 [0]

the test must be fixable by improving owl_find_lunches() (that's one
of the two new FIXMEs), but it doesn't mean we should leave the bug
there.

the impact (of bugfix) on node counters is slightly negative, but
negligible:

  before: 1219215221 2215168 5438563
   after: 1220697901 2219660 5442484
              +0.12%  +0.20%  +0.07%


however, this is understandable, since now `pessimistic_min' is even
more pessimistic. another reason to improve owl_find_lunches() and
see if burying that "inessential stuff in eye" policy doesn't harm.

Paul


Index: engine/owl.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.151
diff -u -p -r1.151 owl.c
--- engine/owl.c        22 Apr 2003 02:48:05 -0000      1.151
+++ engine/owl.c        26 Apr 2003 21:18:11 -0000
@@ -2507,12 +2507,12 @@ owl_determine_life(struct local_owl_data
   int pessimistic_min;
   int attack_point;
   int defense_point;
-  int m, n;
+  int pos;
   int k;
   int lunch;
   int eye_color;
   int num_eyes = 0;
-  int num_lunch = 0;
+  int num_lunches = 0;
   int save_debug = debug;
   memset(mw, 0, sizeof(mw));
   memset(mz, 0, sizeof(mz));
@@ -2564,195 +2564,187 @@ owl_determine_life(struct local_owl_data
   else
     eye_color = BLACK_BORDER;
 
-  for (m = 0; m < board_size; m++)
-    for (n = 0; n < board_size; n++) {
-      int pos = POS(m, n);
-      if (board[pos] == color) {
-       for (k = 0; k < 8; k++) {
-         int pos2 = pos + delta[k];
-         if (ON_BOARD(pos2)
-             && eye[pos2].color == eye_color
-             && eye[pos2].origin != NO_MOVE
-             && !eye[pos2].marginal) {
-           if (owl->goal[pos])
-             mw[eye[pos2].origin]++;
-           else
-             mz[eye[pos2].origin]++;
-         }           
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    if (board[pos] == color) {
+      for (k = 0; k < 8; k++) {
+       int pos2 = pos + delta[k];
+       if (ON_BOARD(pos2)
+           && eye[pos2].color == eye_color
+           && !eye[pos2].marginal) {
+         if (owl->goal[pos])
+           mw[eye[pos2].origin]++;
+         else
+           mz[eye[pos2].origin]++;
        }
       }
     }
+  }
 
   /* Reset halfeye data. Set topological eye value to something big. */
-  for (m = 0; m < board_size; m++)
-    for (n = 0; n < board_size; n++) {
-      owl->half_eye[POS(m, n)].type = 0;
-      owl->half_eye[POS(m, n)].value = 10.0;
-    }
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    owl->half_eye[pos].type = 0;
+    owl->half_eye[pos].value = 10.0;
+  }
   
   /* Find topological half eyes and false eyes. */
   find_half_and_false_eyes(color, eye, owl->half_eye, mw);
 
   set_eyevalue(probable_eyes, 0, 0, 0, 0);
 
-  /* This test must be conditioned on (m, n) being its own origin,
-   * because some origins get moved during the topological eye
-   * code.
-   *
-   * FIXME: I don't think eye origins are moved around any more. 
-   */
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    if (ON_BOARD(pos) && mw[pos] > 1) {
+      int value = 0;
+      const char *reason = "";
+      int pos2;
+      compute_eyes_pessimistic(pos, &eyevalue, &pessimistic_min,
+                              &attack_point, &defense_point,
+                              eye, owl->half_eye);
+
+      /* If the eyespace is more in contact with own stones not in the goal,
+       * than with ones in the goal, there is a risk that we can be cut off
+       * from a major part of the eyespace. Thus we can't trust the opinion
+       * of compute_eyes().
+       *
+       * (Obviously this is a quite fuzzy heuristic. With more accurate
+       * connection analysis in the owl code we could do this more robustly.)
+       */
+      if (mw[pos] < mz[pos]
+         || (mw[pos] < 3 * mz[pos] && mz[pos] > 5))
+       pessimistic_min = 0;
 
-  for (m = 0; m < board_size; m++)
-    for (n = 0; n < board_size; n++) {
-      int pos = POS(m, n);
-      if (mw[pos] > 1 && eye[pos].origin == pos) {
-       int value = 0;
-       const char *reason = "";
-       int i, j;
-       compute_eyes_pessimistic(pos, &eyevalue, &pessimistic_min,
-                                &attack_point, &defense_point,
-                                eye, owl->half_eye);
-       /* If this eyespace includes an owl inessential string, we
-         * must assume that the pessimistic min is 0.
-        */
-       for (i = 0; i < board_size; i++)
-         for (j = 0; j < board_size; j++)
-           if (mw[POS(i, j)] > 1
-               && eye[POS(i, j)].origin == pos
-               && owl->inessential[POS(i, j)])
-             pessimistic_min = 0;
-
-       /* If the eyespace is more in contact with own stones not in the
-         * goal, than with ones in the goal, there is a risk that we
-         * can be cut off from a major part of the eyespace. Thus we
-         * can't trust the opinion of compute_eyes().
-        *
-        * (Obviously this is a quite fuzzy heuristic. With more
-        * accurate connection analysis in the owl code we could do
-        * this more robustly.)
-        */
-       for (i = 0; i < board_size; i++)
-         for (j = 0; j < board_size; j++)
-           if (eye[POS(i, j)].origin == pos
-               && (mw[POS(i, j)] < mz[POS(i,j)]
-                   || (mw[POS(i, j)] < 3 * mz[POS(i, j)]
-                       && mz[POS(i, j)] > 5)))
-             pessimistic_min = 0;
-
-       eyes_attack_points[num_eyes] = NO_MOVE;
-       eyevalue_list[num_eyes] = eyevalue;
-       *eyemin += pessimistic_min;
+      /* If this eyespace includes an owl inessential string, we must assume
+       * assume that the pessimistic min is 0.
+       *
+       * See owl1:304 for an example where this policy is important.
+       * FIXME: However, a better approach would be to improve inessential
+       *       strings detection (S13 in owl1:304 must count as essential).
+       */
+      if (pessimistic_min > 0) {
+       for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
+         if (ON_BOARD(pos2)
+             && eye[pos2].origin == pos
+             && owl->inessential[pos2]) {
+           pessimistic_min = 0;
+           break;
+         }
+       }
+      }
 
-       /* Fill in the value field for use by the owl_eyespace() function. */
-       eye[pos].value = eyevalue;
-       
-       /* This shortcut has been disabled for two reasons:
-        * 1. Due to the vital attack moves being able to later reduce
-        * the *eyemin, we can't say that a certain *eyemin is
-        * sufficient.
-        * 2. This part of the code is in no way time critical.
-        */
+      eyes_attack_points[num_eyes] = NO_MOVE;
+      eyevalue_list[num_eyes] = eyevalue;
+      *eyemin += pessimistic_min;
+
+      /* Fill in the value field for use by the owl_eyespace() function. */
+      eye[pos].value = eyevalue;
+
+      /* This shortcut has been disabled for two reasons:
+       * 1. Due to the vital attack moves being able to later reduce
+       * the *eyemin, we can't say that a certain *eyemin is
+       * sufficient.
+       * 2. This part of the code is in no way time critical.
+       */
 #if 0
-       /* Found two certain eyes---look no further. */
-       if (*eyemin >= 2) {
-         debug = save_debug;
-         return 2;
-       }
+      /* Found two certain eyes---look no further. */
+      if (*eyemin >= 2) {
+       debug = save_debug;
+       return 2;
+      }
 #endif
-       
-       if (eye_move_urgency(&eyevalue)) {
-         value = 50;
-         if (max_eyes(&eyevalue) - min_eyes(&eyevalue) == 2)
-           value = 70;
-         else if (max_eyes(&eyevalue) - pessimistic_min == 2)
-           value = 60;
-         reason = "vital move";
-       }
-       else if (max_eyes(&eyevalue) != pessimistic_min) {
-         if (max_eyes(&eyevalue) - pessimistic_min == 2)
-           value = 40;
-         else
-           value = 30;
-         reason = "marginal eye space";
-       }
 
-       if (value > 0) {
-         if (does_attack && attack_point != NO_MOVE) {
-           if (vital_values[attack_point] > 0) {
-             value += vital_values[attack_point];
-             if (value > 98)
-               value = 98; /* Higher values may get special interpretation. */
-           }
-           
-           TRACE("%s at %1m, score %d (eye at %1m, value %s, pessimistic_min 
%d)\n",
-                 reason, attack_point, value,
-                 pos, eyevalue_to_string(&eyevalue), pessimistic_min);
-           
-           if (eye[attack_point].marginal
-               && modify_stupid_eye_vital_point(owl, &attack_point, 1))
-             TRACE("vital point looked stupid, moved it to %1m\n",
-                   attack_point);
-           
-           owl_add_move(moves, attack_point, value, reason, 1, 0, NO_MOVE,
-                        MAX_MOVES);
-           vital_values[attack_point] = value;
-           eyes_attack_points[num_eyes] = attack_point;
+      if (eye_move_urgency(&eyevalue)) {
+       value = 50;
+       if (max_eyes(&eyevalue) - min_eyes(&eyevalue) == 2)
+         value = 70;
+       else if (max_eyes(&eyevalue) - pessimistic_min == 2)
+         value = 60;
+       reason = "vital move";
+      }
+      else if (max_eyes(&eyevalue) != pessimistic_min) {
+       if (max_eyes(&eyevalue) - pessimistic_min == 2)
+         value = 40;
+       else
+         value = 30;
+       reason = "marginal eye space";
+      }
+
+      if (value > 0) {
+       if (does_attack && attack_point != NO_MOVE) {
+         if (vital_values[attack_point] > 0) {
+           value += vital_values[attack_point];
+           if (value > 98)
+             value = 98; /* Higher values may get special interpretation. */
          }
-         /* The reason for the last set of tests is that we don't
-          * want to play a self atari in e.g. this position
-          *
-          * |XXX.
-          * |OOX.
-          * |.OX.
-          * |XOXX
-          * |XOOX
-          * |O*OX
-          * +----
-          *
-          * but it's okay in this position
-          * 
-          * |XXXXX
-          * |....X
-          * |OOOOX
-          * |.XXOX
-          * |.*XOX
-          * +-----
-          *
-          * In both cases * is the vital point according to the graph
-          * matching. The significant difference is that in the first
-          * case the vital point is adjacent to stones in the goal.
-          */
-         else if (!does_attack
-                  && defense_point != NO_MOVE
-                  && board[defense_point] == EMPTY
-                  && (!liberty_of_goal(defense_point, owl)
-                      || !is_self_atari(defense_point, color)
-                      || is_ko(defense_point, color, NULL)
-                      || safe_move(defense_point, color) != 0)) {
-           if (vital_values[defense_point] > 0) {
-             value += vital_values[defense_point];
-             if (value > 98)
-               value = 98; /* Higher values may get special interpretation. */
-           }
-           
-           TRACE("%s at %1m, score %d (eye at %1m, value %s, pessimistic_min 
%d)\n",
-                 reason, defense_point, value, pos,
-                 eyevalue_to_string(&eyevalue), pessimistic_min);
-
-           if ((eye[defense_point].marginal
-                || eye[defense_point].origin != pos)
-               && modify_stupid_eye_vital_point(owl, &defense_point, 0))
-             TRACE("vital point looked stupid, moved it to %1m\n",
-                   defense_point);
-           
-           owl_add_move(moves, defense_point, value, reason, 1, 0, NO_MOVE,
-                        MAX_MOVES);
-           vital_values[defense_point] = value;
+
+         TRACE("%s at %1m, score %d (eye at %1m, value %s, pessimistic_min 
%d)\n",
+               reason, attack_point, value,
+               pos, eyevalue_to_string(&eyevalue), pessimistic_min);
+
+         if (eye[attack_point].marginal
+             && modify_stupid_eye_vital_point(owl, &attack_point, 1))
+           TRACE("vital point looked stupid, moved it to %1m\n",
+                 attack_point);
+
+         owl_add_move(moves, attack_point, value, reason, 1, 0, NO_MOVE,
+                      MAX_MOVES);
+         vital_values[attack_point] = value;
+         eyes_attack_points[num_eyes] = attack_point;
+       }
+
+       /* The reason for the last set of tests is that we don't
+        * want to play a self atari in e.g. this position
+        *
+        * |XXX.
+        * |OOX.
+        * |.OX.
+        * |XOXX
+        * |XOOX
+        * |O*OX
+        * +----
+        *
+        * but it's okay in this position
+        * 
+        * |XXXXX
+        * |....X
+        * |OOOOX
+        * |.XXOX
+        * |.*XOX
+        * +-----
+        *
+        * In both cases * is the vital point according to the graph
+        * matching. The significant difference is that in the first
+        * case the vital point is adjacent to stones in the goal.
+        */
+       else if (!does_attack
+                && defense_point != NO_MOVE
+                && board[defense_point] == EMPTY
+                && (!liberty_of_goal(defense_point, owl)
+                    || !is_self_atari(defense_point, color)
+                    || is_ko(defense_point, color, NULL)
+                    || safe_move(defense_point, color) != 0)) {
+         if (vital_values[defense_point] > 0) {
+           value += vital_values[defense_point];
+           if (value > 98)
+             value = 98; /* Higher values may get special interpretation. */
          }
+
+         TRACE("%s at %1m, score %d (eye at %1m, value %s, pessimistic_min 
%d)\n",
+               reason, defense_point, value, pos,
+               eyevalue_to_string(&eyevalue), pessimistic_min);
+
+         if ((eye[defense_point].marginal
+              || eye[defense_point].origin != pos)
+             && modify_stupid_eye_vital_point(owl, &defense_point, 0))
+           TRACE("vital point looked stupid, moved it to %1m\n",
+                 defense_point);
+
+         owl_add_move(moves, defense_point, value, reason, 1, 0, NO_MOVE,
+                      MAX_MOVES);
+         vital_values[defense_point] = value;
        }
-       num_eyes++;
       }
+      num_eyes++;
     }
+  }
 
   /* Sniff each lunch for nutritional value. The assumption is that
    * capturing the lunch is gote, therefore the number of half eyes
@@ -2774,28 +2766,21 @@ owl_determine_life(struct local_owl_data
        set_eyevalue(&e, 0, 0, lunch_probable, lunch_probable);
        *eyemax += lunch_max;
 
-       if (lunch_probable == 0)
+       if (lunch_probable == 0) {
+         if (countstones(owl->lunch[lunch]) == 1)
+           continue;
          value = 20;
-       else if (lunch_probable == 1 && lunch_max == 1) {
-         value = 60 + countstones(owl->lunch[lunch]);
        }
+       else if (lunch_probable == 1 && lunch_max == 1)
+         value = 60 + countstones(owl->lunch[lunch]);
        else if (lunch_probable == 1 && lunch_max == 2)
          value = 70 + countstones(owl->lunch[lunch]);
        else
          value = 75 + countstones(owl->lunch[lunch]);
-       
+
        if (owl->lunch_attack_code[lunch] != WIN)
          value -= 10;
 
-       if (value < 21  && countstones(owl->lunch[lunch]) == 1) {
-         /* FIXME: consistent with previous implementation, but
-          *        is this necessary ? if I'm not mistaken, here
-          *        e is 0000, so remove this shouldn't hurt ... */
-         num_lunch++;
-         eyevalue_list[num_eyes++] = e;
-         continue;
-       }
-
        if (does_attack) {
          defense_point = improve_lunch_defense(owl->lunch[lunch],
                                                
owl->lunch_defense_point[lunch]);
@@ -2807,10 +2792,10 @@ owl_determine_life(struct local_owl_data
             * to be adapted accordingly.
             */
            int ne;
-           for (ne = 0; ne < num_eyes - num_lunch; ne++)
+           for (ne = 0; ne < num_eyes - num_lunches; ne++)
              if (eyes_attack_points[ne] == defense_point)
                break;
-           gg_assert(ne < num_eyes - num_lunch);
+           gg_assert(ne < num_eyes - num_lunches);
            /* merge eye values */
            add_eyevalues(&eyevalue_list[ne], &e, &eyevalue_list[ne]);
            /* and adjust */
@@ -2818,7 +2803,7 @@ owl_determine_life(struct local_owl_data
            eyevalue_list[ne].b = 0;
          } 
          else {
-           num_lunch++;
+           num_lunches++;
            eyevalue_list[num_eyes++] = e;
          }
 
@@ -2836,7 +2821,7 @@ owl_determine_life(struct local_owl_data
                lunch_probable, lunch_max);
          owl_add_move(moves, attack_point, value, "eat lunch",
                       1, 0, NO_MOVE, MAX_MOVES);
-         num_lunch++;
+         num_lunches++;
          eyevalue_list[num_eyes++] = e;
        }
       }
@@ -2845,7 +2830,7 @@ owl_determine_life(struct local_owl_data
   /* now, totalize the eye potential */
   {
     int ne;
-    for (ne = 0; ne < num_eyes - num_lunch; ne++)
+    for (ne = 0; ne < num_eyes - num_lunches; ne++)
       add_eyevalues(probable_eyes, &eyevalue_list[ne], probable_eyes);
 
     *eyemax += max_eyes(probable_eyes);
@@ -2855,7 +2840,7 @@ owl_determine_life(struct local_owl_data
      * each other and combination moves (i.e. double threats to create an
      * eye).
      */
-    if (num_eyes - num_lunch > 1 && max_eye_threat(probable_eyes) > 1)
+    if (num_eyes - num_lunches > 1 && max_eye_threat(probable_eyes) > 1)
       *eyemax += 1;
 
     for (; ne < num_eyes; ne++)
@@ -4321,8 +4306,8 @@ owl_connection_defends(int move, int tar
 static void
 owl_find_lunches(struct local_owl_data *owl)
 {
-  int m, n;
   int k;
+  int pos;
   int lunches = 0;
   int prevlunch;
   int lunch;
@@ -4344,134 +4329,132 @@ owl_find_lunches(struct local_owl_data *
   memset(owl->inessential, 0, sizeof(owl->inessential));
   
   memset(already_checked, 0, sizeof(already_checked));
-  for (m = 0; m < board_size; m++)
-    for (n = 0; n < board_size; n++) {
-      int pos = POS(m, n);
-      if (board[pos] == color && owl->goal[pos]) {
-       /* Loop over the eight neighbors. */
-       for (k = 0; k < 8; k++) {
-         int d = delta[k];
-         
-         /* If the immediate neighbor is empty, we look two steps away. */
-         if (k < 4 && board[pos + d] == EMPTY)
-           d *= 2;
-         
-         if (board[pos + d] != other)
-           continue;
-           
-         lunch = find_origin(pos + d);
-         if (already_checked[lunch])
-           continue;
-         already_checked[lunch] = 1;
-         
-         attack_and_defend(lunch, &acode, &apos, &dcode, &dpos);
-         if (acode != 0) {
-           owl->lunch[lunches] = lunch;
-           owl->lunch_attack_code[lunches]  = acode;
-           owl->lunch_attack_point[lunches] = apos;
-           owl->lunch_defend_code[lunches]  = dcode;
-           if (dcode != 0)
-             owl->lunch_defense_point[lunches] = dpos;
-           else
-             owl->lunch_defense_point[lunches] = NO_MOVE;
-           lunches++;
-           if (lunches == MAX_LUNCHES) {
-             sgf_dumptree = save_sgf_dumptree;
-             count_variations = save_count_variations;
-             owl->lunches_are_current = 1;
-             return;
-           }
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    if (board[pos] == color && owl->goal[pos]) {
+      /* Loop over the eight neighbors. */
+      for (k = 0; k < 8; k++) {
+       int pos2 = pos + delta[k];
+
+       /* If the immediate neighbor is empty, we look two steps away. */
+       if (k < 4 && board[pos2] == EMPTY)
+         pos2 += delta[k];
+
+       if (board[pos2] != other)
+         continue;
+
+       lunch = find_origin(pos2);
+       if (already_checked[lunch])
+         continue;
+       already_checked[lunch] = 1;
+
+       attack_and_defend(lunch, &acode, &apos, &dcode, &dpos);
+       if (acode != 0) {
+         owl->lunch[lunches] = lunch;
+         owl->lunch_attack_code[lunches]  = acode;
+         owl->lunch_attack_point[lunches] = apos;
+         owl->lunch_defend_code[lunches]  = dcode;
+         if (dcode != 0)
+           owl->lunch_defense_point[lunches] = dpos;
+         else
+           owl->lunch_defense_point[lunches] = NO_MOVE;
+         lunches++;
+         if (lunches == MAX_LUNCHES) {
+           sgf_dumptree = save_sgf_dumptree;
+           count_variations = save_count_variations;
+           owl->lunches_are_current = 1;
+           return;
          }
-         else if (!owl->inessential[lunch]) {
-           /* Test for inessentiality. */
-           int adj;
-           int adjs[MAXCHAIN];
-           int num_stones;
-           int stones[MAX_BOARD * MAX_BOARD];
-           int liberties;
-           int libs[MAXLIBS];
-           int r;
-           int essential = 0;
-           int superstring[BOARDMAX];
-
-           /* First check the neighbors of the string. */
-           adj = chainlinks(lunch, adjs);
-           for (r = 0; r < adj; r++) {
-             if (!owl->goal[adjs[r]] || attack(adjs[r], NULL) != 0) {
-               essential = 1;
-               break;
-             }
+       }
+       else if (!owl->inessential[lunch]) {
+         /* Test for inessentiality. */
+         int adj;
+         int adjs[MAXCHAIN];
+         int num_stones;
+         int stones[MAX_BOARD * MAX_BOARD];
+         int liberties;
+         int libs[MAXLIBS];
+         int r;
+         int essential = 0;
+         int superstring[BOARDMAX];
+
+         /* First check the neighbors of the string. */
+         adj = chainlinks(lunch, adjs);
+         for (r = 0; r < adj; r++) {
+           if (!owl->goal[adjs[r]] || attack(adjs[r], NULL) != 0) {
+             essential = 1;
+             break;
            }
-           
-           if (essential)
-             continue;
+         }
 
-           find_superstring_stones_and_liberties(lunch, &num_stones, stones,
-                                                 &liberties, libs, 0);
+         if (essential)
+           continue;
 
-           memset(superstring, 0, sizeof(superstring));
-           for (r = 0; r < num_stones; r++)
-             superstring[stones[r]] = 1;
-           
-           for (r = 0; r < liberties; r++) {
-             int bpos = libs[r];
-             int goal_found = 0;
-             int s;
-
-             for (s = 0; s < 4; s++) {
-               int cpos = bpos + delta[s];
-
-               if (!ON_BOARD(cpos))
-                 continue;
-               if (board[cpos] == color) {
-                 if (attack(cpos, NULL) != 0) {
-                   essential = 1;
-                   break;
-                 }
-                 else if (owl->goal[cpos])
-                   goal_found = 1;
-                 else {
-                   essential = 1;
-                   break;
-                 }
-               }
-               else if (board[cpos] == other
-                        && !superstring[cpos]) {
+         find_superstring_stones_and_liberties(lunch, &num_stones, stones,
+                                               &liberties, libs, 0);
+
+         memset(superstring, 0, sizeof(superstring));
+         for (r = 0; r < num_stones; r++)
+           superstring[stones[r]] = 1;
+
+         for (r = 0; r < liberties; r++) {
+           int bpos = libs[r];
+           int goal_found = 0;
+           int s;
+
+           for (s = 0; s < 4; s++) {
+             int cpos = bpos + delta[s];
+
+             if (!ON_BOARD(cpos))
+               continue;
+             if (board[cpos] == color) {
+               if (attack(cpos, NULL) != 0) {
                  essential = 1;
                  break;
                }
-             }
-             if (!goal_found) {
-               /* Requirement 1 not satisfied. Test requirement 1b.
-                * N.B. This is a simplified topological eye test.
-                * The simplification may be good, bad, or neutral.
-                */
-               int off_board = 0;
-               int diagonal_goal = 0;
-               for (s = 4; s < 8; s++) {
-                 if (!ON_BOARD(bpos + delta[s]))
-                   off_board++;
-                 else if (owl->goal[bpos + delta[s]])
-                   diagonal_goal++;
-               }
-               if (diagonal_goal + (off_board >= 2) < 2)
+               else if (owl->goal[cpos])
+                 goal_found = 1;
+               else {
                  essential = 1;
+                 break;
+               }
              }
-
-             if (essential)
+             else if (board[cpos] == other
+                      && !superstring[cpos]) {
+               essential = 1;
                break;
+             }
            }
-           
-           if (!essential) {
-             TRACE("Inessential string found at %1m.\n", lunch);
-             for (r = 0; r < num_stones; r++)
-               owl->inessential[stones[r]] = 1;
+           if (!goal_found) {
+             /* Requirement 1 not satisfied. Test requirement 1b.
+              * N.B. This is a simplified topological eye test.
+              * The simplification may be good, bad, or neutral.
+              */
+             int off_board = 0;
+             int diagonal_goal = 0;
+             for (s = 4; s < 8; s++) {
+               if (!ON_BOARD(bpos + delta[s]))
+                 off_board++;
+               else if (owl->goal[bpos + delta[s]])
+                 diagonal_goal++;
+             }
+             if (diagonal_goal + (off_board >= 2) < 2)
+               essential = 1;
            }
+
+           if (essential)
+             break;
+         }
+
+         if (!essential) {
+           TRACE("Inessential string found at %1m.\n", lunch);
+           for (r = 0; r < num_stones; r++)
+             owl->inessential[stones[r]] = 1;
          }
        }
       }
     }
-  
+  }
+
   owl->lunches_are_current = 1;
   sgf_dumptree = save_sgf_dumptree;
   count_variations = save_count_variations;
@@ -4643,22 +4626,23 @@ owl_lively(int pos)
   if (other_owl_data) {
     if (other_owl_data->goal[pos] && !semeai_trust_tactical_attack(pos))
       return 1;
+    /* FIXME: Shouldn't we check other_owl_data->inessential[origin] here? */
     for (lunch = 0; lunch < MAX_LUNCHES; lunch++)
       if (other_owl_data->lunch[lunch] == origin
          && other_owl_data->lunch_defense_point[lunch] == NO_MOVE)
        return 0;
   }
-  /* Lunches that can't be saved are dead, so don't report them as lively. */
 
+  /* Inessential stones are not lively. */
+  if (current_owl_data->inessential[origin])
+    return 0;
+
+  /* Lunches that can't be saved are dead, so don't report them as lively. */
   for (lunch = 0; lunch < MAX_LUNCHES; lunch++)
     if (current_owl_data->lunch[lunch] == origin
        && current_owl_data->lunch_defense_point[lunch] == NO_MOVE)
       return 0;
-  
-  /* Inessential stones are not lively. */
-  if (current_owl_data->inessential[origin])
-    return 0;
-  
+
   return 1;
 }
 





reply via email to

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