gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] Simple patch


From: Inge Wallin
Subject: [gnugo-devel] Simple patch
Date: Sat, 10 Nov 2001 23:21:18 +0100 (MET)

Here is a very simple patch, but I am afraid that it is all I am
capable right now with my fever.  The patch is against the CVS as it
looked today at 12 o'clock Swedish time (abt 12 hours ago).

Summary:
 - atari_atari moved to combination.c
 - restricted_defend1 and restricted attack2 now public functions
 - bugfix in find_double_threats: remove threat reasons after remaking
   them into an attack_either reason
 - old disabled function remove_move_reason() now enabled
 - some simple cleaning
 - genmove now 1D
 - Some tests in endgame.tst corrected.

        -Inge

================================================================

diff -ur gnugo-sync/engine/combination.c gnugo-iw/engine/combination.c
--- gnugo-sync/engine/combination.c     Sat Nov 10 12:18:23 2001
+++ gnugo-iw/engine/combination.c       Sat Nov 10 21:56:28 2001
@@ -25,7 +25,6 @@
  * especially, combinations of threats.
  */
 
-/* FIXME: Move much of atari_atari here. */
 
 #include "liberty.h"
 #include "gnugo.h"
@@ -88,13 +87,14 @@
       ii = POS(i, j);
       
       /* Generate ATTACK_EITHER_MOVE move reasons for each pair of the 
-       * threatened strings.  
+       * threatened strings.  We must also remove the threats, because
+       * otherwise we would get followup points for them also.     
        *
        * FIXME: 
        *   - This is perhaps not the best way to do it, but realistically
        *     it will be seldom that more than two strings are threatened
        *     at the same point.  Still, we should find a better way.
-       *   - attack_either_move should be generalized to more than two strings.
+       *   - ATTACK_EITHER_MOVE should be generalized to more than two strings.
        */
       num_a_threatened_groups = get_attack_threats(ii, MAX_THREATENED_STRINGS,
                                                   a_threatened_groups);
@@ -113,14 +113,20 @@
               */
              if (board[a_threatened_groups[k]] == EMPTY
                  || board[a_threatened_groups[l]] == EMPTY) {
-               if (!attack(ii, NULL))
+               if (!attack(ii, NULL)) {
                  add_attack_either_move(ii, a_threatened_groups[k], 
                                         a_threatened_groups[l]);
+                 remove_attack_threat_move(ii, a_threatened_groups[k]);
+                 remove_attack_threat_move(ii, a_threatened_groups[l]);
+               }
              }
              else if (!defend_both(a_threatened_groups[k],
-                                   a_threatened_groups[l]))
+                                   a_threatened_groups[l])) {
                add_attack_either_move(ii, a_threatened_groups[k], 
                                       a_threatened_groups[l]);
+               remove_attack_threat_move(ii, a_threatened_groups[k]);
+               remove_attack_threat_move(ii, a_threatened_groups[l]);
+             }
            }
          popgo();
        }
@@ -136,6 +142,524 @@
    *     - combinations of breakins into enemy territory
    */
 }
+
+
+/* ================================================================ */
+/*                       Combination attacks                        */
+/* ================================================================ */
+
+
+/* atari_atari(color, *move) looks for a series of ataris on
+ * strings of the other color culminating in the capture of
+ * a string which is thought to be invulnerable by the reading
+ * code. Such a move can be missed since it may be that each
+ * string involved individually can be rescued, but nevertheless
+ * one of them can be caught. The simplest example is a double
+ * atari. The return value is the size of the smallest opponent
+ * worm. 
+ *
+ * One danger with this scheme is that the first atari
+ * tried might be irrelevant to the actual combination.
+ * To detect this possibility, once we've found a combination,
+ * we mark that first move as forbidden, then try again. If
+ * no combination of the same size or larger turns up, then
+ * the first move was indeed essential.
+ *
+ * For the purpose of the move generation, returns the
+ * size of the smallest of the worms under attack.
+ */
+
+static int aa_status[BOARDMAX]; /* ALIVE, DEAD or CRITICAL */
+static int forbidden[BOARDMAX];
+static void compute_aa_status(int color);
+static int get_aa_status(int pos);
+static int do_atari_atari(int color, int *attack_point,
+                         int *defense_point, int cpos,
+                         int save_verbose, int minsize);
+
+/* Set to 1 if you want verbose traces from this function. */
+
+int
+atari_atari(int color, int *move, int save_verbose)
+{
+  int fpos;
+  int aa_val;
+
+  /* Collect worm statuses of opponent's worms. We need to
+   * know this because we only want to report unexpected
+   * results. For example, we do not want to report success
+   * if we find we can kill a worm which is already dead.
+   * The worm status of empty points is set to UNKNOWN to signal
+   * that stones added along the way need special attention.
+   */
+  if (aa_depth < 2)
+    return 0;
+  memset(forbidden, 0, sizeof(forbidden));
+
+  compute_aa_status(color);
+  
+  aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
+                         save_verbose, 0);
+
+  if (aa_val == 0)
+    return 0;
+
+  /* We try excluding the first atari found and see if the
+   * combination still works. Repeat until failure.
+   */
+  while (1) {
+    int new_aa_val;
+    forbidden[fpos] = 1;
+    new_aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
+                               save_verbose, aa_val);
+
+    /* The last do_atari_atari call fails. When do_atari_atari fails,
+     * it does not change the value of (fpos), so these correspond
+     * to a move that works and is necessary.
+     */
+    if (new_aa_val == 0) {
+      if (move) *move = fpos;
+      return aa_val;
+    }
+    aa_val = new_aa_val;
+  }
+
+  /* We'll never get here, but the compiler may be more happy if it
+   * looks like we're returning something.
+   */
+  return 0;
+}
+
+
+/* Helper function for computing the aa_status for a string. */
+static void
+compute_aa_status(int color)
+{
+  int other = OTHER_COLOR(color);
+  int pos;
+  /* Collect worm statuses of opponent's worms. We need to
+   * know this because we only want to report unexpected
+   * results. For example, we do not want to report success
+   * if we find we can kill a worm which is already dead.
+   * The worm status of empty points is set to UNKNOWN to signal
+   * that stones added along the way need special attention.
+   */
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    if (board[pos] == other) {
+      if (dragon[pos].matcher_status == DEAD)
+       aa_status[pos] = DEAD;
+      else if (worm[pos].attack_codes[0] != 0) {
+       if (worm[pos].defend_codes[0] != 0)
+         aa_status[pos] = CRITICAL;
+       else
+         aa_status[pos] = DEAD;
+      }
+      else
+       aa_status[pos] = ALIVE;
+    }
+    else if(ON_BOARD(pos))
+      aa_status[pos] = UNKNOWN;
+  }
+  
+  /* reclassify a worm with 2 liberties as INSUBSTANTIAL if capturing
+   * it does not result in a live group.
+   */
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    if (board[pos] == other
+       && worm[pos].origin == pos
+       && worm[pos].liberties == 2
+       && aa_status[pos] == ALIVE
+       && !owl_substantial(pos)) {
+      int pos2;
+      for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++)
+       if (ON_BOARD(pos2) && is_worm_origin(pos2, pos))
+         aa_status[pos2] = INSUBSTANTIAL;
+    }
+  }
+    
+  if (debug & DEBUG_ATARI_ATARI) {
+    gprintf("compute_aa_status() for %C\n", color);
+    gprintf("aa_status: (ALIVE worms not listed)\n");
+    for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+      if (board[pos] == other && is_worm_origin(pos, pos)) {
+       const char *status = "UNKNOWN (shouldn't happen)";
+       if (aa_status[pos] == DEAD)
+         status = "DEAD";
+       else if (aa_status[pos] == CRITICAL)
+         status = "CRITICAL";
+       else if (aa_status[pos] == INSUBSTANTIAL)
+         status = "INSUBSTANTIAL";
+       
+       if (aa_status[pos] != ALIVE)
+         gprintf("%1M: %s\n", pos, status);
+      }
+    }
+  }
+}
+
+/* Helper function for retrieving the aa_status for a string. We can't
+ * reliably do this simply by looking up aa_status[pos] since this is
+ * only valid at vertices which were non-empty at the start of the
+ * reading. For later added stones, we need to find their aa_status by
+ * locating a part of the string which was a worm at the beginning of
+ * the reading.
+ */
+static int
+get_aa_status(int pos)
+{
+  int stones[MAX_BOARD * MAX_BOARD];
+  int num_stones;
+  int k;
+
+  if (aa_status[pos] != UNKNOWN)
+    return aa_status[pos];
+
+  num_stones = findstones(pos, MAX_BOARD * MAX_BOARD, stones);
+  for (k = 0; k < num_stones; k++)
+    if (aa_status[stones[k]] != UNKNOWN)
+      return aa_status[stones[k]];
+
+  return UNKNOWN;
+}
+
+
+/* Helper function for atari_atari. Here worms is the number of
+ * opponent worms involved in the combination, and (last_friendly) is
+ * the location of the last friendly move played. Moves marked
+ * with the forbidden array are not tried. If no move is found,
+ * the values of *attack_point and *defense_point are not changed.
+ *
+ * If not NULL, *attack_point is left pointing to the location of the
+ * attacking move, and *defense_point points to a move defending the
+ * combination. In rare cases a defensive move might not be found. If
+ * a non-static function calling do_atari_atari gets a return value of
+ * 1 but NO_MOVE as the defense point, this should be treated as
+ * equivalent to a return value of 0.
+ */
+
+static int
+do_atari_atari(int color, int *attack_point, int *defense_point,
+              int last_friendly, int save_verbose, int minsize)
+{
+  int m, n;
+  int k;
+  
+  int other = OTHER_COLOR(color);
+
+  if (debug & DEBUG_ATARI_ATARI) {
+    gprintf("%odo_atari_atari: ");
+    dump_stack();
+    gprintf("%oforbidden moves: ");
+    for (m = 0; m < board_size; m++)
+      for (n = 0; n < board_size; n++) {
+       if (forbidden[POS(m, n)])
+         gprintf("%o%1m ", POS(m, n));
+      }
+    gprintf("\n");
+  }
+
+  /* First look for strings adjacent to the last friendly move played
+   * (or to another stone in the same string) which can be
+   * unexpectedly attacked.
+   */
+  if (last_friendly != NO_MOVE)
+    for (m = 0; m < board_size; m++)
+      for (n = 0; n < board_size; n++) {
+       int pos = POS(m, n);
+       int apos;
+
+       if (board[pos] != other)
+         continue;
+
+       if (pos != find_origin(pos))
+         continue;
+
+       if (minsize > 0 && countstones(pos) < minsize)
+         continue;
+
+       if (get_aa_status(pos) != ALIVE)
+         continue;
+
+       if (board[last_friendly] != EMPTY
+           && !adjacent_strings(last_friendly, pos))
+         continue;
+
+       if (board[last_friendly] == EMPTY
+           && !liberty_of_string(last_friendly, pos))
+         continue;
+       
+       if (debug & DEBUG_ATARI_ATARI)
+         gprintf("Considering attack of %1m. depth = %d.\n", pos, depth);
+       if (attack(pos, &apos)) {
+         if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
+           gprintf("%oThe worm %1m can be attacked at %1m after ", pos, apos);
+           dump_stack();
+         }       
+         if (attack_point) *attack_point = apos;
+         
+         /* We look for a move defending the combination.
+          * Normally this is found by find_defense but failing
+          * that, if the attacking move is a safe move for color, 
+          * it probably defends.
+          */
+         if (defense_point) {
+           if (!find_defense(pos, defense_point)) {
+             if (safe_move(apos, other)) {
+               *defense_point = apos;
+             }
+             /* No defense is found */
+             else {
+               *defense_point = NO_MOVE;
+             }
+           }
+         }
+
+         DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%1m)\n",
+               countstones(pos), pos);
+         return countstones(pos);
+       }
+      }
+
+  if (stackp > aa_depth)
+    return 0;
+
+  /* Next look for a string, not insubstantial, having exactly two
+   * liberties and no boundary stones in atari. Atari, fill, then try
+   * again. If that doesn't work, try the other atari.
+   */
+  for (m = 0; m < board_size; m++)
+    for (n = 0; n < board_size; n++) {
+      int pos = POS(m, n);
+      int libs[2];
+      int status;
+
+      if (board[pos] != other) 
+       continue;
+
+      if (pos != find_origin(pos))
+       continue;
+      
+      if (minsize > 0 && countstones(pos) < minsize)
+       continue;
+
+      status = get_aa_status(pos);
+      if (status != ALIVE)
+       continue;
+
+      if (findlib(pos, 2, libs) != 2)
+       continue;
+
+      for (k = 0; k < 2; k++) {
+       int apos = libs[k];
+       int bpos;
+
+       if (!forbidden[apos]
+           && (accurate_approxlib(apos, color, 2, NULL) > 1
+               || safe_move(apos, color))) {
+         if (trymove(apos, color, "do_atari_atari-A", pos,
+                      EMPTY, NO_MOVE)) {
+           /* try to defend the stone (m,n) which is in atari */
+           int aa_val = 0;
+
+           /* Because we know (m, n) is in atari there is a trivial
+            * attack and we can be sure find_defense() will give a
+            * useful defense point if it returns non-zero. Usually we
+            * would need to call attack_and_defend() to be certain of
+            * this.
+            *
+            * On the other hand, if there is no defense we have
+            * already been successful.
+            */
+           if (find_defense(pos, &bpos)
+               && trymove(bpos, other, "do_atari_atari-B", pos,
+                           EMPTY, NO_MOVE)) {
+             /* These moves may have been irrelevant for later
+               * reading, so in order to avoid horizon problems, we
+               * need to temporarily increase the depth values.
+              */
+             increase_depth_values();
+             increase_depth_values();
+             aa_val = do_atari_atari(color, NULL, defense_point,
+                                     apos, save_verbose, minsize);
+             decrease_depth_values();
+             decrease_depth_values();
+             popgo();
+           }
+           else {
+             /* No way to save the ataried stone. We have been successful. */
+             popgo();
+             if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
+               gprintf("%oThe worm %m can be attacked at %1m after ", m, n,
+                       apos);
+               dump_stack();
+             }   
+             if (attack_point) *attack_point = apos;
+             if (defense_point && !find_defense(pos, defense_point))
+               *defense_point = NO_MOVE;
+             
+             DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%m)\n",
+                   countstones(pos), m, n);
+             return countstones(pos);
+           }
+
+           if (aa_val) {
+             /* The atari at (ai,aj) seems to work but we still
+              * must check there is not a better defense.
+              */
+             int cpos;
+             int res = restricted_defend1(pos, &cpos, EMPTY, 0, 
+                                          1, &bpos);
+             if (res) {
+               if (trymove(cpos, other, "do_atari_atari-C", 
+                            pos, EMPTY, NO_MOVE)) {
+                 increase_depth_values();
+                 increase_depth_values();
+                 if (!do_atari_atari(color, NULL, defense_point,
+                                     apos, save_verbose, minsize)) 
+                   aa_val = 0;
+                 decrease_depth_values();
+                 decrease_depth_values();
+                 popgo();
+               }
+             }
+             if (aa_val) {
+               if (attack_point) *attack_point = apos;
+               popgo();
+               DEBUG(DEBUG_ATARI_ATARI, 
+                     "%oreturn value:%d (min %d, %d (%m))\n",
+                     gg_min(aa_val, countstones(pos)), aa_val,
+                     countstones(pos), m, n);
+               /* If no defense point is known and (ai,aj) is a safe
+                * move for other, it probably defends the combination.
+                */
+               if (defense_point 
+                   && (*defense_point == NO_MOVE
+                       || !safe_move(*defense_point, other))
+                   && safe_move(apos, other)) {
+                 *defense_point = apos;
+               }
+               return gg_min(aa_val, countstones(pos));
+             }
+           }
+           popgo();
+         }
+       }
+      }
+    }
+  return 0;
+}
+
+/* Ask the atari_atari code whether there appears any combination
+ * attack which would capture at least minsize stones after playing at
+ * (tpos). If this happens, (*move) points to a move which prevents
+ * this blunder.
+ *
+ * FIXME: Most of the code below is common with atari_atari() and
+ *        should be broken out of both functions.
+ */
+int
+atari_atari_confirm_safety(int color, int tpos, int *move, int minsize)
+{
+  int fpos;
+  int defense_point = NO_MOVE, after_defense_point = NO_MOVE;
+  int aa_val, after_aa_val;
+  int other = OTHER_COLOR(color);
+
+  /* If aa_depth is too small, we can't see any combination attacks,
+   * so in this respect the move is safe enough.
+   */
+  if (aa_depth < 2)
+    return 1;
+
+  memset(forbidden, 0, sizeof(forbidden));
+
+  compute_aa_status(other);
+  
+  /* Accept illegal ko capture here. */
+  if (!tryko(tpos, color, NULL, EMPTY, NO_MOVE))
+    /* Really shouldn't happen. */
+    abortgo(__FILE__, __LINE__, "trymove", I(tpos), J(tpos)); 
+  increase_depth_values();
+
+  aa_val = do_atari_atari(other, &fpos, &defense_point,
+                         NO_MOVE, 0, minsize);
+  after_aa_val = aa_val;
+
+  if (aa_val == 0 || defense_point == NO_MOVE) {
+
+  /* No sufficiently large combination attack, so the move is safe from
+   * this danger.
+   *
+   * On rare occasions do_atari_atari might find a combination
+   * but no defense. In this case we assume that the combination
+   * is illusory.
+   */
+
+    popgo();
+    decrease_depth_values();
+    return 1;
+  }
+
+  while (aa_val >= after_aa_val) {
+    /* Try dropping moves from the combination and see if it still
+     * works. What we really want is to get the proper defense move
+     * into (*move).
+     */
+    after_defense_point = defense_point;
+    forbidden[fpos] = 1;
+    aa_val = do_atari_atari(other, &fpos, &defense_point, 
+                           NO_MOVE, 0, aa_val);
+  }
+
+  popgo();
+  decrease_depth_values();
+  /* We know that a combination exists, but we don't know if
+   * the original move at (aa) was really relevant. So we
+   * try omitting it and see if a combination is still found.
+   */
+  if (do_atari_atari(other, NULL, NULL, NO_MOVE, 0, minsize) >= after_aa_val)
+    return 1;
+  else {
+    if (move) *move = after_defense_point;
+    return 0;
+  }
+}
+
+
+/* Ask the atari_atari code if after color plays at (apos)
+ * and other plays at (bpos) there appears any combination
+ * attack. Returns the size of the combination.
+ *
+ * FIXME: Most of the code below is common with atari_atari() and
+ *        should be broken out of both functions.
+ */
+
+int
+atari_atari_try_combination(int color, int apos, int bpos)
+{
+  int other = OTHER_COLOR(color);
+  int aa_val = 0;
+  int save_verbose = verbose;
+
+  if (aa_depth < 2)
+    return 0;
+  if (verbose > 0)
+    verbose--;
+  memset(forbidden, 0, sizeof(forbidden));
+
+  compute_aa_status(color);
+
+  if (trymove(apos, color, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
+    if (trymove(bpos, other, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
+      aa_val = do_atari_atari(color, NULL, NULL, apos, 0, 0);
+      popgo();
+    }
+    popgo();
+  }
+  verbose = save_verbose;
+  return aa_val;
+}
+
 
 /*
  * Local Variables:
Only in gnugo-iw/engine: combination.o
diff -ur gnugo-sync/engine/dragon.c gnugo-iw/engine/dragon.c
--- gnugo-sync/engine/dragon.c  Sat Nov 10 12:18:23 2001
+++ gnugo-iw/engine/dragon.c    Sat Nov 10 21:57:47 2001
@@ -97,8 +97,8 @@
              "Initialising dragon from worm at %1m, size %d\n", 
              ii, worm[ii].size);
     }
-
   time_report(2, "  time to initialize dragons", -1, -1, 1.0);
+
   make_domains(black_eye, white_eye, 0);
   time_report(2, "  time to make domains", -1, -1, 1.0);
 
@@ -196,7 +196,6 @@
        }
       }
     }
-
   time_report(2, "  time to find lunches", -1, -1, 1.0);
 
   /* In case origins of dragons got moved, put the dragons of eyes aright. */
@@ -338,7 +337,6 @@
        }
       }
     }
-
   time_report(2, "  time to compute genus", -1, -1, 1.0);
 
   /* Compute the escape route measure. */
@@ -351,7 +349,6 @@
        DRAGON2(ii).escape_route = compute_escape(ii, 0);
       }
     }
-
   time_report(2, "  time to compute escape", -1, -1, 1.0);
 
   /* Update the segmentation of the initial influence before we
@@ -506,7 +503,6 @@
        time_report(3, "    owl reading for dragon at ", m, n, 1.0);
       }
     }
-
   time_report(2, "  owl reading", -1, -1, 1.0);
 
   /* The dragon data is now correct at the origin of each dragon but
@@ -543,7 +539,6 @@
          dragon[ii].matcher_status = dragon[ii].status;
       }
     }
-
   time_report(2, "  compute matcher status", -1, -1, 1.0);
 
   /* Compute the safety value. */
@@ -590,7 +585,6 @@
     else
       dragon2[d].safety = ALIVE;
   }
-
   time_report(2, "  compute dragon safety", -1, -1, 1.0);
 
   /* Resolve semeais. This may revise the safety and status fields. */
@@ -637,7 +631,6 @@
        }
       }
     }
-  
   time_report(2, "  revise inessentiality", -1, -1, 1.0);
 
   /* Count the non-dead dragons. */
Only in gnugo-iw/engine: dragon.o
Only in gnugo-iw/engine: filllib.o
Only in gnugo-iw/engine: fuseki.o
diff -ur gnugo-sync/engine/genmove.c gnugo-iw/engine/genmove.c
--- gnugo-sync/engine/genmove.c Sat Nov 10 12:18:23 2001
+++ gnugo-iw/engine/genmove.c   Sat Nov 10 22:20:13 2001
@@ -35,7 +35,7 @@
 #define NEEDS_UPDATE(x) (x != position_number ? (x = position_number, 1) : 0)
 
 static int get_level(int *level);
-static int do_genmove(int *i, int *j, int color, float pure_threat_value);
+static int do_genmove(int *move, int color, float pure_threat_value);
 
 static double slowest_time = 0.;
 static int slowest_i = -1;
@@ -219,7 +219,15 @@
 int
 genmove(int *i, int *j, int color)
 {
-  return do_genmove(i, j, color, 0.4);
+  int move;
+  int retval;
+
+  retval = do_genmove(&move, color, 0.4);
+
+  if (i) *i = I(move);
+  if (j) *j = J(move);
+
+  return retval;
 }
 
 
@@ -231,9 +239,16 @@
 int
 genmove_conservative(int *i, int *j, int color)
 {
-  return do_genmove(i, j, color, 0.0);
-}
+  int move;
+  int retval;
 
+  retval = do_genmove(&move, color, 0.4);
+
+  if (i) *i = I(move);
+  if (j) *j = J(move);
+
+  return retval;
+}
 
 
 /* 
@@ -241,10 +256,9 @@
  */
   
 static int
-do_genmove(int *i, int *j, int color, float pure_threat_value)
+do_genmove(int *move, int color, float pure_threat_value)
 {
   float val;
-  int move;
   int save_verbose;
 
   start_timer(0);
@@ -261,8 +275,7 @@
   stats.hash_collisions     = 0;
   
   /* no move is found yet. */
-  *i = -1;  
-  *j = -1;  
+  *move = NO_MOVE;  
   val = -1; 
   if (get_level(&level))
     fprintf(stderr, "level = %d\n", level);
@@ -356,9 +369,9 @@
   gg_assert(stackp == 0);
 
   /* Review the move reasons and estimate move values. */
-  if (review_move_reasons(i, j, &val, color, 
+  if (review_move_reasons(move, &val, color, 
                          pure_threat_value, lower_bound))
-    TRACE("Move generation likes %m with value %f\n", *i, *j, val);
+    TRACE("Move generation likes %1m with value %f\n", *move, val);
   gg_assert(stackp == 0);
   time_report(1, "review move reasons", -1, -1, 1.0);
 
@@ -366,8 +379,8 @@
   if (val <= 6.0 && !disable_endgame_patterns) {
     endgame_shapes(color);
     gg_assert(stackp == 0);
-    if (review_move_reasons(i, j, &val, color, pure_threat_value, score))
-      TRACE("Move generation likes %m with value %f\n", *i, *j, val);
+    if (review_move_reasons(move, &val, color, pure_threat_value, score))
+      TRACE("Move generation likes %1m with value %f\n", *move, val);
     gg_assert(stackp == 0);
     time_report(1, "endgame", -1, -1, 1.0);
   }
@@ -380,9 +393,9 @@
     if (revise_semeai(color)) {
       shapes(color);
       endgame_shapes(color);
-      if (review_move_reasons(i, j, &val, color, pure_threat_value, score)) {
-       TRACE("Upon reconsideration move generation likes %m with value %f\n",
-             *i, *j, val); 
+      if (review_move_reasons(move, &val, color, pure_threat_value, score)) {
+       TRACE("Upon reconsideration move generation likes %1m with value %f\n",
+             *move, val); 
       }
     }
     time_report(1, "move reasons with revised semeai status", -1, -1, 1.0);
@@ -392,12 +405,10 @@
    * all missing dame points.
    */
   if (val < 0.0 
-      && fill_liberty(&move, color)) {
+      && fill_liberty(move, color)) {
     val = 1.0;
     TRACE("Filling a liberty at %1m\n", move);
-    *i = I(move);
-    *j = J(move);
-    move_considered(*i, *j, val);
+    move_considered(I(*move), J(*move), val);
     time_report(1, "fill liberty", -1, -1, 1.0);
   }
 
@@ -407,12 +418,10 @@
   if (val < 0.0
       && !doing_scoring
       && (play_out_aftermath || capture_all_dead)
-      && aftermath_genmove(&move, color, NULL, 0) > 0) {
-    *i = I(move);
-    *j = J(move);
+      && aftermath_genmove(move, color, NULL, 0) > 0) {
     val = 1.0;
-    TRACE("Aftermath move at %m\n", *i, *j);
-    move_considered(*i, *j, val);
+    TRACE("Aftermath move at %1m\n", *move);
+    move_considered(I(*move), J(*move), val);
     time_report(1, "aftermath_genmove", -1, -1, 1.0);
   }
 
@@ -422,23 +431,20 @@
   if (val < 0.0
       && !doing_scoring
       && capture_all_dead
-      && aftermath_genmove(&move, color, NULL, 1) > 0) {
-    *i = I(move);
-    *j = J(move);
+      && aftermath_genmove(move, color, NULL, 1) > 0) {
     val = 1.0;
-    TRACE("Aftermath move at %m\n", *i, *j);
-    move_considered(*i, *j, val);
+    TRACE("Aftermath move at %1m\n", *move);
+    move_considered(I(*move), J(*move), val);
     time_report(1, "aftermath_genmove", -1, -1, 1.0);
   }
 
   /* If no move is found then pass. */
   if (val < 0.0) {
     TRACE("I pass.\n");
-    *i = -1;
-    *j = -1;
+    *move = NO_MOVE;
   }
   else
-    TRACE("genmove() recommends %m with value %f\n", *i, *j, val);
+    TRACE("genmove() recommends %1m with value %f\n", *move, val);
   
   /* If statistics is turned on, this is the place to show it. */
   if (showstatistics) {
@@ -451,15 +457,16 @@
   }
  
  if (showtime) {
-    double spent = time_report(0, "TIME to generate move at ", *i, *j, 1.0);
+    double spent = time_report(0, "TIME to generate move at ",
+                              I(*move), J(*move), 1.0);
     total_time += spent;
     if (spent > slowest_time) {
       slowest_time = spent;
-      slowest_i = *i;
-      slowest_j = *j;
+      slowest_i = I(*move);
+      slowest_j = J(*move);
       slowest_movenum = movenum+1;
     }
-    if (*i == -1) {
+    if (*move == NO_MOVE) {
       gprintf("\nSLOWEST MOVE: %d at %m ", slowest_movenum,
              slowest_i, slowest_j);
       fprintf(stderr, "(%.2f seconds)\n", slowest_time);
@@ -472,8 +479,7 @@
   }
   
   return val;
-  
-}  /* end genmove */
+}
 
 
 /* This is called for each move which has been considered. For
Only in gnugo-iw/engine: genmove.o
Only in gnugo-iw/engine: globals.o
Only in gnugo-iw/engine: hash.o
Only in gnugo-iw/engine: influence.o
Only in gnugo-iw/engine: interface.o
Only in gnugo-iw/engine: libboard.a
Only in gnugo-iw/engine: libengine.a
diff -ur gnugo-sync/engine/liberty.h gnugo-iw/engine/liberty.h
--- gnugo-sync/engine/liberty.h Sat Nov 10 12:18:26 2001
+++ gnugo-iw/engine/liberty.h   Sat Nov 10 22:06:48 2001
@@ -226,6 +226,12 @@
 int attack_either(int astr, int bstr);
 int defend_both(int astr, int bstr);
 int break_through(int apos, int bpos, int cpos);
+
+int restricted_defend1(int str, int *move, int komaster, int kom_pos,
+                      int num_forbidden_moves, int *forbidden_moves);
+int restricted_attack2(int str, int *move, int komaster, int kom_pos,
+                      int num_forbidden_moves, int *forbidden_moves);
+
 int naive_ladder(int str, int *move);
 #define MOVE_ORDERING_PARAMETERS 67
 void tune_move_ordering(int params[MOVE_ORDERING_PARAMETERS]);
@@ -287,6 +293,7 @@
 void add_attack_move(int pos, int ww, int code);
 void add_defense_move(int pos, int ww, int code);
 void add_attack_threat_move(int pos, int ww, int code);
+void remove_attack_threat_move(int pos, int ww);
 void add_defense_threat_move(int pos, int ww, int code);
 int  get_attack_threats(int pos, int max_strings, int strings[]);
 int  get_defense_threats(int pos, int max_strings, int strings[]);
@@ -363,7 +370,7 @@
                               int minsize);
 int atari_atari_try_combination(int color, int apos, int bpos);
 
-int review_move_reasons(int *i, int *j, float *val, int color,
+int review_move_reasons(int *move, float *val, int color,
                        float pure_threat_value, float lower_bound);
 int fill_liberty(int *move, int color);
 int aftermath_genmove(int *aftermath_move, int color,
Only in gnugo-iw/engine: life.o
Only in gnugo-iw/engine: matchpat.o
diff -ur gnugo-sync/engine/move_reasons.c gnugo-iw/engine/move_reasons.c
--- gnugo-sync/engine/move_reasons.c    Sat Nov 10 12:18:47 2001
+++ gnugo-iw/engine/move_reasons.c      Sat Nov 10 22:20:12 2001
@@ -356,7 +356,6 @@
     move[pos].reason[k] = find_reason(type, what);
 }
 
-#if 0
 /*
  * Remove a move reason for (pos). Ignore silently if the reason
  * wasn't there.
@@ -387,7 +386,7 @@
   move[pos].reason[n] = move[pos].reason[k];
   move[pos].reason[k] = -1;
 }
-#endif
+
 
 /*
  * Check whether a move reason already is recorded for a move.
@@ -510,6 +509,15 @@
   add_move_reason(pos, ATTACK_THREAT_MOVE, worm_number);
 }
 
+void
+remove_attack_threat_move(int pos, int ww)
+{
+  int worm_number = find_worm(worm[ww].origin);
+
+  ASSERT_ON_BOARD1(ww);
+  remove_move_reason(pos, ATTACK_THREAT_MOVE, worm_number);
+}
+
 /*
  * Add to the reasons for the move at (pos) that it defends the worm
  * at (ww).
@@ -1128,7 +1136,7 @@
   int unstable_worms[MAX_WORMS];
   int N = 0;  /* number of unstable worms */
   int m, n;
-  int pos;
+  int ii;
   int k;
   int other = OTHER_COLOR(color);
   
@@ -1136,24 +1144,27 @@
   
   /* Identify the unstable worms and store them in a list. */
   for (m = 0; m < board_size; m++)
-    for (n = 0; n  <board_size; n++)
-      if (BOARD(m, n)
-         && worm[POS(m, n)].origin == POS(m, n)
-         && worm[POS(m, n)].attack_codes[0] != 0
-         && worm[POS(m, n)].defend_codes[0] != 0) {
-       unstable_worms[N] = find_worm(POS(m, n));
+    for (n = 0; n  <board_size; n++) {
+      ii = POS(m, n);
+
+      if (board[ii]
+         && worm[ii].origin == ii
+         && worm[ii].attack_codes[0] != 0
+         && worm[ii].defend_codes[0] != 0) {
+       unstable_worms[N] = find_worm(ii);
        N++;
       }
+    }
   
   /* To avoid horizon effects, we temporarily increase the depth values. */
   increase_depth_values();
   
   for (m = 0; m < board_size; m++)
     for (n = 0; n < board_size; n++) {
-      pos = POS(m, n);
+      ii = POS(m, n);
 
       for (k = 0; k < MAX_REASONS; k++) {
-       int r = move[pos].reason[k];
+       int r = move[ii].reason[k];
        int what;
 
        if (r < 0)
@@ -1172,12 +1183,12 @@
          break;
       }
       
-      if (k<MAX_REASONS && move[pos].reason[k] != -1) {
-       /* Try the move at (pos) and see what happens. */
+      if (k<MAX_REASONS && move[ii].reason[k] != -1) {
+       /* Try the move at (ii) and see what happens. */
        int cursor_at_start_of_line = 0;
 
-       TRACE("%1m ", pos);
-       if (trymove(pos, color, "find_more_attack_and_defense_moves",
+       TRACE("%1m ", ii);
+       if (trymove(ii, color, "find_more_attack_and_defense_moves",
                     NO_MOVE, EMPTY, NO_MOVE)) {
          for (k = 0; k < N; k++) {
            int aa = worms[unstable_worms[k]];
@@ -1186,21 +1197,21 @@
             * unless we already know the move works as defense move.
             */
            if (board[aa] == color
-               && !defense_move_reason_known(pos, unstable_worms[k]))
+               && !defense_move_reason_known(ii, unstable_worms[k]))
              if (!attack(aa, NULL)) {
                if (!cursor_at_start_of_line)
                  TRACE("\n");
                TRACE("%ofound extra point of defense of %1m at %1m\n", 
-                     aa, pos);
+                     aa, ii);
                cursor_at_start_of_line = 1;
-               add_defense_move(pos, aa, WIN);
+               add_defense_move(ii, aa, WIN);
              }
            
            /* string of opponent color, see if there still is a defense,
             * unless we already know the move works as attack move.
             */
            if (board[aa] == other
-               && !attack_move_reason_known(pos, unstable_worms[k]))
+               && !attack_move_reason_known(ii, unstable_worms[k]))
              if (!find_defense(aa, NULL)) {
                /* Maybe find_defense() doesn't find the defense. Try to
                 * defend with the stored defense move.
@@ -1219,9 +1230,9 @@
                  if (!cursor_at_start_of_line)
                    TRACE("\n");
                  TRACE("%ofound extra point of attack of %1m at %1m\n",
-                       aa, pos);
+                       aa, ii);
                  cursor_at_start_of_line = 1;
-                 add_attack_move(pos, aa, WIN);
+                 add_attack_move(ii, aa, WIN);
                }
              }
          }
@@ -2182,12 +2193,12 @@
 static float cautious_impact_values[10][10] = {
 /*        (bi, bj) DEAD ALIV CRIT INES TACT WEAK WE_A SEKI STRO INVI */
 /* DEAD        */ {0.3, 0.9, 0.0, 0.0, 0.0, 0.8, 0.85,0.8, 0.95,1.0 },
-/* ALIVE       */ {0.0, 0.2, 0.05,0.0, 0.0, 0.1,0.15,0.10, 0.2 ,0.2 },
+/* ALIVE       */ {0.0, 0.2, 0.05,0.0, 0.0, 0.1,0.15, 0.10,0.2 ,0.2 },
 /* CRITICAL    */ {0.0, 1.04,0.85,0.0, 0.0, 0.75,0.9, 0.85,1.08,1.1 },
 /* INESSENTIAL */ {0.1, 0.6, 0.0, 0.0, 0.0, 0.3, 0.5, 0.5, 0.6, 0.6 },
 /* TACT. DEAD  */ {0.2, 0.9, 0.0, 0.0, 0.0, 0.8, 0.85,0.8, 0.95,1.0 },
 /* WEAK        */ {0.1, 0.6, 0.25,0.0, 0.0, 0.2, 0.25,0.25,0.65,0.65},
-/* WEAK ALIVE  */ {0.0, 0.4, 0.3, 0.0, 0.0, 0.2,0.2, 0.2 ,0.45,0.45},
+/* WEAK ALIVE  */ {0.0, 0.4, 0.3, 0.0, 0.0, 0.2, 0.2, 0.2 ,0.45,0.45},
 /* SEKI        */ {0.0, 0.2, 0.15,0.0, 0.0, 0.1, 0.15,0.2, 0.25,0.3 },
 /* STR. ALIVE  */ {0.0, 0.02,0.01,0.0, 0.0, 0.01,0.01,0.01,0.02,0.02},
 /* INVINCIBLE  */ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }};
@@ -2371,7 +2382,7 @@
 
       if (DRAGON2(aa).safety == INESSENTIAL || worm[aa].inessential) {
        DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0 - attack on %1m (inessential)\n", pos, aa);
+             "  %1m: 0.0 - attack on %1m (inessential)\n", pos, aa);
        break;
       }
 
@@ -3280,8 +3291,7 @@
         * substantial enough that capturing it saves the strategically
         * attacked dragon.
         */
-       if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE)
-       {
+       if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE) {
          int s;
          
          for (s = 0; s < DRAGON2(aa).neighbors; s++) {
@@ -3418,7 +3428,6 @@
   int strings = 0;
   int own_strings = 0;
   int k, l;
-  int oo;
   int fewlibs = 0;
 
   for (k = 0; k < 4; k++) {
@@ -3429,14 +3438,13 @@
       continue;
 
     origin = find_origin(ii);
-    oo = origin;
 
     for (l = 0; l < strings; l++)
-      if (ss[l] == oo)
+      if (ss[l] == origin)
        break;
 
     if (l == strings) {
-      ss[strings] = oo;
+      ss[strings] = origin;
       strings++;
     }
   }
@@ -3698,14 +3706,14 @@
        * captures here though, because if that is the best move, we
        * should reevaluate ko threats.
        */
-      if (!(is_illegal_ko_capture(pos, color) || is_legal(pos, color))) {
-       move[pos].value = 0.0;
-       TRACE("Move at %1m wasn't legal.\n", pos);
-      }
-      else {
+      if (is_legal(pos, color) || is_illegal_ko_capture(pos, color)) {
        /* Add a random number between 0 and 0.01 to use in comparisons. */
        move[pos].value += 0.01 * move[pos].random_number;
       }
+      else {
+       move[pos].value = 0.0;
+       TRACE("Move at %1m wasn't legal.\n", pos);
+      }
     }
 }
 
@@ -3786,10 +3794,11 @@
   for (m = 0; m < board_size; m++)
     for (n = 0; n < board_size; n++) {
       pos = POS(m, n);
-      ii = replacement_map[pos];
       
+      ii = replacement_map[pos];
       if (ii == NO_MOVE)
        continue;
+
       TRACE("Redistributing points from %1m to %1m.\n", pos, ii);
       if (move[ii].final_value < move[pos].final_value) {
        TRACE("%1m is now valued %f.\n", ii, move[pos].final_value);
@@ -3809,10 +3818,11 @@
  * misevaluated the dangers or because the opponent misplays.
  */
 int
-review_move_reasons(int *i, int *j, float *val, int color,
+review_move_reasons(int *the_move, float *val, int color,
                    float pure_threat_value, float score)
 {
   int m, n;
+  int ii;
   float tval;
   float bestval = 0.0;
   int best_move = NO_MOVE;
@@ -3860,7 +3870,6 @@
    * moves and print them.
    */
   print_top_moves();
-  
   while (!good_move_found) {
     bestval = 0.0;
     best_move = NO_MOVE;
@@ -3868,20 +3877,22 @@
     /* Search through all board positions for the highest valued move. */
     for (m = 0; m < board_size; m++)
       for (n = 0; n < board_size; n++) {
-       if (move[POS(m, n)].final_value == 0.0)
+       ii = POS(m, n);
+
+       if (move[ii].final_value == 0.0)
          continue;
        
-       tval = move[POS(m, n)].value;
+       tval = move[ii].value;
        
        if (tval > bestval) {
-         if (is_legal(POS(m, n), color) || is_illegal_ko_capture(POS(m, n), 
color)) {
+         if (is_legal(ii, color) || is_illegal_ko_capture(ii, color)) {
            bestval = tval;
-           best_move = POS(m, n);
+           best_move = ii;
          }
          else {
-           TRACE("Move at %m would be suicide.\n", m, n);
-           move[POS(m, n)].value = 0.0;
-           move[POS(m, n)].final_value = 0.0;
+           TRACE("Move at %1m would be suicide.\n", ii);
+           move[ii].value = 0.0;
+           move[ii].final_value = 0.0;
          }
        }
       }
@@ -3932,9 +3943,8 @@
   
   if (bestval > 0.0 
       && best_move != NO_MOVE) {
+    *the_move = best_move;
     *val = bestval;
-    *i = I(best_move);
-    *j = J(best_move);
     return 1;
   }
   else
Only in gnugo-iw/engine: move_reasons.o
Only in gnugo-iw/engine: optics.o
Only in gnugo-iw/engine: owl.o
Only in gnugo-iw/engine: printutils.o
Only in gnugo-iw/engine: readconnect.o
diff -ur gnugo-sync/engine/reading.c gnugo-iw/engine/reading.c
--- gnugo-sync/engine/reading.c Sat Nov  3 19:11:45 2001
+++ gnugo-iw/engine/reading.c   Sat Nov 10 22:18:01 2001
@@ -76,8 +76,6 @@
 
 static int do_find_defense(int str, int *move, int komaster, int kom_pos);
 static int defend1(int str, int *move, int komaster, int kom_pos);
-static int restricted_defend1(int str, int *move, int komaster, int kom_pos,
-                             int num_forbidden_moves, int *forbidden_moves);
 static int defend2(int str, int *move, int komaster, int kom_pos);
 static int defend3(int str, int *move, int komaster, int kom_pos);
 static int defend4(int str, int *move, int komaster, int kom_pos);
@@ -94,8 +92,6 @@
 static int do_attack(int str, int *move, int komaster, int kom_pos);
 static int attack1(int str, int *move, int komaster, int kom_pos);
 static int attack2(int str, int *move, int komaster, int kom_pos);
-static int restricted_attack2(int str, int *move, int komaster, int kom_pos,
-                             int num_forbidden_moves, int *forbidden_moves);
 static int attack3(int str, int *move, int komaster, int kom_pos);
 static int attack4(int str, int *move, int komaster, int kom_pos);
 static int find_cap2(int str, int alib, int blib, int *move,
@@ -762,522 +758,6 @@
 }
 
 
-/* ================================================================ */
-/*                     Global reading functions                     */
-/* ================================================================ */
-
-/* atari_atari(color, *move) looks for a series of ataris on
- * strings of the other color culminating in the capture of
- * a string which is thought to be invulnerable by the reading
- * code. Such a move can be missed since it may be that each
- * string involved individually can be rescued, but nevertheless
- * one of them can be caught. The simplest example is a double
- * atari. The return value is the size of the smallest opponent
- * worm. 
- *
- * One danger with this scheme is that the first atari
- * tried might be irrelevant to the actual combination.
- * To detect this possibility, once we've found a combination,
- * we mark that first move as forbidden, then try again. If
- * no combination of the same size or larger turns up, then
- * the first move was indeed essential.
- *
- * For the purpose of the move generation, returns the
- * size of the smallest of the worms under attack.
- */
-
-static int aa_status[BOARDMAX]; /* ALIVE, DEAD or CRITICAL */
-static int forbidden[BOARDMAX];
-static void compute_aa_status(int color);
-static int get_aa_status(int pos);
-static int do_atari_atari(int color, int *attack_point,
-                         int *defense_point, int cpos,
-                         int save_verbose, int minsize);
-
-/* Set to 1 if you want verbose traces from this function. */
-
-int
-atari_atari(int color, int *move, int save_verbose)
-{
-  int fpos;
-  int aa_val;
-
-  /* Collect worm statuses of opponent's worms. We need to
-   * know this because we only want to report unexpected
-   * results. For example, we do not want to report success
-   * if we find we can kill a worm which is already dead.
-   * The worm status of empty points is set to UNKNOWN to signal
-   * that stones added along the way need special attention.
-   */
-  if (aa_depth < 2)
-    return 0;
-  memset(forbidden, 0, sizeof(forbidden));
-
-  compute_aa_status(color);
-  
-  aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
-                         save_verbose, 0);
-
-  if (aa_val == 0)
-    return 0;
-
-  /* We try excluding the first atari found and see if the
-   * combination still works. Repeat until failure.
-   */
-  while (1) {
-    int new_aa_val;
-    forbidden[fpos] = 1;
-    new_aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
-                               save_verbose, aa_val);
-
-    /* The last do_atari_atari call fails. When do_atari_atari fails,
-     * it does not change the value of (fpos), so these correspond
-     * to a move that works and is necessary.
-     */
-    if (new_aa_val == 0) {
-      if (move) *move = fpos;
-      return aa_val;
-    }
-    aa_val = new_aa_val;
-  }
-
-  /* We'll never get here, but the compiler may be more happy if it
-   * looks like we're returning something.
-   */
-  return 0;
-}
-
-
-/* Helper function for computing the aa_status for a string. */
-static void
-compute_aa_status(int color)
-{
-  int other = OTHER_COLOR(color);
-  int pos;
-  /* Collect worm statuses of opponent's worms. We need to
-   * know this because we only want to report unexpected
-   * results. For example, we do not want to report success
-   * if we find we can kill a worm which is already dead.
-   * The worm status of empty points is set to UNKNOWN to signal
-   * that stones added along the way need special attention.
-   */
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (board[pos] == other) {
-      if (dragon[pos].matcher_status == DEAD)
-       aa_status[pos] = DEAD;
-      else if (worm[pos].attack_codes[0] != 0) {
-       if (worm[pos].defend_codes[0] != 0)
-         aa_status[pos] = CRITICAL;
-       else
-         aa_status[pos] = DEAD;
-      }
-      else
-       aa_status[pos] = ALIVE;
-    }
-    else if(ON_BOARD(pos))
-      aa_status[pos] = UNKNOWN;
-  }
-  
-  /* reclassify a worm with 2 liberties as INSUBSTANTIAL if capturing
-   * it does not result in a live group.
-   */
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (board[pos] == other
-       && worm[pos].origin == pos
-       && worm[pos].liberties == 2
-       && aa_status[pos] == ALIVE
-       && !owl_substantial(pos)) {
-      int pos2;
-      for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++)
-       if (ON_BOARD(pos2) && is_worm_origin(pos2, pos))
-         aa_status[pos2] = INSUBSTANTIAL;
-    }
-  }
-    
-  if (debug & DEBUG_ATARI_ATARI) {
-    gprintf("compute_aa_status() for %C\n", color);
-    gprintf("aa_status: (ALIVE worms not listed)\n");
-    for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-      if (board[pos] == other && is_worm_origin(pos, pos)) {
-       const char *status = "UNKNOWN (shouldn't happen)";
-       if (aa_status[pos] == DEAD)
-         status = "DEAD";
-       else if (aa_status[pos] == CRITICAL)
-         status = "CRITICAL";
-       else if (aa_status[pos] == INSUBSTANTIAL)
-         status = "INSUBSTANTIAL";
-       
-       if (aa_status[pos] != ALIVE)
-         gprintf("%1M: %s\n", pos, status);
-      }
-    }
-  }
-}
-
-/* Helper function for retrieving the aa_status for a string. We can't
- * reliably do this simply by looking up aa_status[pos] since this is
- * only valid at vertices which were non-empty at the start of the
- * reading. For later added stones, we need to find their aa_status by
- * locating a part of the string which was a worm at the beginning of
- * the reading.
- */
-static int
-get_aa_status(int pos)
-{
-  int stones[MAX_BOARD * MAX_BOARD];
-  int num_stones;
-  int k;
-
-  if (aa_status[pos] != UNKNOWN)
-    return aa_status[pos];
-
-  num_stones = findstones(pos, MAX_BOARD * MAX_BOARD, stones);
-  for (k = 0; k < num_stones; k++)
-    if (aa_status[stones[k]] != UNKNOWN)
-      return aa_status[stones[k]];
-
-  return UNKNOWN;
-}
-
-
-/* Helper function for atari_atari. Here worms is the number of
- * opponent worms involved in the combination, and (last_friendly) is
- * the location of the last friendly move played. Moves marked
- * with the forbidden array are not tried. If no move is found,
- * the values of *attack_point and *defense_point are not changed.
- *
- * If not NULL, *attack_point is left pointing to the location of the
- * attacking move, and *defense_point points to a move defending the
- * combination. In rare cases a defensive move might not be found. If
- * a non-static function calling do_atari_atari gets a return value of
- * 1 but NO_MOVE as the defense point, this should be treated as
- * equivalent to a return value of 0.
- */
-
-static int
-do_atari_atari(int color, int *attack_point, int *defense_point,
-              int last_friendly, int save_verbose, int minsize)
-{
-  int m, n;
-  int k;
-  
-  int other = OTHER_COLOR(color);
-
-  if (debug & DEBUG_ATARI_ATARI) {
-    gprintf("%odo_atari_atari: ");
-    dump_stack();
-    gprintf("%oforbidden moves: ");
-    for (m = 0; m < board_size; m++)
-      for (n = 0; n < board_size; n++) {
-       if (forbidden[POS(m, n)])
-         gprintf("%o%1m ", POS(m, n));
-      }
-    gprintf("\n");
-  }
-
-  /* First look for strings adjacent to the last friendly move played
-   * (or to another stone in the same string) which can be
-   * unexpectedly attacked.
-   */
-  if (last_friendly != NO_MOVE)
-    for (m = 0; m < board_size; m++)
-      for (n = 0; n < board_size; n++) {
-       int pos = POS(m, n);
-       int apos;
-
-       if (board[pos] != other)
-         continue;
-
-       if (pos != find_origin(pos))
-         continue;
-
-       if (minsize > 0 && countstones(pos) < minsize)
-         continue;
-
-       if (get_aa_status(pos) != ALIVE)
-         continue;
-
-       if (board[last_friendly] != EMPTY
-           && !adjacent_strings(last_friendly, pos))
-         continue;
-
-       if (board[last_friendly] == EMPTY
-           && !liberty_of_string(last_friendly, pos))
-         continue;
-       
-       if (debug & DEBUG_ATARI_ATARI)
-         gprintf("Considering attack of %1m. depth = %d.\n", pos, depth);
-       if (attack(pos, &apos)) {
-         if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
-           gprintf("%oThe worm %1m can be attacked at %1m after ", pos, apos);
-           dump_stack();
-         }       
-         if (attack_point) *attack_point = apos;
-         
-         /* We look for a move defending the combination.
-          * Normally this is found by find_defense but failing
-          * that, if the attacking move is a safe move for color, 
-          * it probably defends.
-          */
-         if (defense_point) {
-           if (!find_defense(pos, defense_point)) {
-             if (safe_move(apos, other)) {
-               *defense_point = apos;
-             }
-             /* No defense is found */
-             else {
-               *defense_point = NO_MOVE;
-             }
-           }
-         }
-
-         DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%1m)\n",
-               countstones(pos), pos);
-         return countstones(pos);
-       }
-      }
-
-  if (stackp > aa_depth)
-    return 0;
-
-  /* Next look for a string, not insubstantial, having exactly two
-   * liberties and no boundary stones in atari. Atari, fill, then try
-   * again. If that doesn't work, try the other atari.
-   */
-  for (m = 0; m < board_size; m++)
-    for (n = 0; n < board_size; n++) {
-      int pos = POS(m, n);
-      int libs[2];
-      int status;
-
-      if (board[pos] != other) 
-       continue;
-
-      if (pos != find_origin(pos))
-       continue;
-      
-      if (minsize > 0 && countstones(pos) < minsize)
-       continue;
-
-      status = get_aa_status(pos);
-      if (status != ALIVE)
-       continue;
-
-      if (findlib(pos, 2, libs) != 2)
-       continue;
-
-      for (k = 0; k < 2; k++) {
-       int apos = libs[k];
-       int bpos;
-
-       if (!forbidden[apos]
-           && (accurate_approxlib(apos, color, 2, NULL) > 1
-               || safe_move(apos, color))) {
-         if (trymove(apos, color, "do_atari_atari-A", pos,
-                      EMPTY, NO_MOVE)) {
-           /* try to defend the stone (m,n) which is in atari */
-           int aa_val = 0;
-
-           /* Because we know (m, n) is in atari there is a trivial
-            * attack and we can be sure find_defense() will give a
-            * useful defense point if it returns non-zero. Usually we
-            * would need to call attack_and_defend() to be certain of
-            * this.
-            *
-            * On the other hand, if there is no defense we have
-            * already been successful.
-            */
-           if (find_defense(pos, &bpos)
-               && trymove(bpos, other, "do_atari_atari-B", pos,
-                           EMPTY, NO_MOVE)) {
-             /* These moves may have been irrelevant for later
-               * reading, so in order to avoid horizon problems, we
-               * need to temporarily increase the depth values.
-              */
-             increase_depth_values();
-             increase_depth_values();
-             aa_val = do_atari_atari(color, NULL, defense_point,
-                                     apos, save_verbose, minsize);
-             decrease_depth_values();
-             decrease_depth_values();
-             popgo();
-           }
-           else {
-             /* No way to save the ataried stone. We have been successful. */
-             popgo();
-             if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
-               gprintf("%oThe worm %m can be attacked at %1m after ", m, n,
-                       apos);
-               dump_stack();
-             }   
-             if (attack_point) *attack_point = apos;
-             if (defense_point && !find_defense(pos, defense_point))
-               *defense_point = NO_MOVE;
-             
-             DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%m)\n",
-                   countstones(pos), m, n);
-             return countstones(pos);
-           }
-
-           if (aa_val) {
-             /* The atari at (ai,aj) seems to work but we still
-              * must check there is not a better defense.
-              */
-             int cpos;
-             int res = restricted_defend1(pos, &cpos, EMPTY, 0, 
-                                          1, &bpos);
-             if (res) {
-               if (trymove(cpos, other, "do_atari_atari-C", 
-                            pos, EMPTY, NO_MOVE)) {
-                 increase_depth_values();
-                 increase_depth_values();
-                 if (!do_atari_atari(color, NULL, defense_point,
-                                     apos, save_verbose, minsize)) 
-                   aa_val = 0;
-                 decrease_depth_values();
-                 decrease_depth_values();
-                 popgo();
-               }
-             }
-             if (aa_val) {
-               if (attack_point) *attack_point = apos;
-               popgo();
-               DEBUG(DEBUG_ATARI_ATARI, 
-                     "%oreturn value:%d (min %d, %d (%m))\n",
-                     gg_min(aa_val, countstones(pos)), aa_val,
-                     countstones(pos), m, n);
-               /* If no defense point is known and (ai,aj) is a safe
-                * move for other, it probably defends the combination.
-                */
-               if (defense_point 
-                   && (*defense_point == NO_MOVE
-                       || !safe_move(*defense_point, other))
-                   && safe_move(apos, other)) {
-                 *defense_point = apos;
-               }
-               return gg_min(aa_val, countstones(pos));
-             }
-           }
-           popgo();
-         }
-       }
-      }
-    }
-  return 0;
-}
-
-/* Ask the atari_atari code whether there appears any combination
- * attack which would capture at least minsize stones after playing at
- * (tpos). If this happens, (*move) points to a move which prevents
- * this blunder.
- *
- * FIXME: Most of the code below is common with atari_atari() and
- *        should be broken out of both functions.
- */
-int
-atari_atari_confirm_safety(int color, int tpos, int *move, int minsize)
-{
-  int fpos;
-  int defense_point = NO_MOVE, after_defense_point = NO_MOVE;
-  int aa_val, after_aa_val;
-  int other = OTHER_COLOR(color);
-
-  /* If aa_depth is too small, we can't see any combination attacks,
-   * so in this respect the move is safe enough.
-   */
-  if (aa_depth < 2)
-    return 1;
-
-  memset(forbidden, 0, sizeof(forbidden));
-
-  compute_aa_status(other);
-  
-  /* Accept illegal ko capture here. */
-  if (!tryko(tpos, color, NULL, EMPTY, NO_MOVE))
-    /* Really shouldn't happen. */
-    abortgo(__FILE__, __LINE__, "trymove", I(tpos), J(tpos)); 
-  increase_depth_values();
-
-  aa_val = do_atari_atari(other, &fpos, &defense_point,
-                         NO_MOVE, 0, minsize);
-  after_aa_val = aa_val;
-
-  if (aa_val == 0 || defense_point == NO_MOVE) {
-
-  /* No sufficiently large combination attack, so the move is safe from
-   * this danger.
-   *
-   * On rare occasions do_atari_atari might find a combination
-   * but no defense. In this case we assume that the combination
-   * is illusory.
-   */
-
-    popgo();
-    decrease_depth_values();
-    return 1;
-  }
-
-  while (aa_val >= after_aa_val) {
-    /* Try dropping moves from the combination and see if it still
-     * works. What we really want is to get the proper defense move
-     * into (*move).
-     */
-    after_defense_point = defense_point;
-    forbidden[fpos] = 1;
-    aa_val = do_atari_atari(other, &fpos, &defense_point, 
-                           NO_MOVE, 0, aa_val);
-  }
-
-  popgo();
-  decrease_depth_values();
-  /* We know that a combination exists, but we don't know if
-   * the original move at (aa) was really relevant. So we
-   * try omitting it and see if a combination is still found.
-   */
-  if (do_atari_atari(other, NULL, NULL, NO_MOVE, 0, minsize) >= after_aa_val)
-    return 1;
-  else {
-    if (move) *move = after_defense_point;
-    return 0;
-  }
-}
-
-
-/* Ask the atari_atari code if after color plays at (apos)
- * and other plays at (bpos) there appears any combination
- * attack. Returns the size of the combination.
- *
- * FIXME: Most of the code below is common with atari_atari() and
- *        should be broken out of both functions.
- */
-
-int
-atari_atari_try_combination(int color, int apos, int bpos)
-{
-  int other = OTHER_COLOR(color);
-  int aa_val = 0;
-  int save_verbose = verbose;
-
-  if (aa_depth < 2)
-    return 0;
-  if (verbose > 0)
-    verbose--;
-  memset(forbidden, 0, sizeof(forbidden));
-
-  compute_aa_status(color);
-
-  if (trymove(apos, color, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
-    if (trymove(bpos, other, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
-      aa_val = do_atari_atari(color, NULL, NULL, apos, 0, 0);
-      popgo();
-    }
-    popgo();
-  }
-  verbose = save_verbose;
-  return aa_val;
-}
-
-
 /* ================================================================ */  
 /*                       Defensive functions                        */
 /* ================================================================ */
@@ -4956,6 +4436,7 @@
 /*                Restricted Attack and Defense                     */
 /* ================================================================ */
 
+
 /* These functions try to attack and defend a string, avoiding moves
  * from a certain set. It is assumed that as soon as the string gets
  * three liberties, it is alive.
@@ -4979,7 +4460,7 @@
  * move that defends the string (str) with one liberty,
  * not considering moves from the list.
  */
-static int
+int
 restricted_defend1(int str, int *move, int komaster, int kom_pos,
                   int num_forbidden_moves, int *forbidden_moves)
 {
@@ -5109,7 +4590,7 @@
  * move that attacks the string (str) with two liberties,
  * not considering moves from the list.
  */
-static int
+int
 restricted_attack2(int str, int *move, int komaster, int kom_pos,
                   int num_forbidden_moves, int *forbidden_moves)
 {
@@ -5197,7 +4678,10 @@
   return 0;
 }
 
-/* Returns true if the move is in a given list of moves. */
+
+/*
+ * Returns true if the move is in a given list of moves.
+ */
 
 static int
 in_list(int move, int num_moves, int *moves)
diff -ur gnugo-sync/regression/endgame.tst gnugo-iw/regression/endgame.tst
--- gnugo-sync/regression/endgame.tst   Sat Nov 10 15:37:00 2001
+++ gnugo-iw/regression/endgame.tst     Sat Nov 10 16:38:08 2001
@@ -17,9 +17,10 @@
 103 gg_genmove black
 #? [G9]
 
+# E7 has slightly worse shape but does the job as well as E8 or D8
 loadsgf games/endgame1.sgf 4
 104 gg_genmove white
-#? [E8|D8]
+#? [E8|D8|E7]
 
 loadsgf games/endgame1.sgf 5
 105 gg_genmove black
@@ -30,13 +31,14 @@
 #? [G1|H1|F3]
 
 # J3 is 0 points double sente.
+# Double sente?? White can't play there.  /iw
 loadsgf games/endgame1.sgf 7
 107 gg_genmove black
-#? [J3|A7]*
+#? [J3|A7]
 
 loadsgf games/endgame1.sgf 8
 108 gg_genmove white
-#? [G1]
+#? [G1|H1]
 
 loadsgf games/endgame1.sgf 9
 109 gg_genmove black



reply via email to

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