gnugo-devel
[Top][All Lists]
Advanced

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

Re: [gnugo-devel] reading patch


From: Gunnar Farneback
Subject: Re: [gnugo-devel] reading patch
Date: Fri, 20 Jun 2003 11:31:11 +0200
User-agent: EMH/1.14.1 SEMI/1.14.3 (Ushinoya) FLIM/1.14.2 (Yagi-Nishiguchi) APEL/10.3 Emacs/20.7 (sparc-sun-solaris2.7) (with unibyte mode)

I wrote:
> I may make some experiments with this. In any case it now wants to
> play E11 instead of A18 at move 130 and all later repetitions of the
> mistake. Locally A16 is better than E11 but compared to A18 it's a
> huge improvement.

The appended patch makes A16 the highest valued local move. Now we
get, at move 130,

1. A16 17.80
2. M5  16.30
3. E11 15.86
(  A18 -1.00)

- new function break_chain4_moves()
- owl moves for non-critical dragons discarded
- do_owl_analyze_semeai() revised
- detect_owl_blunder() also looks for semeai defenses
- estimate_strategical_value() revised

Break_chain4_moves() is only called from defend2() and only when
be_aggressive (see Paul's patch) is set. It can certainly be used in
more contexts but for now I've only enabled this use.

The change in do_owl_analyze_semeai() was needed to solve semeai:54.
The rest of the changes are various tweaks to get proper valuation of
A16 above and to avoid having it discarded as a blunder.

Regression delta:
reading:182     pass (FAIL before patch)
reading:184     pass (FAIL before patch)
connection:94   PASS 1 D9 [1 D9]
strategy:36     PASS R6 [!D18]
nicklas3:401    FAIL F9 [A5]
semeai:54       pass (FAIL before patch)
nngs2:600       FAIL D6 [B5]
nngs4:210       PASS B19 [!S5]

The failures:

nicklas3:401
This is a tidy position with a principally important mistake which
should be looked into. The failure is not really the fault of this
patch though. Before the patch it considered F9 a blunder (correct)
because F8 became owl attackable (wrong). After the patch it
understands that F8 is perfectly safe also after F9 and no longer
discards it as a blunder. The real problem with F9 is that B9 is
brought alive, but this was not understood neither before nor after
the patch.

nngs2:600
Possibly a real failure of the patch. The position is quite complex
and something goes wrong, although I'm not sure what. I'll look
further into it.

The patch gives a very minor slowdown. Should be well worth the
improvements.

Before patch:
Total nodes: 1521433025 2282073 8820795
Total time: 7508.94 (8663.79)

After patch:
Total nodes: 1525806058 2285638 8823933
Total time: 7606.68 (8626.89)

/Gunnar

Index: engine/move_reasons.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/move_reasons.c,v
retrieving revision 1.114
diff -u -r1.114 move_reasons.c
--- engine/move_reasons.c       9 Jun 2003 16:05:32 -0000       1.114
+++ engine/move_reasons.c       20 Jun 2003 08:21:33 -0000
@@ -595,6 +595,14 @@
   return !move[pos].move_safety;
 }
 
+/* Check whether a dragon is non-critical. */
+static int
+concerns_noncritical_dragon(int pos, int what)
+{
+  UNUSED(pos);
+  return dragon[what].status != CRITICAL; 
+}
+
 
 /* (what) points to two worms listed in either_data. Returns true if
  * this is a "attack either" move reason, and one of the worms attackable.
@@ -1882,6 +1890,10 @@
       DEFEND_MOVE, DEFEND_MOVE_GOOD_KO, DEFEND_MOVE_BAD_KO, -1},
     move_is_marked_unsafe, REDUNDANT,
     "  %1m: 0.0 - tactical move vs %1m (unsafe move)\n"},
+  { { OWL_ATTACK_MOVE, OWL_ATTACK_MOVE_GOOD_KO, OWL_ATTACK_MOVE_BAD_KO,
+      OWL_DEFEND_MOVE, OWL_DEFEND_MOVE_GOOD_KO, OWL_DEFEND_MOVE_BAD_KO, -1},
+    concerns_noncritical_dragon, REDUNDANT,
+    "  %1m: 0.0 - owl move vs %1m (non-critical)\n"},
   { { -1 }, NULL, 0, ""}  /* Keep this entry at end of the list. */
 };
 
Index: engine/owl.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.170
diff -u -r1.170 owl.c
--- engine/owl.c        10 Jun 2003 04:52:45 -0000      1.170
+++ engine/owl.c        20 Jun 2003 08:21:36 -0000
@@ -524,9 +524,10 @@
 
     for (sworm = 0; sworm <= s_worms; sworm++) {
       critical_semeai_worms[sworm] = 0;
-      if (board[semeai_worms[sworm]] == other
-         && attack(semeai_worms[sworm], &upos) == WIN) {
-       if (semeai_trust_tactical_attack(semeai_worms[sworm])
+      if (board[semeai_worms[sworm]] == other) {
+       int acode = attack(semeai_worms[sworm], &upos);
+       if (acode == WIN
+           && semeai_trust_tactical_attack(semeai_worms[sworm])
            && important_semeai_worms[sworm]) {
          *resulta = WIN;
          *resultb = WIN;
@@ -536,7 +537,8 @@
          SGFTRACE_SEMEAI(upos, WIN, WIN, "tactical win found");
          READ_RETURN_SEMEAI(read_result, move, upos, WIN, WIN);
        }
-       else if (find_defense(semeai_worms[sworm], NULL)) {
+       else if (acode != 0
+                && find_defense(semeai_worms[sworm], NULL)) {
          critical_semeai_worms[sworm] = 1;
          owl_add_move(moves, upos, 95, "attack semeai worm", 1, 0, NO_MOVE,
                       MAX_SEMEAI_MOVES);
Index: engine/reading.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/reading.c,v
retrieving revision 1.115
diff -u -r1.115 reading.c
--- engine/reading.c    19 Jun 2003 18:57:45 -0000      1.115
+++ engine/reading.c    20 Jun 2003 08:21:39 -0000
@@ -194,6 +194,8 @@
                                       int be_aggressive);
 static void break_chain3_moves(int str, struct reading_moves *moves,
                               int be_aggressive);
+static void break_chain4_moves(int str, struct reading_moves *moves,
+                              int be_aggressive);
 static void superstring_moves(int str, struct reading_moves *moves, 
                              int liberty_cap, int does_attack);
 static void superstring_break_chain_moves(int str, int liberty_cap,
@@ -1450,6 +1452,9 @@
       || (be_aggressive && stackp <= backfill_depth))
     break_chain3_moves(str, &moves, be_aggressive);
 
+  if (be_aggressive && stackp <= backfill_depth)
+    break_chain4_moves(str, &moves, be_aggressive);
+
   /* Only order and test the new set of moves. */
   order_moves(str, &moves, other, read_function_name, saved_num_moves, 
NO_MOVE);
     
@@ -4670,6 +4675,113 @@
   }
 }
 
+/*
+ * (str) points to a group.
+ * If there is a string in the surrounding chain having
+ * exactly four liberties whose attack leads to the rescue of
+ * (str), break_chain4_moves(str, *moves) adds attack moves against
+ * the surrounding string as candidate moves.
+ */
+
+static void
+break_chain4_moves(int str, struct reading_moves *moves, int be_aggressive)
+{
+  int color = board[str];
+  int other = OTHER_COLOR(color);
+  int r;
+  int k;
+  int u = 0, v;
+  int apos;
+  int adj;
+  int adjs[MAXCHAIN];
+  int libs[4];
+  int possible_moves[MAX_MOVES];
+  int mw[BOARDMAX];
+
+  memset(mw, 0, sizeof(mw));
+  
+  adj = chainlinks2(str, adjs, 4);
+  for (r = 0; r < adj; r++) {
+    int lib1 = 0, lib2 = 0, lib3 = 0, lib4 = 0;
+    apos = adjs[r];
+
+    /* We make a list in the (adjs) array of the liberties
+     * of boundary strings having exactly four liberties. We mark
+     * each liberty in the mw array so that we do not list any
+     * more than once.
+     */
+    findlib(apos, 4, libs);
+
+    /* If the 4 liberty chain easily can run away through one of the
+     * liberties, we don't play on any of the other liberties.
+     */
+    lib1 = approxlib(libs[0], other, 5, NULL);
+    lib2 = approxlib(libs[1], other, 5, NULL);
+    if (lib1 >= 5 && lib2 >= 5)
+      continue;
+    lib3 = approxlib(libs[2], other, 5, NULL);
+
+    if ((lib1 >= 5 || lib2 >= 5) && lib3 >= 5)
+      continue;
+    lib4 = approxlib(libs[3], other, 5, NULL);
+
+    if ((lib1 >= 5 || lib2 >= 5 || lib3 >= 5) && lib4 >= 5)
+      continue;
+
+    if (lib1 >= 5 && !mw[libs[0]]) {
+      mw[libs[0]] = 1;
+      possible_moves[u++] = libs[0];
+      continue;
+    }
+    
+    if (lib2 >= 5 && !mw[libs[1]]) {
+      mw[libs[1]] = 1;
+      possible_moves[u++] = libs[1];
+      continue;
+    }
+    
+    if (lib3 >= 5 && !mw[libs[2]]) {
+      mw[libs[2]] = 1;
+      possible_moves[u++] = libs[2];
+      continue;
+    }
+
+    if (lib4 >= 5 && !mw[libs[3]]) {
+      mw[libs[3]] = 1;
+      possible_moves[u++] = libs[3];
+      continue;
+    }
+
+    /* No easy escape, try all liberties. */
+    for (k = 0; k < 4; k++) {
+      if (!mw[libs[k]]) {
+       mw[libs[k]] = 1;
+       possible_moves[u++] = libs[k];
+      }
+    }
+
+    if (stackp <= backfill2_depth
+       || (be_aggressive && stackp <= backfill_depth))
+      defend_secondary_chain_moves(adjs[r], moves, 4);
+  }
+
+  for (v = 0; v < u; v++) {
+    /* We do not wish to consider the move if it can be 
+     * immediately recaptured, unless stackp < backfill2_depth.
+     * Beyond backfill2_depth, the necessary capturing move might not
+     * get generated in follow-up for the attacker.
+     * (This currently only makes a difference at stackp == backfill2_depth.)
+     */
+    int xpos = possible_moves[v];
+    if (stackp <= break_chain_depth
+       || (be_aggressive && stackp <= backfill_depth)
+       || approxlib(xpos, color, 2, NULL) > 1)
+      /* We use a negative initial score here as we prefer to find
+       * direct defense moves.
+       */
+      ADD_CANDIDATE_MOVE(xpos, -2, *moves, "break_chain4");
+  }
+}
 
 /* This function looks for moves attacking those components
  * of the surrounding chain of the superstring (see find_superstring
Index: engine/utils.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/utils.c,v
retrieving revision 1.73
diff -u -r1.73 utils.c
--- engine/utils.c      19 Jun 2003 18:57:45 -0000      1.73
+++ engine/utils.c      20 Jun 2003 08:21:40 -0000
@@ -1006,6 +1006,22 @@
        && DRAGON2(bpos).safety != STRONGLY_ALIVE) {
       int kworm = NO_MOVE;
       int acode = owl_confirm_safety(move, bpos, defense_point, &kworm);
+
+      /* If owl couldn't confirm safety, maybe semeai can. */
+      if (acode != WIN) {
+       int r;
+       for (r = 0; r < DRAGON2(bpos).neighbors; r++) {
+         int neighbor = dragon2[DRAGON2(bpos).adjacent[r]].origin;
+         int resultb;
+         if (board[neighbor] == color)
+           continue;
+         owl_analyze_semeai_after_move(move, color, neighbor, bpos,
+                                       NULL, &resultb, NULL, 1, NULL);
+         if (resultb == 0)
+           acode = WIN;
+       }
+      }
+      
       if (acode == 0) {
        verbose = save_verbose;
        TRACE("Dragon at %1m becomes attackable.\n", bpos);
Index: engine/value_moves.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v
retrieving revision 1.102
diff -u -r1.102 value_moves.c
--- engine/value_moves.c        18 Jun 2003 11:01:24 -0000      1.102
+++ engine/value_moves.c        20 Jun 2003 08:21:43 -0000
@@ -2466,8 +2466,9 @@
      */
     if (attack_move_reason_known(pos, aa)
        || defense_move_reason_known(pos, aa)
-       || owl_attack_move_reason_known(pos, aa)
-       || owl_defense_move_reason_known(pos, aa)
+       || ((owl_attack_move_reason_known(pos, aa)
+            || owl_defense_move_reason_known(pos, aa))
+           && dragon[aa].status == CRITICAL)
        || move_reason_known(pos, SEMEAI_MOVE, aa)) {
       /* But if the strategical value was larger than the territorial
        * value (e.g. because connecting to strong dragon) we award the




reply via email to

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