gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] minor tweaks in tactical reading


From: Paul Pogonyshev
Subject: [gnugo-devel] minor tweaks in tactical reading
Date: 19 Nov 2003 04:04:25 +0000

This patch was aim to reduce the number of reading nodes.  Well, it
does but the drop is very small.  So let's call this patch a cleaning
of `reading.c' :)


(Presumably) full list of changes:

* All move trying loops in defend[1234]() and attack[234]() are
  replaced with macros.  You may argue that i should have used
  functions instead, but i don't see any strong cons for using long
  macros.  If nothing else, they have way fewer arguments and can make
  the function they reside in return without extra code.

  The advantage of having the code in one place is quite obvious:
  easier to make changes and lesser probability of introducing a bug.

* Attack move trying loops are unified (of course, they are the same
  macro's expansions now).  In particular, the loop in attack4() was
  quite different from the others in `move' arguments they supplied to
  do_attack() and do_find_defense().  Tiny decrease in reading nodes.

* Attack move trying loops no longer call do_attack() if they are not
  going to use the result (see the code in ATTACK_TRY_MOVES()).
  Another tiny decrease in reading nodes.

* Closed Inge's FIXME's in do_attack() and do_find_defense() about
  using cached move for ordering when the stored depth is too low.
  The implementation is not ideal: it reuses "killer move" heuristics
  in order_moves().  Yet another decrease in reading nodes.

* Fixed weird policy about `branch_depth' in defend3().  Not sure
  about reading node results, but this was agreed to be logical.
  Unfortunately this change brings regression breakage.

* Replaced

        if (savecode != 0)
          RETURN_RESULT(savecode, savemove, move, "saved move");
 
        RETURN_RESULT(savecode, savemove, move, NULL);

  with just

        RETURN_RESULT(savecode, savemove, move, "saved move");

  where it was still used (RETURN_RESULT() does exactly the same on
  its own).

* Added new debugging flag: DUMP_ALL_RESULTS (required extracting a
  new function do_dump_stack() from dump_stack()).  Detailed comments
  are in the very beginning of the `reading.c' part of the patch.
  This is actually useful, trust me :)

* Added two new macros: DIRECT_NEIGHBORS(pos1, pos2) and
  DIAGONAL_NEIGHBORS(pos1, pos2) with obvious meaning in `board.h'.
  The first is currently only used once in `reading.c', the second --
  twice in `reading.c' and twice in `board.c'.  Potential use in other
  files must be impessive :)

* Reused has_neighbor() once in each of attack[234]().


The results:

* Regression breakage:

        connection:105  FAIL 0 [1 G7]
        strategy:27     FAIL H3 [C3]
        ninestones:150  PASS C5 [C5|D5]

  All changes are due to the tweak in defend3().  I verified only the
  first in details -- it's completely accidential.  The two others are
  probably too.

* Node counters:

  before:  1362600713 2450573 8827896
  after:   1355316096 2444269 8826705
                -0.5%   -0.0%   -0.0%

* The reading functions are much shorter now: `reading.c' has shrunk
  by more than 200 lines.


Paul



Index: engine/board.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/board.c,v
retrieving revision 1.89
diff -u -p -r1.89 board.c
--- engine/board.c      13 Nov 2003 22:48:40 -0000      1.89
+++ engine/board.c      19 Nov 2003 01:56:03 -0000
@@ -740,7 +740,6 @@ undo_trymove()
 
 
 
-
 /*
  * dump_stack() for use under gdb prints the move stack. 
  */
@@ -748,11 +747,6 @@ undo_trymove()
 void
 dump_stack(void)
 {
-  int n;
-
-  for (n = 0; n < stackp; n++)
-    gprintf("%o%s:%1m ", move_color[n] == BLACK ? "B" : "W", stack[n]);
-  
 #if !TRACE_READ_RESULTS
   if (count_variations)
     gprintf("%o (variation %d)", count_variations-1);
@@ -764,6 +758,15 @@ dump_stack(void)
   fflush(stderr);
 }
 
+/* Bare bones of dump_stack(). */
+void
+do_dump_stack(void)
+{
+  int n;
+
+  for (n = 0; n < stackp; n++)
+    gprintf("%o%s:%1m ", move_color[n] == BLACK ? "B" : "W", stack[n]);
+}
 
 /* ================================================================ */
 /*                     Permanent moves                              */
@@ -1219,18 +1222,14 @@ komaster_trymove(int pos, int color, con
       return 0;
 
     /* If we are komaster, we may only do nested captures. */
-    if (komaster == color
-       && !(kpos == SW(kom_pos) || kpos == NW(kom_pos)
-            || kpos == NE(kom_pos) || kpos == SE(kom_pos)))
+    if (komaster == color && !DIAGONAL_NEIGHBORS(kpos, kom_pos))
       return 0;
 
     /* If komaster is WEAK_KO, we may only do nested ko capture or
      * conditional ko capture.
      */
     if (komaster == WEAK_KO) {
-      if (pos != board_ko_pos
-         && !(kpos == SW(kom_pos) || kpos == NW(kom_pos)
-              || kpos == NE(kom_pos) || kpos == SE(kom_pos)))
+      if (pos != board_ko_pos && !DIAGONAL_NEIGHBORS(kpos, kom_pos))
        return 0;
     }
   }
Index: engine/board.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/board.h,v
retrieving revision 1.6
diff -u -p -r1.6 board.h
--- engine/board.h      13 Nov 2003 22:48:40 -0000      1.6
+++ engine/board.h      19 Nov 2003 01:56:03 -0000
@@ -141,6 +141,18 @@ typedef unsigned char Intersection;
 #define NN(pos)       ((pos) - 2 * NS)
 #define EE(pos)       ((pos) + 2)
 
+#define DIRECT_NEIGHBORS(pos1, pos2)           \
+  ((pos1) == SOUTH(pos2)                       \
+   || (pos1) == WEST(pos2)                     \
+   || (pos1) == NORTH(pos2)                    \
+   || (pos1) == EAST(pos2))
+
+#define DIAGONAL_NEIGHBORS(pos1, pos2)         \
+  ((pos1) == SW(pos2)                          \
+   || (pos1) == NW(pos2)                       \
+   || (pos1) == NE(pos2)                       \
+   || (pos1) == SE(pos2))
+
 #define BOARD(i, j)   board[POS(i, j)]
 
 
@@ -241,6 +253,7 @@ int komaster_trymove(int pos, int color,
 int move_in_stack(int pos, int cutoff);
 void get_move_from_stack(int k, int *move, int *color);
 void dump_stack(void);
+void do_dump_stack(void);
 
 void reset_trymove_counter(void);
 int get_trymove_counter(void);
Index: engine/reading.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/reading.c,v
retrieving revision 1.127
diff -u -p -r1.127 reading.c
--- engine/reading.c    18 Nov 2003 22:41:36 -0000      1.127
+++ engine/reading.c    19 Nov 2003 01:56:17 -0000
@@ -32,6 +32,24 @@
 #include "patterns.h"
 #include "gg_utils.h"
 
+/* If defined, attack() and find_defense() write all results to
+ * stderr.  Use this to if you have deviations in results, but cannot
+ * find where they come from.
+ *
+ * Redirect results to a file.  Take dumps of two versions and
+ * (assuming GNU tools) do `sort -t= -s' on both.  Then join the
+ * sorted dumps:
+ *
+ *   join -t= sorted-first-dump sorted-second-dump \
+ *   | sed -e "s/^[^=]\+=\([^=]\+\)=\1$//" | tr -s "\n" | tr = "\t"
+ *
+ * to get a nice list of deviations.  This is only meaningful if you
+ * dump results of a single test (or at least tests originating at a
+ * same position).
+ */
+#define DUMP_ALL_RESULTS       0
+
+
 #if EXPERIMENTAL_READING
 
 /* When to use pattern-base reading */
@@ -122,6 +140,97 @@ static int do_attack_pat(int str, int *m
   } while (0)
 
 
+/* Play a collected batch of moves and see if any of them works.  This
+ * is a defense version.
+ */
+#define DEFEND_TRY_MOVES(no_deep_branching, attack_hint)               \
+  do {                                                                 \
+    int k;                                                             \
+                                                                       \
+    for (k = moves.num_tried; k < moves.num; k++) {                    \
+      int new_komaster;                                                        
\
+      int new_kom_pos;                                                 \
+      int ko_move;                                                     \
+      int dpos = moves.pos[k];                                         \
+                                                                       \
+      if (komaster_trymove(dpos, color, moves.message[k], str,         \
+                          komaster, kom_pos,                           \
+                          &new_komaster, &new_kom_pos, &ko_move,       \
+                          stackp <= ko_depth && savecode == 0)) {      \
+       int acode = do_attack(str, (attack_hint),                       \
+                             new_komaster, new_kom_pos);               \
+       popgo();                                                        \
+                                                                       \
+       if (!ko_move) {                                                 \
+         CHECK_RESULT(savecode, savemove, acode, dpos, move,           \
+                      "defense effective");                            \
+       }                                                               \
+       else {                                                          \
+         if (acode != WIN) {                                           \
+           savemove = dpos;                                            \
+           savecode = KO_B;                                            \
+         }                                                             \
+       }                                                               \
+      }                                                                        
\
+                                                                       \
+      if ((no_deep_branching) && stackp >= branch_depth)               \
+       RETURN_RESULT(savecode, savemove, move, "branching limit");     \
+    }                                                                  \
+                                                                       \
+    moves.num_tried = moves.num;                                       \
+  } while (0)
+
+
+/* Attack version of the macro above.  This one is a bit more
+ * complicated, because when defender fails to defend, attacker has to
+ * prove that he can capture the string before claiming victory.
+ */
+#define ATTACK_TRY_MOVES(no_deep_branching, defense_hint)              \
+  do {                                                                 \
+    int k;                                                             \
+                                                                       \
+    for (k = moves.num_tried; k < moves.num; k++) {                    \
+      int new_komaster;                                                        
\
+      int new_kom_pos;                                                 \
+      int ko_move;                                                     \
+      int apos = moves.pos[k];                                         \
+                                                                       \
+      if (komaster_trymove(apos, other, moves.message[k], str,         \
+                          komaster, kom_pos,                           \
+                          &new_komaster, &new_kom_pos, &ko_move,       \
+                          stackp <= ko_depth && savecode == 0)) {      \
+       int dcode = do_find_defense(str, (defense_hint),                \
+                                   new_komaster, new_kom_pos);         \
+                                                                       \
+       if (REVERSE_RESULT(dcode) > savecode                            \
+           && do_attack(str, NULL, new_komaster, new_kom_pos)) {       \
+         if (!ko_move) {                                               \
+           if (dcode == 0) {                                           \
+             popgo();                                                  \
+             RETURN_RESULT(WIN, apos, move, "attack effective");       \
+           }                                                           \
+                                                                       \
+           savemove = apos;                                            \
+           savecode = REVERSE_RESULT(dcode);                           \
+         }                                                             \
+         else {                                                        \
+           savemove = apos;                                            \
+           savecode = KO_B;                                            \
+         }                                                             \
+       }                                                               \
+                                                                       \
+       popgo();                                                        \
+      }                                                                        
\
+                                                                       \
+      if ((no_deep_branching) && stackp >= branch_depth)               \
+       RETURN_RESULT(savecode, savemove, move, "branching limit");     \
+    }                                                                  \
+                                                                       \
+    moves.num_tried = moves.num;                                       \
+  } while (0)
+
+
+
 struct reading_moves
 {
   int pos[MAX_MOVES];
@@ -289,6 +398,12 @@ attack(int str, int *move)
   
   if (move)
     *move = the_move;
+
+#if DUMP_ALL_RESULTS
+  do_dump_stack();
+  gprintf("%oattack %1m=%d %1m\n", str, result, the_move);
+#endif
+
   return result;
 }
 
@@ -353,6 +468,12 @@ find_defense(int str, int *move)
   
   if (move)
     *move = the_move;
+
+#if DUMP_ALL_RESULTS
+  do_dump_stack();
+  gprintf("%odefend %1m=%d %1m\n", str, result, the_move);
+#endif
+
   return result;
 }
 
@@ -1062,9 +1183,6 @@ do_find_defense(int str, int *move, int 
 #endif
   
   SETUP_TRACE_INFO("find_defense", str);
-  
-  if (move)
-    xpos = *move;
 
   /* We first check if the number of liberties is larger than four. In
    * that case we don't cache the result and to avoid needlessly
@@ -1084,13 +1202,24 @@ do_find_defense(int str, int *move, int 
     return WIN;
   }
 
+  /* Set "killer move" up.  This move (if set) was successful in
+   * another variation, so it is reasonable to try it now.  However,
+   * we only do this if the string has at least 3 liberties -
+   * otherwise the situation changes too much from variation to
+   * variation.
+   */
+  if (liberties > 2 && move)
+    xpos = *move;
+
 #if USE_HASHTABLE_NG
 
   if ((stackp <= depth) && (hashflags & HASH_FIND_DEFENSE)
       && tt_get(&ttable, komaster, kom_pos, FIND_DEFENSE, str, 
                depth - stackp,
                &retval, &xpos) == 2) {
-    /* FIXME: Use move for move ordering if tt_get() returned 1 */
+    /* Note that if return value is 1 (too small depth), the move will
+     * still be used for move ordering.
+     */
     SGFTRACE(xpos, retval, "cached");
     if (move)
       *move = xpos;
@@ -1150,24 +1279,28 @@ do_find_defense(int str, int *move, int 
 }
 
 
-/* Called by the defendN functions.  Don't think too much if there's
- * an easy way to get enough liberties.
+/* Called by the defendN functions.
+ * Don't think too much if there's an easy way to get enough liberties
  */
+
 static int
 fast_defense(int str, int liberties, int *libs, int *move)
 {
   int color = board[str];
   int k;
-  int goal_liberties = (stackp < fourlib_depth ? 5 : 4);
+  int newlibs;
 
   ASSERT1(libs != NULL, str);
   ASSERT1(move != NULL, str);
 
   for (k = 0; k < liberties; k++) {
-    /* accuratelib() seems to be more efficient than fastlib() here,
-     * probably because it catches more cases.
+    /* accuratelib() to be seems more effective than fastlib() here.
+     * (probably because it catches more cases). And since 5 liberties
+     * is enough for our purpose, no need to ask for more.
      */
-    if (accuratelib(libs[k], color, goal_liberties, NULL) >= goal_liberties) {
+    newlibs = accuratelib(libs[k], color, 5, NULL);
+    if (newlibs > 4
+       || (newlibs == 4 && stackp > fourlib_depth)) {
       *move = libs[k];
       return 1;
     }
@@ -1233,32 +1366,8 @@ defend1(int str, int *move, int komaster
   break_chain_moves(str, &moves);
   set_up_snapback_moves(str, lib, &moves);
 
-  order_moves(str, &moves, color, read_function_name, NO_MOVE);
-
-  for (k = 0; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-
-    xpos = moves.pos[k];
-    if (komaster_trymove(xpos, color, moves.message[k], str, komaster, kom_pos,
-                        &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, NULL, new_komaster, new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - A");
-      }
-      else {
-       if (do_attack(str, NULL, new_komaster, new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
+  order_moves(str, &moves, color, read_function_name, *move);
+  DEFEND_TRY_MOVES(0, NULL);
 
   /* If the string is a single stone and a capture would give a ko,
    * try to defend it with ko by backfilling.
@@ -1364,37 +1473,8 @@ defend2(int str, int *move, int komaster
   if (stackp <= backfill_depth)
     special_rescue2_moves(str, libs, &moves);
 
-  order_moves(str, &moves, color, read_function_name, NO_MOVE);
-
-  for (k = 0; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-
-    xpos = moves.pos[k];
-    
-    if (komaster_trymove(xpos, color, moves.message[k], str,
-                        komaster, kom_pos, &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, &suggest_move, new_komaster,
-           new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - A");
-      }
-      else {
-       if (do_attack(str, &suggest_move, new_komaster,
-             new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
-
-  moves.num_tried = moves.num;
+  order_moves(str, &moves, color, read_function_name, *move);
+  DEFEND_TRY_MOVES(0, &suggest_move);
 
   /* Look for backfilling moves. */
   for (k = 0; k < liberties; k++) {
@@ -1425,35 +1505,8 @@ defend2(int str, int *move, int komaster
   }
 
   /* Only order and test the new set of moves. */
-  order_moves(str, &moves, other, read_function_name, NO_MOVE);
-
-  for (k = moves.num_tried; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-    xpos = moves.pos[k];
-    
-    if (komaster_trymove(xpos, color, moves.message[k], str,
-                        komaster, kom_pos, &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, &suggest_move, new_komaster, new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - B");
-      }
-      else {
-       if (do_attack(str, &suggest_move, new_komaster,
-             new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
-
-  moves.num_tried = moves.num;
+  order_moves(str, &moves, other, read_function_name, *move);
+  DEFEND_TRY_MOVES(0, &suggest_move);
 
   /* If we haven't found any useful moves in first batches, be more
    * aggressive in break_chain[23]_moves().
@@ -1482,38 +1535,10 @@ defend2(int str, int *move, int komaster
     break_chain4_moves(str, &moves, be_aggressive);
 
   /* Only order and test the new set of moves. */
-  order_moves(str, &moves, other, read_function_name, NO_MOVE);
-
-  for (k = moves.num_tried; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-    xpos = moves.pos[k];
-    
-    if (komaster_trymove(xpos, color, moves.message[k], str,
-                        komaster, kom_pos, &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, &suggest_move, new_komaster, new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - A");
-      }
-      else {
-       if (do_attack(str, &suggest_move, new_komaster,
-           new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
-
-  if (savecode != 0)
-    RETURN_RESULT(savecode, savemove, move, "saved move");
+  order_moves(str, &moves, other, read_function_name, *move);
+  DEFEND_TRY_MOVES(0, &suggest_move);
 
-  RETURN_RESULT(savecode, savemove, move, NULL);
+  RETURN_RESULT(savecode, savemove, move, "saved move");
 }
 
 
@@ -1573,38 +1598,7 @@ defend3(int str, int *move, int komaster
     hane_rescue_moves(str, libs, &moves);
 
   order_moves(str, &moves, color, read_function_name, *move);
-
-  for (k = 0; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-
-    if (stackp >= branch_depth && k > 0)
-      break;
-    
-    xpos = moves.pos[k];
-    
-    if (komaster_trymove(xpos, color, moves.message[k], str, komaster, kom_pos,
-                        &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, &suggest_move, new_komaster, new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - A");
-      }
-      else {
-       if (do_attack(str, &suggest_move, new_komaster,
-             new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
-
-  moves.num_tried = moves.num;
+  DEFEND_TRY_MOVES(1, &suggest_move);
 
   /* This looks a little too expensive. */
 #if 0
@@ -1691,33 +1685,7 @@ defend3(int str, int *move, int komaster
 
   /* Only order and test the new set of moves. */
   order_moves(str, &moves, other, read_function_name, *move);
-
-  for (k = moves.num_tried; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-    xpos = moves.pos[k];
-    
-    if (komaster_trymove(xpos, color, moves.message[k], str,
-                        komaster, kom_pos, &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, &suggest_move, new_komaster, new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - A");
-      }
-      else {
-       if (do_attack(str, &suggest_move, new_komaster, new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
-
-  moves.num_tried = moves.num;
+  DEFEND_TRY_MOVES(1, &suggest_move);
 
   /* If nothing else works, we try playing a liberty of the
    * super_string.
@@ -1730,36 +1698,9 @@ defend3(int str, int *move, int komaster
 
   /* Only order and test the new set of moves. */
   order_moves(str, &moves, other, read_function_name, *move);
+  DEFEND_TRY_MOVES(1, &suggest_move);
 
-  for (k = moves.num_tried; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-    xpos = moves.pos[k];
-    
-    if (komaster_trymove(xpos, color, moves.message[k], str,
-                        komaster, kom_pos, &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, &suggest_move, new_komaster, new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - A");
-      }
-      else {
-       if (do_attack(str, &suggest_move, new_komaster, new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
-
-  if (savecode != 0)
-    RETURN_RESULT(savecode, savemove, move, "saved move");
-
-  RETURN_RESULT(0, 0, move, NULL);
+  RETURN_RESULT(savecode, savemove, move, "saved move");
 }
 
 
@@ -1781,7 +1722,7 @@ defend4(int str, int *move, int komaster
   int savecode = 0;
   int k;
   int suggest_move = NO_MOVE;
-  
+
   SETUP_TRACE_INFO("defend4", str);
   reading_node_counter++;
 
@@ -1822,40 +1763,9 @@ defend4(int str, int *move, int komaster
   }
 
   order_moves(str, &moves, color, read_function_name, *move);
+  DEFEND_TRY_MOVES(1, &suggest_move);
 
-  for (k = 0; k < moves.num; k++) {
-    int new_komaster;
-    int new_kom_pos;
-    int ko_move;
-
-    if (stackp >= branch_depth && k > 0)
-      break;
-    
-    xpos = moves.pos[k];
-    
-    if (komaster_trymove(xpos, color, moves.message[k], str, komaster, kom_pos,
-                        &new_komaster, &new_kom_pos,
-                        &ko_move, stackp <= ko_depth && savecode == 0)) {
-      if (!ko_move) {
-       int acode = do_attack(str, &suggest_move, new_komaster, new_kom_pos);
-       popgo();
-       CHECK_RESULT(savecode, savemove, acode, xpos, move,
-                    "defense effective - A");
-      }
-      else {
-       if (do_attack(str, &suggest_move, new_komaster, new_kom_pos) != WIN) {
-         savemove = xpos;
-         savecode = KO_B;
-       }
-       popgo();
-      }
-    }
-  }
-
-  if (savecode != 0)
-    RETURN_RESULT(savecode, savemove, move, "saved move");
-
-  RETURN_RESULT(0, 0, move, NULL);
+  RETURN_RESULT(savecode, savemove, move, "saved move");
 }
 
 
@@ -2971,7 +2881,7 @@ do_attack(int str, int *move, int komast
 {
   int color = board[str];
   int xpos = NO_MOVE;
-  int libs;
+  int liberties;
   int result = 0;
 #if !USE_HASHTABLE_NG
   int found_read_result;
@@ -2984,17 +2894,14 @@ do_attack(int str, int *move, int komast
 
   ASSERT1(color != 0, str);
 
-  if (move)
-    xpos = *move;
-
   if (color == 0)      /* if assertions are turned off, silently fails */
     return 0;
 
   str = find_origin(str);
-  libs = countlib(str);
+  liberties = countlib(str);
 
-  if (libs > 4
-      || (libs == 4 && stackp > fourlib_depth)) {
+  if (liberties > 4
+      || (liberties == 4 && stackp > fourlib_depth)) {
     /* No need to cache the result in these cases. */
     if (sgf_dumptree) {
       char buf[100];
@@ -3005,13 +2912,23 @@ do_attack(int str, int *move, int komast
     return 0;
   }
 
+  /* Set "killer move" up.  This move (if set) was successful in
+   * another variation, so it is reasonable to try it now.  However,
+   * we only do this if the string has 4 liberties - otherwise the
+   * situation changes too much from variation to variation.
+   */
+  if (liberties > 3 && move)
+    xpos = *move;
+
 #if USE_HASHTABLE_NG
 
+  /* Note that if return value is 1 (too small depth), the move will
+   * still be used for move ordering.
+   */
   if ((stackp <= depth) && (hashflags & HASH_ATTACK)
       && tt_get(&ttable, komaster, kom_pos, ATTACK, str, 
                depth - stackp,
                &retval, &xpos) == 2) {
-    /* FIXME: Use move for move ordering if tt_get() returned 1 */
     SGFTRACE(xpos, retval, "cached");
     if (move)
       *move = xpos;
@@ -3040,24 +2957,24 @@ do_attack(int str, int *move, int komast
 #if EXPERIMENTAL_READING
   if (attack_by_pattern) {
     result = do_attack_pat(str, &xpos, komaster, kom_pos);
-    /* Set libs to 0 to pass over the non-pattern code below. */
-    libs = 0;
+    /* Set liberties to 0 to pass over the non-pattern code below. */
+    liberties = 0;
   }
 #endif
 
   /* Treat the attack differently depending on how many liberties the 
      string at (str) has. */
-  if (libs == 1)
+  if (liberties == 1)
     result = attack1(str, &xpos, komaster, kom_pos);
-  else if (libs == 2) {
+  else if (liberties == 2) {
     if (stackp > depth + 10)
       result = simple_ladder_attack(str, &xpos, komaster, kom_pos);
     else
       result = attack2(str, &xpos, komaster, kom_pos);
   }
-  else if (libs == 3)
+  else if (liberties == 3)
     result = attack3(str, &xpos, komaster, kom_pos);
-  else if (libs == 4)
+  else if (liberties == 4)
     result = attack4(str, &xpos, komaster, kom_pos);
 
 
@@ -3306,7 +3223,6 @@ attack2(int str, int *move, int komaster
   int adj, adjs[MAXCHAIN];
   int savemove = 0;
   int savecode = 0;
-  int dcode;
   int k;
   int atari_possible = 0;
   struct reading_moves moves;
@@ -3360,27 +3276,21 @@ attack2(int str, int *move, int komaster
       liberties = findlib(str, 2, libs);
       ASSERT1(liberties == 2, str);
 
-      if (libs[0] == SOUTH(libs[1])
-          || libs[0] == WEST(libs[1])
-          || libs[0] == NORTH(libs[1])
-          || libs[0] == EAST(libs[1]))
+      if (DIRECT_NEIGHBORS(libs[0], libs[1]))
         adjacent_liberties = 1;
 
       for (k = 0; k < 2; k++) {
         int apos = libs[k];
         if (!is_self_atari(apos, other))
           atari_possible = 1;
-        /* we only want to consider the move at (apos) if:
+       /* We only want to consider the move at (apos) if:
          * stackp <= backfill_depth
          * -or-  stackp <= depth and it is an isolated stone
          * -or-  it is not in immediate atari
          */
         if (stackp <= backfill_depth
            || ((stackp <= depth || adjacent_liberties)
-               && board[SOUTH(apos)] != other
-               && board[WEST(apos)] != other
-               && board[NORTH(apos)] != other
-               && board[EAST(apos)] != other)
+               && !has_neighbor(apos, other))
            || !is_self_atari(apos, other))
           ADD_CANDIDATE_MOVE(apos, 0, moves, "liberty");
 
@@ -3461,47 +3371,8 @@ attack2(int str, int *move, int komaster
       abort();
     } /* switch (pass) */
 
-    order_moves(str, &moves, other, read_function_name, NO_MOVE);
-
-    for (k = moves.num_tried; k < moves.num; k++) {
-      int new_komaster;
-      int new_kom_pos;
-      int ko_move;
-
-      int apos = moves.pos[k];
-      if (komaster_trymove(apos, other, moves.message[k], str,
-                          komaster, kom_pos, &new_komaster, &new_kom_pos,
-                          &ko_move, stackp <= ko_depth && savecode == 0)) {
-       if (!ko_move) {
-         dcode = do_find_defense(str, &suggest_move, new_komaster,
-                                 new_kom_pos);
-         if (dcode != WIN
-             && do_attack(str, NULL, new_komaster, new_kom_pos)) {
-           popgo();
-           CHECK_RESULT(savecode, savemove, dcode, apos, move,
-                        "attack effective");
-         }
-         else
-           popgo();
-       }
-       else {
-         if (do_find_defense(str, &suggest_move, new_komaster,
-                             new_kom_pos) != WIN
-             && do_attack(str, NULL, new_komaster, new_kom_pos) != 0) {
-           savemove = apos;
-           savecode = KO_B;
-         }
-         popgo();
-       }
-      }
-    }
-
-    moves.num_tried = moves.num;
-  }
-
-
-  if (savecode == 0) {
-    RETURN_RESULT(0, 0, move, NULL);
+    order_moves(str, &moves, other, read_function_name, *move);
+    ATTACK_TRY_MOVES(0, &suggest_move);
   }
 
   RETURN_RESULT(savecode, savemove, move, "saved move");
@@ -3528,18 +3399,16 @@ attack3(int str, int *move, int komaster
   int color = board[str];
   int other = OTHER_COLOR(color);
   int adj, adjs[MAXCHAIN];
-  int xpos = NO_MOVE;
   int liberties;
   int libs[3];
   int r;
-  int dcode = 0;
   int k;
   struct reading_moves moves;
   int savemove = 0;
   int savecode = 0;
   int pass;
   int suggest_move = NO_MOVE;
-  
+
   SETUP_TRACE_INFO("attack3", str);
   reading_node_counter++;
   moves.num = 0;
@@ -3575,17 +3444,14 @@ attack3(int str, int *move, int komaster
         int libs2[2];
 #endif
         int apos = libs[k];
-        /* we only want to consider the move at (apos) if:
+       /* We only want to consider the move at (apos) if:
          * stackp <= backfill_depth
          * -or-  stackp <= depth and it is an isolated stone
          * -or-  it is not in immediate atari
          */
         if (stackp <= backfill_depth
            || (stackp <= depth
-               && board[SOUTH(apos)] != other
-               && board[WEST(apos)] != other
-               && board[NORTH(apos)] != other
-               && board[EAST(apos)] != other)
+               && !has_neighbor(apos, other))
            || !is_self_atari(apos, other))
           ADD_CANDIDATE_MOVE(apos, 0, moves, "liberty");
 
@@ -3647,46 +3513,8 @@ attack3(int str, int *move, int komaster
       abort();
     }
 
-    order_moves(str, &moves, other, read_function_name, NO_MOVE);
-
-    /* Try the moves collected so far. */
-    for (k = moves.num_tried; k < moves.num; k++) {
-      int new_komaster;
-      int new_kom_pos;
-      int ko_move;
-
-      if (stackp >= branch_depth && k > 0)
-       break;
-      xpos = moves.pos[k];
-      if (komaster_trymove(xpos, other, moves.message[k], str,
-                          komaster, kom_pos, &new_komaster,
-                          &new_kom_pos, &ko_move,
-                          stackp <= ko_depth && savecode == 0)) {
-       if (!ko_move) {
-         dcode = do_find_defense(str, &suggest_move, new_komaster,
-                                 new_kom_pos);
-         if (dcode != WIN
-             && do_attack(str, NULL, new_komaster, new_kom_pos)) {
-           popgo();
-           CHECK_RESULT(savecode, savemove, dcode, xpos, move,
-                        "attack effective");
-         }
-         else
-           popgo();
-       }
-       else {
-         if (do_find_defense(str, &suggest_move, new_komaster,
-                             new_kom_pos) != WIN
-             && do_attack(str, NULL, new_komaster, new_kom_pos) != 0) {
-           savemove = xpos;
-           savecode = KO_B;
-         }
-         popgo();
-       }
-      }
-    }
-
-    moves.num_tried = moves.num;
+    order_moves(str, &moves, other, read_function_name, *move);
+    ATTACK_TRY_MOVES(1, &suggest_move);
   } /* for (pass... */
 
   RETURN_RESULT(savecode, savemove, move, "saved move");
@@ -3700,13 +3528,11 @@ attack4(int str, int *move, int komaster
 {
   int color = board[str];
   int other = OTHER_COLOR(color);
-  int xpos = NO_MOVE;
   int r;
   int k;
   int liberties;
   int libs[4];
   int adj, adjs[MAXCHAIN];
-  int dcode = 0;
   struct reading_moves moves;
   int savemove = 0;
   int savecode = 0;
@@ -3751,18 +3577,15 @@ attack4(int str, int *move, int komaster
 
       for (k = 0; k < 4; k++) {
         int apos = libs[k];
-        /* we only want to consider the move at (apos) if:
+       /* We only want to consider the move at (apos) if:
          * stackp <= backfill_depth
          * -or-  stackp <= depth and it is an isolated stone
          * -or-  it is not in immediate atari
          */
         if (stackp <= backfill_depth
            || (stackp <= depth
-               && board[SOUTH(apos)] != other
-               && board[WEST(apos)] != other
-               && board[NORTH(apos)] != other
-               && board[EAST(apos)] != other)
-            || !is_self_atari(apos, other))
+               && !has_neighbor(apos, other))
+           || !is_self_atari(apos, other))
           ADD_CANDIDATE_MOVE(apos, 0, moves, "liberty");
 
         edge_closing_backfill_moves(str, apos, &moves);
@@ -3785,46 +3608,7 @@ attack4(int str, int *move, int komaster
     }
 
     order_moves(str, &moves, other, read_function_name, *move);
-
-    /* Try the moves collected so far. */
-    for (k = moves.num_tried; k < moves.num; k++) {
-      int new_komaster;
-      int new_kom_pos;
-      int ko_move;
-
-      if (stackp >= branch_depth && k > 0)
-       break;
-      
-      xpos = moves.pos[k];
-      if (komaster_trymove(xpos, other, moves.message[k], str,
-                          komaster, kom_pos, &new_komaster,
-                          &new_kom_pos, &ko_move,
-                          stackp <= ko_depth && savecode == 0)) {
-       if (!ko_move) {
-         dcode = do_find_defense(str, NULL, new_komaster, new_kom_pos);
-         if (dcode != WIN
-             && do_attack(str, NULL, new_komaster, new_kom_pos)) {
-           popgo();
-           CHECK_RESULT(savecode, savemove, dcode, xpos, move,
-                        "attack effective");
-         }
-         else
-           popgo();
-       }
-       else {
-         if (do_find_defense(str, &suggest_move, new_komaster,
-                             new_kom_pos) != WIN
-             && do_attack(str, &suggest_move, new_komaster,
-                          new_kom_pos) != 0) {
-           savemove = xpos;
-           savecode = KO_B;
-         }
-         popgo();
-       }
-      }
-    } /* for (k = ... */
-
-    moves.num_tried = moves.num;
+    ATTACK_TRY_MOVES(1, &suggest_move);
   } /* for (pass = ... */
 
   RETURN_RESULT(savecode, savemove, move, "saved move");
@@ -3872,10 +3656,7 @@ find_cap_moves(int str, struct reading_m
       blib = libs[j];
 
       /* Check if the two liberties are located like the figure above. */
-      if (alib != SW(blib)
-          && alib != NW(blib)
-          && alib != NE(blib)
-          && alib != SE(blib))
+      if (!DIAGONAL_NEIGHBORS(alib, blib))
         continue;
 
       ai = I(alib);
@@ -4516,10 +4297,7 @@ do_find_break_chain2_efficient_moves(int
    * Update: This was too crude. Also require that the X stone is on
    * the second line and that the proposed move is not a self-atari.
    */
-  if (libs[0] != SW(libs[1])
-      && libs[0] != NW(libs[1])
-      && libs[0] != NE(libs[1])
-      && libs[0] != SE(libs[1]))
+  if (!DIAGONAL_NEIGHBORS(libs[0], libs[1]))
     return;
 
   /* Since we know that the two liberties are diagonal, the following





reply via email to

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