gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] liberty counting, revised


From: Paul Pogonyshev
Subject: [gnugo-devel] liberty counting, revised
Date: Tue, 15 Oct 2002 22:21:00 +0300

i checked the speed. rewritten function is 4-8 times faster (depending
on position) than the old one, which seems to be good enough ;)

i also ran the complete regression suit with an assertion set,
checking that new function always gives correct result. after one
bugfix it started doing so ;)

changes:
  - exactlib() is renamed to accuratelib() as Marco Scheurer proposed.
    gtp command is renamed to accuratelib as well.
  - accuratelib() is bugfixed and now seems to always tell the truth.
  - incremental_sloppy_self_atari() is finally integrated into
    is_self_atari().

code maintenance changes:
  - new 'neighbor' variable in extended_chainlinks() replaced
    (libs[r] + delta[k]) expression which was repeated 4 times there.
  - use variables for pos + delta[k] instead of for delta[k] alone in
    slow_approxlib().

regression delta is zero.

Paul


Index: gnugo/engine/utils.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/utils.c,v
retrieving revision 1.58
diff -u -r1.58 utils.c
--- gnugo/engine/utils.c        9 Oct 2002 18:36:23 -0000       1.58
+++ gnugo/engine/utils.c        15 Oct 2002 19:10:37 -0000
@@ -762,52 +762,6 @@
   ko_depth          = save_ko_depth;
 }
 
-/* Play a stone at (pos) and count the number of liberties for the
- * resulting string. This requires (pos) to be empty.
- *
- * This function differs from approxlib() by the fact that it removes
- * captured stones before counting the liberties.
- */
-
-int
-accurate_approxlib(int pos, int color, int maxlib, int *libs)
-{
-  int fast_liberties = -1;
-  int liberties = 0;
-  SGFTree *save_sgf_dumptree = sgf_dumptree;
-  int save_count_variations = count_variations;
-
-  ASSERT1(board[pos] == EMPTY, pos);
-  ASSERT1(IS_STONE(color), pos);
-
-  if (!libs) {
-    fast_liberties = fastlib(pos, color, 0);
-    if (fast_liberties >= 0) {
-      return fast_liberties;
-    } 
-  }
-
-  sgf_dumptree = 0;
-  /* Use tryko() since we don't care whether the move would violate
-   * the ko rule.
-   */
-  if (tryko(pos, color, "accurate approxlib", EMPTY, 0)) {
-    if (libs != NULL)
-      liberties = findlib(pos, maxlib, libs);
-    else
-      liberties = countlib(pos);
-    popgo();
-  }
-
-  if (fast_liberties >= 0 && liberties > 0) {
-    ASSERT1(fast_liberties == liberties, pos);
-  }
-
-  sgf_dumptree = save_sgf_dumptree;
-  count_variations = save_count_variations;
-
-  return liberties;
-}
 
 /*******************
  * Detect blunders *
@@ -855,7 +809,7 @@
             char safe_stones[BOARDMAX])
 {
   int libs[5];
-  int liberties = accurate_approxlib(move, color, 5, libs);
+  int liberties = accuratelib(move, color, 5, libs);
   int apos;
   int trouble = 0;
   int save_verbose = verbose;
Index: gnugo/engine/readconnect.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/readconnect.c,v
retrieving revision 1.36
diff -u -r1.36 readconnect.c
--- gnugo/engine/readconnect.c  10 Sep 2002 20:06:01 -0000      1.36
+++ gnugo/engine/readconnect.c  15 Oct 2002 19:10:46 -0000
@@ -2946,7 +2946,7 @@
   if (findlib(str, 1, &lib) > 1)
     return 0;
 
-  if (accurate_approxlib(lib, board[str], 2, NULL) > 1)
+  if (accuratelib(lib, board[str], 2, NULL) > 1)
     return 0;
 
   /* FIXME: Should exclude snapback. */
Index: gnugo/engine/owl.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.111
diff -u -r1.111 owl.c
--- gnugo/engine/owl.c  9 Oct 2002 23:23:21 -0000       1.111
+++ gnugo/engine/owl.c  15 Oct 2002 19:11:10 -0000
@@ -4285,8 +4285,8 @@
       else
        pos2 = libs[0];
 
-      if (accurate_approxlib(pos2, color, MAXLIBS, NULL)
-         > accurate_approxlib(defense_point, color, MAXLIBS, NULL)
+      if (accuratelib(pos2, color, MAXLIBS, NULL)
+         > accuratelib(defense_point, color, MAXLIBS, NULL)
          && does_defend(pos2, lunch)) {
        TRACE("Moved defense of lunch %1m from %1m to %1m.\n",
              lunch, defense_point, pos2);
Index: gnugo/engine/liberty.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
retrieving revision 1.124
diff -u -r1.124 liberty.h
--- gnugo/engine/liberty.h      9 Oct 2002 18:36:23 -0000       1.124
+++ gnugo/engine/liberty.h      15 Oct 2002 19:11:18 -0000
@@ -159,6 +159,7 @@
 int findlib(int str, int maxlib, int *libs);
 int fastlib(int pos, int color, int ignore_capture);
 int approxlib(int pos, int color, int maxlib, int *libs);
+int accuratelib(int pos, int color, int maxlib, int *libs);
 int count_common_libs(int str1, int str2);
 int find_common_libs(int str1, int str2, int maxlib, int *libs);
 int have_common_lib(int str1, int str2, int *lib);
@@ -169,9 +170,6 @@
 
 void update_random_seed(void);
 
-
-/* Play at (pos) and then count the liberties. */
-int accurate_approxlib(int pos, int color, int maxlib, int *libs);
 
 /* Check for self atari. */
 int is_self_atari(int pos, int color);
Index: gnugo/engine/board.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/board.c,v
retrieving revision 1.52
diff -u -r1.52 board.c
--- gnugo/engine/board.c        5 Oct 2002 09:15:44 -0000       1.52
+++ gnugo/engine/board.c        15 Oct 2002 19:11:39 -0000
@@ -202,6 +202,17 @@
   (board[pos] == string[s].color\
    && string[string_number[pos]].mark != string_mark)
 
+/* Note that these two macros are not complementary. Both return
+ * false if board[pos] != color.
+ */
+#define UNMARKED_COLOR_STRING(pos, color)\
+  (board[pos] == color\
+   && string[string_number[pos]].mark != string_mark)
+
+#define MARKED_COLOR_STRING(pos, color)\
+  (board[pos] == color\
+   && string[string_number[pos]].mark == string_mark)
+
 #define MARK_STRING(pos) string[string_number[pos]].mark = string_mark
 
 #define STRING_AT_VERTEX(pos, s)\
@@ -275,7 +286,6 @@
 static int do_remove_string(int s);
 static void do_play_move(int pos, int color);
 static int slow_approxlib(int pos, int color, int maxlib, int *libs);
-static int incremental_sloppy_self_atari(int pos, int color);
 
 
 /* Statistics. */
@@ -1996,16 +2006,17 @@
 
 /* Count the liberties a stone of the given color would get if played
  * at (pos).  Captures are ignored based on the ignore_capture flag.
- * (pos) must be empty.  It will fail if there is more than one
+ * (pos) must be empty.  It will fail if there is more than two
  * string neighbor of the same color.  In this case, the return value
- * is -1.  Captures are not handled, so if ignore_capture is 0, and
- * a capture is required, -1 is returned.
+ * is -1.  Captures are handled in a very limited way, so if 
+ * ignore_capture is 0, and a capture is required, it will often
+ * return -1.
  *
  * The intent of this function is to be as fast as possible, not
- * necessarily complete.
+ * necessarily complete. But if it returns a positive value (meaning
+ * it has succeeded), the value is guaranteed to be correct.
  *
- * Note well, that it relies on incremental data (?), and the number
- * of liberties (if over MAX_LIBERTIES) may be inaccurate (?).
+ * Note well, that it relies on incremental data.
  */
 
 int
@@ -2042,6 +2053,7 @@
         ally1 = neighbor;
     }
   }
+  
   for (k = 0; k < 4; k++) {
     int neighbor = pos + delta[k];
     int neighbor_color = board[neighbor];
@@ -2049,11 +2061,16 @@
         && neighbor_color == other
        && LIBERTIES(neighbor) == 1) {
       int neighbor_size = COUNTSTONES(neighbor);
+#if 0
       if ((neighbor_size <= 2 && !ally1)
-          || (neighbor_size == 1
+       || (neighbor_size == 1
               && ally1 
               && !ally2
               && COUNTSTONES(ally1) == 1)) {
+#else
+      if (neighbor_size == 1
+         || (neighbor_size == 2 && !ally1)) {
+#endif
         /* Here, we can gain only the adjacent new liberty. */
         fast_liberties++;
       }
@@ -2072,6 +2089,7 @@
     fast_liberties += LIBERTIES(ally1) - 1;
   if (ally2)
     fast_liberties += LIBERTIES(ally2) - count_common_libs(ally1, ally2);
+  
   return fast_liberties;
 }
 
@@ -2092,16 +2110,14 @@
 {
   int k;
   int liberties = 0;
-  int fast_liberties = 0;
 
   ASSERT1(board[pos] == EMPTY, pos);
   ASSERT1(IS_STONE(color), pos);
 
   if (!libs) {
-    fast_liberties = fastlib(pos, color, 1);
-    if (fast_liberties >= 0) {
+    int fast_liberties = fastlib(pos, color, 1);
+    if (fast_liberties >= 0)
       return fast_liberties;
-    }
   }
 
   if (!strings_initialized)
@@ -2123,7 +2139,7 @@
   MARK_LIBERTY(pos);
     
   if (UNMARKED_LIBERTY(SOUTH(pos))) {
-    if (libs != NULL && liberties < maxlib)
+    if (libs != NULL)
       libs[liberties] = SOUTH(pos);
     liberties++;
     /* Stop counting if we reach maxlib. */
@@ -2132,11 +2148,11 @@
     MARK_LIBERTY(SOUTH(pos));
   }
   else if (board[SOUTH(pos)] == color) {
-    int s = string_number[SOUTH(pos)];
-    for (k = 0; k < string[s].liberties; k++) {
-      int lib = string[s].libs[k];
+    struct string_data *s = &string[string_number[SOUTH(pos)]];
+    for (k = 0; k < s->liberties; k++) {
+      int lib = s->libs[k];
       if (UNMARKED_LIBERTY(lib)) {
-       if (libs != NULL && liberties < maxlib)
+       if (libs != NULL)
          libs[liberties] = lib;
        liberties++;
        if (liberties >= maxlib)
@@ -2147,7 +2163,7 @@
   }
   
   if (UNMARKED_LIBERTY(WEST(pos))) {
-    if (libs != NULL && liberties < maxlib)
+    if (libs != NULL)
       libs[liberties] = WEST(pos);
     liberties++;
     /* Stop counting if we reach maxlib. */
@@ -2156,11 +2172,11 @@
     MARK_LIBERTY(WEST(pos));
   }
   else if (board[WEST(pos)] == color) {
-    int s = string_number[WEST(pos)];
-    for (k = 0; k < string[s].liberties; k++) {
-      int lib = string[s].libs[k];
+    struct string_data *s = &string[string_number[WEST(pos)]];
+    for (k = 0; k < s->liberties; k++) {
+      int lib = s->libs[k];
       if (UNMARKED_LIBERTY(lib)) {
-       if (libs != NULL && liberties < maxlib)
+       if (libs != NULL)
          libs[liberties] = lib;
        liberties++;
        if (liberties >= maxlib)
@@ -2171,7 +2187,7 @@
   }
   
   if (UNMARKED_LIBERTY(NORTH(pos))) {
-    if (libs != NULL && liberties < maxlib)
+    if (libs != NULL)
       libs[liberties] = NORTH(pos);
     liberties++;
     /* Stop counting if we reach maxlib. */
@@ -2180,11 +2196,11 @@
     MARK_LIBERTY(NORTH(pos));
   }
   else if (board[NORTH(pos)] == color) {
-    int s = string_number[NORTH(pos)];
-    for (k = 0; k < string[s].liberties; k++) {
-      int lib = string[s].libs[k];
+    struct string_data *s = &string[string_number[NORTH(pos)]];
+    for (k = 0; k < s->liberties; k++) {
+      int lib = s->libs[k];
       if (UNMARKED_LIBERTY(lib)) {
-       if (libs != NULL && liberties < maxlib)
+       if (libs != NULL)
          libs[liberties] = lib;
        liberties++;
        if (liberties >= maxlib)
@@ -2194,29 +2210,27 @@
     }
   }
   
+  /* Note that we don't mark liberties anymore since we're about
+   * to leave.
+   */
   if (UNMARKED_LIBERTY(EAST(pos))) {
-    if (libs != NULL && liberties < maxlib)
+    if (libs != NULL)
       libs[liberties] = EAST(pos);
     liberties++;
     /* Stop counting if we reach maxlib. */
     if (liberties >= maxlib)
       return liberties;
-    /* Unneeded since we're about to leave. */
-#if 0
-    MARK_LIBERTY(EAST(pos));
-#endif
   }
   else if (board[EAST(pos)] == color) {
-    int s = string_number[EAST(pos)];
-    for (k = 0; k < string[s].liberties; k++) {
-      int lib = string[s].libs[k];
+    struct string_data *s = &string[string_number[EAST(pos)]];
+    for (k = 0; k < s->liberties; k++) {
+      int lib = s->libs[k];
       if (UNMARKED_LIBERTY(lib)) {
-       if (libs != NULL && liberties < maxlib)
+       if (libs != NULL)
          libs[liberties] = lib;
        liberties++;
        if (liberties >= maxlib)
          return liberties;
-       MARK_LIBERTY(lib);
       }
     }
   }  
@@ -2225,6 +2239,194 @@
 }
 
 
+/* Find the liberties a stone of the given color would get if played
+ * at (pos). This function takes into consideration all captures. Its
+ * return value is exact in that sense it counts all the liberties,
+ * unless (maxlib) allows it to stop earlier. (pos) must be empty. If
+ * libs != NULL, the locations of up to maxlib liberties are written
+ * into libs[]. The counting of liberties may or may not be halted
+ * when maxlib is reached. The number of liberties is returned.
+ *
+ * This function guarantees that liberties which are not results of
+ * captures come first in libs[] array. To find whether all the 
+ * liberties starting from a given one are results of captures, one
+ * may use  if (board[libs[k]] != EMPTY)  construction.
+ *
+ * If you want the number or the locations of all liberties, however
+ * many they are, you should pass MAXLIBS as the value for maxlib and
+ * allocate space for libs[] accordingly.
+ */
+
+int
+accuratelib(int pos, int color, int maxlib, int *libs)
+{
+  int k, l;
+  int liberties = 0;
+  int lib;
+  int captured[4];
+  int captures = 0;
+
+  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(IS_STONE(color), pos);
+
+  if (!libs) {
+    int fast_liberties = fastlib(pos, color, 0);
+    if (fast_liberties >= 0)
+      return fast_liberties;
+  }
+  
+  if (!strings_initialized)
+    init_board();
+
+  string_mark++;
+  liberty_mark++;
+  MARK_LIBERTY(pos);
+
+  for (k = 0; k < 4; k++) {
+    int pos2 = pos + delta[k];
+    if (UNMARKED_LIBERTY(pos2)) {
+      /* A trivial liberty */
+      if (libs)
+       libs[liberties] = pos2;
+      liberties++;
+      if (liberties >= maxlib)
+       return liberties;
+
+      MARK_LIBERTY(pos2);
+    }
+    else if (board[pos2] == color) {
+      /* An own neighbor string */
+      struct string_data *s = &string[string_number[pos2]];
+      
+      if (s->liberties <= MAX_LIBERTIES || maxlib <= MAX_LIBERTIES - 1) {
+       /* The easy case - we already have all (necessary) liberties of
+        * the string listed
+        */
+       for (l = 0; l < s->liberties; l++) {
+         lib = s->libs[l];
+         if (UNMARKED_LIBERTY(lib)) {
+           if(libs)
+             libs[liberties] = lib;
+           liberties++;
+           if(liberties >= maxlib)
+             return liberties;
+
+           MARK_LIBERTY(lib);
+         }
+       }
+      }
+      else {
+       /* The harder case - we need to find all the liberties of the
+        * string by traversing its stones. We stop as soon as we have
+        * traversed all the stones or have reached maxlib. Unfortunately,
+        * we cannot use the trick from findlib() since some of the
+        * liberties may already have been marked.
+        */
+       int stone = pos2;
+       do {
+         if (UNMARKED_LIBERTY(SOUTH(stone))) {
+           if (libs)
+             libs[liberties] = SOUTH(stone);
+           liberties++;
+           if (liberties >= maxlib)
+             return liberties;
+
+           MARK_LIBERTY(SOUTH(stone));
+         }
+         
+         if (UNMARKED_LIBERTY(WEST(stone))) {
+           if (libs)
+             libs[liberties] = WEST(stone);
+           liberties++;
+           if (liberties >= maxlib)
+             return liberties;
+
+           MARK_LIBERTY(WEST(stone));
+         }
+
+         if (UNMARKED_LIBERTY(NORTH(stone))) {
+           if (libs)
+             libs[liberties] = NORTH(stone);
+           liberties++;
+           if (liberties >= maxlib)
+             return liberties;
+
+           MARK_LIBERTY(NORTH(stone));
+         }
+
+         if (UNMARKED_LIBERTY(EAST(stone))) {
+           if (libs)
+             libs[liberties] = EAST(stone);
+           liberties++;
+           if (liberties >= maxlib)
+             return liberties;
+
+           MARK_LIBERTY(EAST(stone));
+         }
+
+         stone = NEXT_STONE(stone);
+       } while (stone != pos2);
+      }
+
+      MARK_STRING(pos2);
+    }
+    else if (board[pos2] == OTHER_COLOR(color)
+        && string[string_number[pos2]].liberties == 1) {
+      /* A capture. */
+      captured[captures++] = pos2;
+    }
+  }
+
+  /* Now we look at all the captures found in the previous step */
+  for (k = 0; k < captures; k++) {
+    lib = captured[k];
+
+    /* Add the stone adjacent to (pos) to the list of liberties if
+     * it is not also adjacent to an own marked string (otherwise,
+     * it will be added later).
+     */
+    if (!MARKED_COLOR_STRING(SOUTH(lib), color)
+       && !MARKED_COLOR_STRING(WEST(lib), color)
+       && !MARKED_COLOR_STRING(NORTH(lib), color)
+       && !MARKED_COLOR_STRING(EAST(lib), color)) {
+      if (libs)
+       libs[liberties] = lib;
+      liberties++;
+      if (liberties >= maxlib)
+       return liberties;
+    }
+
+    /* Check if we already know of this capture. */
+    for (l = 0; l < k; l++)
+      if (string_number[captured[l]] == string_number[lib])
+       break;
+
+    if (l == k) {
+      /* Traverse all the stones of the capture and add to the list
+       * of liberties those, which are adjacent to at least one own
+       * marked string.
+       */
+      do {
+       if (MARKED_COLOR_STRING(SOUTH(lib), color)
+           || MARKED_COLOR_STRING(WEST(lib), color)
+           || MARKED_COLOR_STRING(NORTH(lib), color)
+           || MARKED_COLOR_STRING(EAST(lib), color)) {
+         if (libs)
+           libs[liberties] = lib;
+         liberties++;
+         if (liberties >= maxlib)
+           return liberties;
+       }
+
+       lib = NEXT_STONE(lib);
+      } while (lib != captured[k]);
+    }
+  }
+  
+  return liberties;
+}
+
+
 /* Find the number of common liberties of the two strings at str1 and str2.
  */
 
@@ -2596,10 +2798,11 @@
    */
   for (r = 0; r < liberties; r++) {
     for (k = 0; k < 4; k++) {
-      if ((board[libs[r] + delta[k]] == OTHER_COLOR(board[str])
-          || (both_colors && board[libs[r] + delta[k]] == board[str]))
-         && UNMARKED_STRING(libs[r] + delta[k])) {
-       adj[n] = string[string_number[libs[r] + delta[k]]].origin;
+      int neighbor = libs[r] + delta[k];
+      if ((board[neighbor] == OTHER_COLOR(board[str])
+          || (both_colors && board[neighbor] == board[str]))
+         && UNMARKED_STRING(neighbor)) {
+       adj[n] = string[string_number[neighbor]].origin;
        MARK_STRING(adj[n]);
        n++;
       }
@@ -2636,8 +2839,15 @@
 int
 is_self_atari(int pos, int color)
 {
-  int liberties;
-  int result;
+  int other = OTHER_COLOR(color);
+  /* number of empty neighbors */
+  int trivial_liberties = 0;
+  /* number of captured opponent strings */
+  int captures = 0;
+  /* Whether there is a friendly neighbor with a spare liberty. If it
+   * has more than one spare liberty we immediately return 0.
+   */
+  int far_liberties = 0;
   
   ASSERT_ON_BOARD1(pos);
   ASSERT1(board[pos] == EMPTY, pos);
@@ -2646,21 +2856,82 @@
   if (!strings_initialized)
     init_board();
 
-  /* 1. Try first without really putting the stone on the board. */
-  /* FIXME: Integrate incremental_sloppy_self_atari() here. */
-  result = incremental_sloppy_self_atari(pos, color);
-  if (result != -1)
-    return result;
+  /* 1. Try first to solve the problem without much work. */
+  string_mark++;
+  
+  if (LIBERTY(SOUTH(pos)))
+    trivial_liberties++;
+  else if (board[SOUTH(pos)] == color) {
+    if (LIBERTIES(SOUTH(pos)) > 2)
+      return 0;
+    if (LIBERTIES(SOUTH(pos)) == 2)
+      far_liberties++;
+  }
+  else if (board[SOUTH(pos)] == other
+          && LIBERTIES(SOUTH(pos)) == 1 && UNMARKED_STRING(SOUTH(pos))) {
+    captures++;
+    MARK_STRING(SOUTH(pos));
+  }
+
+  if (LIBERTY(WEST(pos)))
+    trivial_liberties++;
+  else if (board[WEST(pos)] == color) {
+    if (LIBERTIES(WEST(pos)) > 2)
+      return 0;
+    if (LIBERTIES(WEST(pos)) == 2)
+      far_liberties++;
+  }
+  else if (board[WEST(pos)] == other
+          && LIBERTIES(WEST(pos)) == 1 && UNMARKED_STRING(WEST(pos))) {
+    captures++;
+    MARK_STRING(WEST(pos));
+  }
+
+  if (LIBERTY(NORTH(pos)))
+    trivial_liberties++;
+  else if (board[NORTH(pos)] == color) {
+    if (LIBERTIES(NORTH(pos)) > 2)
+      return 0;
+    if (LIBERTIES(NORTH(pos)) == 2)
+      far_liberties++;
+  }
+  else if (board[NORTH(pos)] == other
+          && LIBERTIES(NORTH(pos)) == 1 && UNMARKED_STRING(NORTH(pos))) {
+    captures++;
+    MARK_STRING(NORTH(pos));
+  }
+
+  if (LIBERTY(EAST(pos)))
+    trivial_liberties++;
+  else if (board[EAST(pos)] == color) {
+    if (LIBERTIES(EAST(pos)) > 2)
+      return 0;
+    if (LIBERTIES(EAST(pos)) == 2)
+      far_liberties++;
+  }
+  else if (board[EAST(pos)] == other
+          && LIBERTIES(EAST(pos)) == 1 && UNMARKED_STRING(EAST(pos))) {
+    captures++;
+#if 0
+    MARK_STRING(EAST(pos));
+#endif
+  }
 
-  /* 2. It was not so easy.  Now see if we can put the stone on the board.
-   *    If we can't, this is a self atari.
+  /* Each captured string is guaranteed to produce at least one
+   * liberty. These are disjoint from both trivial liberties and far
+   * liberties. The two latter may however coincide.
    */
-  if (!do_trymove(pos, color, 1))
+  if (trivial_liberties + captures >= 2)
+    return 0;
+
+  if ((far_liberties > 0) + captures >= 2)
+    return 0;
+
+  if (captures == 0 && far_liberties + trivial_liberties <= 1)
     return 1;
-  liberties = string[string_number[pos]].liberties;
-  silent_popgo();
-  
-  return liberties <= 1;
+
+  /* 2. It was not so easy.  We use accuratelib() in this case. */
+  return accuratelib(pos, color, 2, NULL) <= 1;
 }
 
 
@@ -3854,44 +4125,44 @@
    */
   string_mark++;
 
-  if (board[south] == color && UNMARKED_STRING(south)) {
+  if (UNMARKED_COLOR_STRING(south, color)) {
     neighbor_allies++;
     s = string_number[south];
     MARK_STRING(south);
   }
-  else if (board[south] == other && UNMARKED_STRING(south)) {
+  else if (UNMARKED_COLOR_STRING(south, other)) {
     remove_liberty(string_number[south], pos);
     MARK_STRING(south);
   }    
   
-  if (board[west] == color && UNMARKED_STRING(west)) {
+  if (UNMARKED_COLOR_STRING(west, color)) {
     neighbor_allies++;
     s = string_number[west];
     MARK_STRING(west);
   }
-  else if (board[west] == other && UNMARKED_STRING(west)) {
+  else if (UNMARKED_COLOR_STRING(west, other)) {
     remove_liberty(string_number[west], pos);
     MARK_STRING(west);
   }    
   
-  if (board[north] == color && UNMARKED_STRING(north)) {
+  if (UNMARKED_COLOR_STRING(north, color)) {
     neighbor_allies++;
     s = string_number[north];
     MARK_STRING(north);
   }
-  else if (board[north] == other && UNMARKED_STRING(north)) {
+  else if (UNMARKED_COLOR_STRING(north, other)) {
     remove_liberty(string_number[north], pos);
     MARK_STRING(north);
   }    
   
-  if (board[east] == color && UNMARKED_STRING(east)) {
+  if (UNMARKED_COLOR_STRING(east, color)) {
     neighbor_allies++;
     s = string_number[east];
 #if 0
     MARK_STRING(east);
 #endif
   }
-  else if (board[east] == other && UNMARKED_STRING(east)) {
+  else if (UNMARKED_COLOR_STRING(east, other)) {
     remove_liberty(string_number[east], pos);
 #if 0
     MARK_STRING(east);
@@ -3943,140 +4214,44 @@
   liberty_mark++;
   MARK_LIBERTY(pos);
   string_mark++;
+  
   for (k = 0; k < 4; k++) {
-    int d = delta[k];
-    if (UNMARKED_LIBERTY(pos + d)) {
+    int pos2 = pos + delta[k];
+    if (UNMARKED_LIBERTY(pos2)) {
       if (libs)
-       libs[liberties] = pos + d;
+       libs[liberties] = pos2;
       liberties++;
       if (liberties == maxlib)
        return liberties;
-      MARK_LIBERTY(pos + d);
+      MARK_LIBERTY(pos2);
     }
-    else if (board[pos + d] == color
-            && UNMARKED_STRING(pos + d)) {
-      int s = string_number[pos + d];
-      int pos2;
-      pos2 = FIRST_STONE(s);
+    else if (UNMARKED_COLOR_STRING(pos2, color)) {
+      int s = string_number[pos2];
+      int stone;
+      stone = FIRST_STONE(s);
       do {
        int l;
        for (l = 0; l < 4; l++) {
-         int d2 = delta[l];
-         if (UNMARKED_LIBERTY(pos2 + d2)) {
+         int lib = stone + delta[l];
+         if (UNMARKED_LIBERTY(lib)) {
            if (libs)
-             libs[liberties] = pos2 + d2;
+             libs[liberties] = lib;
            liberties++;
            if (liberties == maxlib)
              return liberties;
-           MARK_LIBERTY(pos2 + d2);
+           MARK_LIBERTY(lib);
          }
        }
        
-       pos2 = NEXT_STONE(pos2);
-      } while (!BACK_TO_FIRST_STONE(s, pos2));
-      MARK_STRING(pos + d);
+       stone = NEXT_STONE(stone);
+      } while (!BACK_TO_FIRST_STONE(s, stone));
+      MARK_STRING(pos2);
     }
   }
+  
   return liberties;
 }
 
-
-/* Determine whether a move by color at pos might be a self atari.
- * This function is sloppy in that it only does a quick check for two
- * liberties and might miss certain cases.
- * Return value 0 means it cannot be a self atari.
- * Return value 1 means it definitely is a self atari.
- * Return value -1 means uncertain.
- */
-
-static int
-incremental_sloppy_self_atari(int pos, int color)
-{
-  int other = OTHER_COLOR(color);
-  /* number of empty neighbors */
-  int trivial_liberties = 0;
-  /* number of captured opponent strings */
-  int captures = 0;
-  /* Whether there is a friendly neighbor with a spare liberty. If it
-   * has more than one spare liberty we immediately return 0.
-   */
-  int far_liberties = 0;
-
-  /* Clear string mark. */
-  string_mark++;
-  
-  if (board[SOUTH(pos)] == EMPTY)
-    trivial_liberties++;
-  else if (board[SOUTH(pos)] == color) {
-    if (LIBERTIES(SOUTH(pos)) > 2)
-      return 0;
-    if (LIBERTIES(SOUTH(pos)) == 2)
-      far_liberties++;
-  }
-  else if (board[SOUTH(pos)] == other
-          && LIBERTIES(SOUTH(pos)) == 1 && UNMARKED_STRING(SOUTH(pos))) {
-    captures++;
-    MARK_STRING(SOUTH(pos));
-  }
-
-  if (board[WEST(pos)] == EMPTY)
-    trivial_liberties++;
-  else if (board[WEST(pos)] == color) {
-    if (LIBERTIES(WEST(pos)) > 2)
-      return 0;
-    if (LIBERTIES(WEST(pos)) == 2)
-      far_liberties++;
-  }
-  else if (board[WEST(pos)] == other
-          && LIBERTIES(WEST(pos)) == 1 && UNMARKED_STRING(WEST(pos))) {
-    captures++;
-    MARK_STRING(WEST(pos));
-  }
-
-  if (board[NORTH(pos)] == EMPTY)
-    trivial_liberties++;
-  else if (board[NORTH(pos)] == color) {
-    if (LIBERTIES(NORTH(pos)) > 2)
-      return 0;
-    if (LIBERTIES(NORTH(pos)) == 2)
-      far_liberties++;
-  }
-  else if (board[NORTH(pos)] == other
-          && LIBERTIES(NORTH(pos)) == 1 && UNMARKED_STRING(NORTH(pos))) {
-    captures++;
-    MARK_STRING(NORTH(pos));
-  }
-
-  if (board[EAST(pos)] == EMPTY)
-    trivial_liberties++;
-  else if (board[EAST(pos)] == color) {
-    if (LIBERTIES(EAST(pos)) > 2)
-      return 0;
-    if (LIBERTIES(EAST(pos)) == 2)
-      far_liberties++;
-  }
-  else if (board[EAST(pos)] == other
-          && LIBERTIES(EAST(pos)) == 1 && UNMARKED_STRING(EAST(pos))) {
-    captures++;
-    MARK_STRING(EAST(pos));
-  }
-
-  /* Each captured string is guaranteed to produce at least one
-   * liberty. These are disjoint from both trivial liberties and far
-   * liberties. The two latter may however coincide.
-   */
-  
-  if (trivial_liberties + captures >= 2)
-    return 0;
-
-  if ((far_liberties > 0) + captures >= 2)
-    return 0;
-
-  if (captures == 0 && far_liberties + trivial_liberties <= 1)
-    return 1;
-
-  return -1;
-}
 
 
 /* ================================================================ *
Index: gnugo/interface/play_gtp.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/play_gtp.c,v
retrieving revision 1.94
diff -u -r1.94 play_gtp.c
--- gnugo/interface/play_gtp.c  9 Oct 2002 18:36:23 -0000       1.94
+++ gnugo/interface/play_gtp.c  15 Oct 2002 19:11:43 -0000
@@ -67,6 +67,7 @@
 DECLARE(gtp_echo);
 DECLARE(gtp_echo_err);
 DECLARE(gtp_eval_eye);
+DECLARE(gtp_accuratelib);
 DECLARE(gtp_final_score);
 DECLARE(gtp_final_status);
 DECLARE(gtp_final_status_list);
@@ -165,6 +166,7 @@
   {"echo" ,                   gtp_echo},
   {"echo_err" ,               gtp_echo_err},
   {"estimate_score",          gtp_estimate_score},
+  {"accuratelib",            gtp_accuratelib},
   {"experimental_score",      gtp_experimental_score},
   {"eval_eye",                       gtp_eval_eye},
   {"final_score",             gtp_final_score},
@@ -740,6 +742,34 @@
     return gtp_failure("vertex must not be empty");
 
   liberties = findlib(POS(i, j), MAXLIBS, libs);
+  gtp_start_response(GTP_SUCCESS);
+  gtp_print_vertices2(liberties, libs);
+  return gtp_finish_response();
+}
+
+
+/* Function:  Determine which liberties a stone of given color
+ *           will get if played at given vertex.
+ * Arguments: move (color + vertex)
+ * Fails:     invalid color, invalid vertex, occupied vertex
+ * Returns:   Sorted space separated list of liberties
+ */
+static int
+gtp_accuratelib(char *s)
+{
+  int i, j;
+  int color;
+  int libs[MAXLIBS];
+  int liberties;
+
+  if (!gtp_decode_move(s, &color, &i, &j))
+    return gtp_failure("invalid color or coordinate");
+
+  if (BOARD(i, j) != EMPTY)
+    return gtp_failure("vertex must be empty");
+
+  liberties = accuratelib(POS(i, j), color, MAXLIBS, libs);
+
   gtp_start_response(GTP_SUCCESS);
   gtp_print_vertices2(liberties, libs);
   return gtp_finish_response();
Index: gnugo/patterns/mkpat.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/mkpat.c,v
retrieving revision 1.82
diff -u -r1.82 mkpat.c
--- gnugo/patterns/mkpat.c      30 Sep 2002 21:04:14 -0000      1.82
+++ gnugo/patterns/mkpat.c      15 Oct 2002 19:11:49 -0000
@@ -224,9 +224,9 @@
   {"approx_olib",              1, 0.03,
                "approxlib(%s, color, MAX_LIBERTIES, NULL)"},
   {"xlib",                     1, 0.05,
-       "accurate_approxlib(%s, OTHER_COLOR(color), MAX_LIBERTIES, NULL)"},
+       "accuratelib(%s, OTHER_COLOR(color), MAX_LIBERTIES, NULL)"},
   {"olib",                     1, 0.05,
-       "accurate_approxlib(%s,color, MAX_LIBERTIES, NULL)"},
+       "accuratelib(%s, color, MAX_LIBERTIES, NULL)"},
   {"xcut",                     1, 0.01, "cut_possible(%s,OTHER_COLOR(color))"},
   {"ocut",                     1, 0.05, "cut_possible(%s,color)"},
   {"edge_double_sente",        4, 3.00,





reply via email to

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