gnugo-devel
[Top][All Lists]
Advanced

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

Re: [gnugo-devel] bug report


From: Paul Pogonyshev
Subject: Re: [gnugo-devel] bug report
Date: Thu, 8 Jan 2004 00:32:19 +0000
User-agent: KMail/1.5.94

I wrote:
> > I was playing a bot on KGS which claimed to be running
> > GNU Go v3.5.2, when in the endgame it made a fairly significant blunder.
> > On move 234 in the attached SGF, it prefers to save 3 stones, preventing
> > a 6 point loss, which results in a seki. If the 3 stones had been
> > sacrificed, there would have been no seki: it would have captured 9
> > stones for a local gain of 18 points, or a net gain of 12 points
> > including the sacrifice.
>
> GNU Go is not very good with sekis.  Recently, some decent improvements
> have been made, but it this position it doesn't even see A19/B17.  I'll
> try to see if i can fix this particular issue.

Here is a patch.  Unfortunately, it fails two existing tests (very similar
to each others), but i consider the fails acceptable, because tests used to
pass for a wrong reason.

Here is the full list of changes (some were proposed by Gunnar):

- new function compute_dragon_genus(), can optionally ignore one selected eye
- find_moves_to_make_seki() disregards the eye containing the string in
  question when calculating opponent's dragon genus
- find_moves_to_make_seki() tries all liberties of the string to prevent seki
- worms of a dragon, which is found to be non-dead by semeai code, are always
  considered essential
- find_more_attack_and_defense_moves() and make_worms() no longer claim a new
  attack if a move makes a worm non-attackable (by pushing it into seki)

Regression breakage is

seki:206        FAIL C9 [A1]
seki:811        FAIL C9 [A1]
seki:2010       pass            (failed by CVS; new test by Dan Rosen)

The two failed tests used to pass for a wrong reason: GNU Go saw false attacks
on certain worms and, hence, strategic effects.  It should have seen owl
defenses instead.  These should be fixed by a separate patch.

I regressed the patch without Gunnar's latest patch, but then rediffed mine on
top of Gunnar's.

Paul



Index: engine/dragon.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v
retrieving revision 1.128
diff -u -p -r1.128 dragon.c
--- engine/dragon.c     7 Jan 2004 10:00:19 -0000       1.128
+++ engine/dragon.c     7 Jan 2004 22:13:21 -0000
@@ -100,7 +100,6 @@ void 
 make_dragons(int color, int stop_before_owl)
 {
   int str;
-  int dr;
   int d;
 
   start_timer(2);
@@ -210,41 +209,54 @@ make_dragons(int color, int stop_before_
   analyze_false_eye_territory();
 
   /* Now we compute the genus. */
-  for (str = BOARDMIN; str < BOARDMAX; str++) {
-    if (!ON_BOARD(str))
-      continue;
-    
-    if (black_eye[str].color == BLACK
-       && black_eye[str].origin == str
-       && find_eye_dragons(black_eye[str].origin, black_eye,
-                           BLACK, &dr, 1) == 1) {
-      
-      ASSERT1(board[dr] == BLACK, dr);
-      TRACE("eye at %1m found for dragon at %1m--augmenting genus\n",
-           str, dr);
-      if (eye_move_urgency(&black_eye[str].value)
-         > eye_move_urgency(&DRAGON2(dr).genus))
-       DRAGON2(dr).heye = black_eye[str].defense_point;
-      add_eyevalues(&DRAGON2(dr).genus, &black_eye[str].value,
-                   &DRAGON2(dr).genus);
-    }
-    
-    if (white_eye[str].color == WHITE
-       && white_eye[str].origin == str
-       && find_eye_dragons(white_eye[str].origin, white_eye,
-                           WHITE, &dr, 1) == 1) {
-      
-      ASSERT1(board[dr] == WHITE, dr);
-      TRACE("eye at %1m found for dragon at %1m--augmenting genus\n",
-           str, dr);
-      if (eye_move_urgency(&white_eye[str].value)
-         > eye_move_urgency(&DRAGON2(dr).genus))
-       DRAGON2(dr).heye = white_eye[str].defense_point;
-      add_eyevalues(&DRAGON2(dr).genus, &white_eye[str].value,
-                   &DRAGON2(dr).genus);
+#if 1
+
+  for (d = 0; d < number_of_dragons; d++)
+    compute_dragon_genus(dragon2[d].origin, &dragon2[d].genus, NO_MOVE);
+
+#else
+
+  {
+    int dr;
+
+    for (str = BOARDMIN; str < BOARDMAX; str++) {
+      if (!ON_BOARD(str))
+       continue;
+
+      if (black_eye[str].color == BLACK
+         && black_eye[str].origin == str
+         && find_eye_dragons(black_eye[str].origin, black_eye,
+                             BLACK, &dr, 1) == 1) {
+
+       ASSERT1(board[dr] == BLACK, dr);
+       TRACE("eye at %1m found for dragon at %1m--augmenting genus\n",
+             str, dr);
+       if (eye_move_urgency(&black_eye[str].value)
+           > eye_move_urgency(&DRAGON2(dr).genus))
+         DRAGON2(dr).heye = black_eye[str].defense_point;
+       add_eyevalues(&DRAGON2(dr).genus, &black_eye[str].value,
+                     &DRAGON2(dr).genus);
+      }
+
+      if (white_eye[str].color == WHITE
+         && white_eye[str].origin == str
+         && find_eye_dragons(white_eye[str].origin, white_eye,
+                             WHITE, &dr, 1) == 1) {
+
+       ASSERT1(board[dr] == WHITE, dr);
+       TRACE("eye at %1m found for dragon at %1m--augmenting genus\n",
+             str, dr);
+       if (eye_move_urgency(&white_eye[str].value)
+           > eye_move_urgency(&DRAGON2(dr).genus))
+         DRAGON2(dr).heye = white_eye[str].defense_point;
+       add_eyevalues(&DRAGON2(dr).genus, &white_eye[str].value,
+                     &DRAGON2(dr).genus);
+      }
     }
   }
 
+#endif
+
   /* Compute the escape route measure. */
   for (str = BOARDMIN; str < BOARDMAX; str++)
     if (IS_STONE(board[str]) && dragon[str].origin == str)
@@ -1228,6 +1240,69 @@ compute_dragon_influence()
   compute_influence(WHITE, safe_stones, strength, &initial_white_influence,
                     NO_MOVE, "initial white influence, dragons known");
   break_territories(WHITE, &initial_white_influence, 1);
+}
+
+
+/* Compute dragon's genus, possibly excluding one given eye.  To
+ * compute full genus, just set `eye_to_exclude' to NO_MOVE.
+ */
+void
+compute_dragon_genus(int d, struct eyevalue *genus, int eye_to_exclude)
+{
+  int pos;
+  int dr;
+
+  ASSERT1(IS_STONE(board[d]), d);
+  gg_assert(eye_to_exclude == NO_MOVE || ON_BOARD1(eye_to_exclude));
+
+  set_eyevalue(genus, 0, 0, 0, 0);
+
+  if (board[d] == BLACK) {
+    for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+      if (!ON_BOARD(pos))
+       continue;
+
+      if (black_eye[pos].color == BLACK
+         && black_eye[pos].origin == pos
+         && (eye_to_exclude == NO_MOVE
+             || black_eye[eye_to_exclude].origin != pos)
+         && find_eye_dragons(pos, black_eye, BLACK, &dr, 1) == 1
+         && is_same_dragon(dr, d)) {
+       TRACE("eye at %1m (%s) found for dragon at %1m--augmenting genus\n",
+             pos, eyevalue_to_string(&black_eye[pos].value), dr);
+
+       if (eye_to_exclude == NO_MOVE
+           && (eye_move_urgency(&black_eye[pos].value)
+               > eye_move_urgency(genus)))
+         DRAGON2(d).heye = black_eye[pos].defense_point;
+
+       add_eyevalues(genus, &black_eye[pos].value, genus);
+      }
+    }
+  }
+  else {
+    for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+      if (!ON_BOARD(pos))
+       continue;
+
+      if (white_eye[pos].color == WHITE
+         && white_eye[pos].origin == pos
+         && (eye_to_exclude == NO_MOVE
+             || white_eye[eye_to_exclude].origin != pos)
+         && find_eye_dragons(pos, white_eye, WHITE, &dr, 1) == 1
+         && is_same_dragon(dr, d)) {
+       TRACE("eye at %1m (%s) found for dragon at %1m--augmenting genus\n",
+             pos, eyevalue_to_string(&white_eye[pos].value), dr);
+
+       if (eye_to_exclude == NO_MOVE
+           && (eye_move_urgency(&white_eye[pos].value)
+               > eye_move_urgency(genus)))
+         DRAGON2(d).heye = white_eye[pos].defense_point;
+
+       add_eyevalues(genus, &white_eye[pos].value, genus);
+      }
+    }
+  }
 }
 
 
Index: engine/liberty.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
retrieving revision 1.205
diff -u -p -r1.205 liberty.h
--- engine/liberty.h    18 Nov 2003 08:55:46 -0000      1.205
+++ engine/liberty.h    7 Jan 2004 22:13:31 -0000
@@ -290,9 +290,12 @@ int does_secure(int color, int move, int
 void join_dragons(int d1, int d2);
 int dragon_escape(char goal[BOARDMAX], int color, char escape_value[BOARDMAX]);
 void compute_refined_dragon_weaknesses(void);
+
 struct eyevalue;
+void compute_dragon_genus(int d, struct eyevalue *genus, int eye_to_exclude);
 float crude_dragon_weakness(int safety, struct eyevalue *genus, int has_lunch,
                            float moyo_value, float escape_route);
+
 int is_same_dragon(int d1, int d2);
 int are_neighbor_dragons(int d1, int d2);
 void mark_dragon(int pos, char mx[BOARDMAX], char mark);
Index: engine/semeai.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/semeai.c,v
retrieving revision 1.66
diff -u -p -r1.66 semeai.c
--- engine/semeai.c     7 Jan 2004 10:00:20 -0000       1.66
+++ engine/semeai.c     7 Jan 2004 22:13:31 -0000
@@ -246,7 +246,8 @@ find_moves_to_make_seki()
       int color = board[str];
       int opponent = NO_MOVE;
       int certain;
-      
+      struct eyevalue reduced_genus;
+
       for (k = 0; k < DRAGON2(str).neighbors; k++) {
        opponent = dragon2[DRAGON2(str).adjacent[k]].origin;
        if (board[opponent] != color)
@@ -257,15 +258,14 @@ find_moves_to_make_seki()
 
       if (dragon[opponent].status != ALIVE)
        continue;
-      
-      /* FIXME: These heuristics are not very precise. What we really
-       * want to check is whether str is inside the eyespace of the
-       * opponent, for an interpretation of eyespace that includes
-       * lunches, while it doesn't already have more than one eye
-       * elsewhere.
+
+      /* FIXME: These heuristics are used for optimization.  We don't
+       *        want to call expensive semeai code if the opponent
+       *        dragon has more than one eye elsewhere.  However, the
+       *        heuristics might still need improvement.
        */
-      if (DRAGON2(opponent).moyo_size > 10
-         || min_eyes(&DRAGON2(opponent).genus) > 1)
+      compute_dragon_genus(opponent, &reduced_genus, str);
+      if (DRAGON2(opponent).moyo_size > 10 || min_eyes(&reduced_genus) > 1)
        continue;
 
       owl_analyze_semeai_after_move(defend_move, color, opponent, str,
@@ -283,10 +283,39 @@ find_moves_to_make_seki()
        update_status(str, CRITICAL, CRITICAL);
        dragon2[d].semeai_defense_point = defend_move;
        dragon2[d].semeai_defense_certain = certain;
-       /* FIXME: The assumption that the attack move coincides with
-         * the defense move is somewhat optimistic.
+
+       /* We need to determine a proper attack move (the one that
+        * prevents seki).  Currently we try the defense move first,
+        * and if it doesn't work -- all liberties of the string.
         */
-       dragon2[d].semeai_attack_point = defend_move;
+       owl_analyze_semeai_after_move(defend_move, OTHER_COLOR(color),
+                                     str, opponent, &resulta, NULL,
+                                     NULL, 1, NULL);
+       if (resulta != WIN)
+         dragon2[d].semeai_attack_point = defend_move;
+       else {
+         int k;
+         int libs[MAXLIBS];
+         int liberties = findlib(str, MAXLIBS, libs);
+
+         for (k = 0; k < liberties; k++) {
+           owl_analyze_semeai_after_move(libs[k], OTHER_COLOR(color),
+                                         str, opponent, &resulta, NULL,
+                                         NULL, 1, NULL);
+           if (resulta != WIN) {
+             dragon2[d].semeai_attack_point = libs[k];
+             break;
+           }
+         }
+
+         /* FIXME: What should we do if none of the tried attacks worked? */
+         if (k == liberties)
+           dragon2[d].semeai_attack_point = defend_move;
+       }
+
+       DEBUG(DEBUG_SEMEAI, "Move to prevent seki at %1m (%1m vs %1m)\n",
+             dragon2[d].semeai_attack_point, opponent, str);
+
        dragon2[d].semeai_attack_certain = certain;
        dragon2[d].semeai_target = opponent;
       }
@@ -435,8 +464,10 @@ semeai_move_reasons(int color)
 }
 
 
-/* Change the status and safety of a dragon */
-
+/* Change the status and safety of a dragon.  In addition, if the new
+ * status is not DEAD, make all worms of the dragon essential, so that
+ * results found by semeai code don't get ignored.
+ */
 static void
 update_status(int dr, enum dragon_status new_status,
              enum dragon_status new_safety)
@@ -449,8 +480,11 @@ update_status(int dr, enum dragon_status
          status_to_string(dragon[dr].status),
          status_to_string(new_status));
     for (pos = BOARDMIN; pos < BOARDMAX; pos++)
-      if (IS_STONE(board[pos]) && is_same_dragon(dr, pos))
+      if (IS_STONE(board[pos]) && is_same_dragon(dr, pos)) {
        dragon[pos].status = new_status;
+       if (new_status != DEAD)
+         worm[pos].inessential = 0;
+      }
   }
 
   if (DRAGON2(dr).safety != new_safety
Index: engine/value_moves.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v
retrieving revision 1.115
diff -u -p -r1.115 value_moves.c
--- engine/value_moves.c        7 Jan 2004 10:00:20 -0000       1.115
+++ engine/value_moves.c        7 Jan 2004 22:14:02 -0000
@@ -232,19 +232,27 @@ find_more_attack_and_defense_moves(int c
          if (dcode < worm[aa].defense_codes[0]) {
            /* Maybe find_defense() doesn't find the defense. Try to
             * defend with the stored defense move.
+            *
+            * Another option is maybe there is no attack anymore
+            * (e.g. we pushed the worm into seki), find_defense()
+            * could easily fail in that case.
             */
            int attack_works = 1;
-           
-           if (trymove(worm[aa].defense_points[0], other, 
-                       "find_more_attack_and_defense_moves", 0, EMPTY, 0)) {
-             int this_dcode = REVERSE_RESULT(attack(aa, NULL));
-             if (this_dcode > dcode) {
-               dcode = this_dcode;
-               if (dcode >= worm[aa].defense_codes[0])
-                 attack_works = 0;
+
+           if (attack(aa, NULL) >= worm[aa].attack_codes[0]) {
+             if (trymove(worm[aa].defense_points[0], other, 
+                         "find_more_attack_and_defense_moves", 0, EMPTY, 0)) {
+               int this_dcode = REVERSE_RESULT(attack(aa, NULL));
+               if (this_dcode > dcode) {
+                 dcode = this_dcode;
+                 if (dcode >= worm[aa].defense_codes[0])
+                   attack_works = 0;
+               }
+               popgo();
              }
-             popgo();
            }
+           else
+             attack_works = 0;
            
            if (attack_works) {
              if (!cursor_at_start_of_line)
Index: engine/worm.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/worm.c,v
retrieving revision 1.58
diff -u -p -r1.58 worm.c
--- engine/worm.c       24 Aug 2003 03:04:11 -0000      1.58
+++ engine/worm.c       7 Jan 2004 22:14:07 -0000
@@ -301,21 +301,30 @@ make_worms(void)
            int dcode = find_defense(str, NULL);
            if (dcode < worm[str].defense_codes[0]) {
              int attack_works = 1;
+
              /* Sometimes find_defense() fails to find a
               * defense which has been found by other means.
               * Try if the old defense move still works.
+              *
+              * However, we first check if the _attack_ still exists,
+              * because we could, for instance, drive the worm into
+              * seki with our move.
               */
-             if (worm[str].defense_codes[0] != 0
-                 && trymove(worm[str].defense_points[0],
-                            OTHER_COLOR(color), "make_worms", 0, EMPTY, 0)) {
-               int this_dcode = REVERSE_RESULT(attack(str, NULL));
-               if (this_dcode > dcode) {
-                 dcode = this_dcode;
-                 if (dcode >= worm[str].defense_codes[0])
-                   attack_works = 0;
+             if (attack(str, NULL) >= worm[str].attack_codes[0]) {
+               if (worm[str].defense_codes[0] != 0
+                   && trymove(worm[str].defense_points[0],
+                              OTHER_COLOR(color), "make_worms", 0, EMPTY, 0)) {
+                 int this_dcode = REVERSE_RESULT(attack(str, NULL));
+                 if (this_dcode > dcode) {
+                   dcode = this_dcode;
+                   if (dcode >= worm[str].defense_codes[0])
+                     attack_works = 0;
+                 }
+                 popgo();
                }
-               popgo();
              }
+             else
+               attack_works = 0;
              
              /* ...then add an attack point of that worm at pos. */
              if (attack_works) {
Index: regression/seki.tst
===================================================================
RCS file: /cvsroot/gnugo/gnugo/regression/seki.tst,v
retrieving revision 1.4
diff -u -p -r1.4 seki.tst
--- regression/seki.tst 31 Dec 2003 07:05:11 -0000      1.4
+++ regression/seki.tst 7 Jan 2004 22:14:17 -0000
@@ -498,3 +498,7 @@ play black C2
 1106 reg_genmove white
 #? [C1]*
 
+
+loadsgf games/FSGCBot-dr.sgf 234
+2010 reg_genmove white
+#? [A19|B17]
Index: regression/games/FSGCBot-dr.sgf
===================================================================
RCS file: regression/games/FSGCBot-dr.sgf
diff -N regression/games/FSGCBot-dr.sgf
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regression/games/FSGCBot-dr.sgf     7 Jan 2004 22:18:02 -0000
@@ -0,0 +1,246 @@
+(;GM[1]FF[4]CA[UTF-8]AP[CGoban:2]ST[2]
+RU[Japanese]SZ[19]KM[5.50]TM[1500]OT[5x30 byo-yomi]
+PW[FSGCBot]PB[dr]BR[13k]DT[2004-01-06]PC[The Kiseido Go Server (KGS) at 
http://kgs.kiseido.com/]C[FSGCBot [?\]: GTP Engine for FSGCBot (white): GNU Go 
version 3.5.2
+]RE[B+13.50]
+;B[pd]BL[1645.506]CR[pd]
+;W[dp]WL[1649.882]CR[dp]
+;B[pp]BL[1641.677]CR[pp]
+;W[dd]WL[1649.661]CR[dd]
+;B[pj]BL[1638.671]CR[pj]
+;W[nq]WL[1649.258]CR[nq]
+;B[qn]BL[1636]CR[qn]
+;W[pr]WL[1648.844]CR[pr]
+;B[qq]BL[1635.03]CR[qq]
+;W[kq]WL[1648.214]CR[kq]PL[B]
+;B[fc]BL[1623.422]CR[fc]
+;W[nd]WL[1646.74]CR[nd]
+;B[pf]BL[1620.08]CR[pf]
+;W[pc]WL[1645.91]CR[pc]
+;B[qc]BL[1619.068]CR[qc]
+;W[oc]WL[1644.088]CR[oc]
+;B[qd]BL[1607.735]CR[qd]
+;W[fd]WL[1643.499]CR[fd]
+;B[gd]BL[1605.076]CR[gd]
+;W[fe]WL[1642.379]CR[fe]
+;B[dc]BL[1591.304]CR[dc]
+;W[cc]WL[1640.516]CR[cc]
+;B[ec]BL[1586.362]CR[ec]
+;W[cd]WL[1638.323]CR[cd]
+;B[jc]BL[1574.654]CR[jc]
+;W[ch]WL[1637.412]CR[ch]
+;B[cn]BL[1570.625]CR[cn]
+;W[fq]WL[1636.369]CR[fq]
+;B[bp]BL[1568.468]CR[bp]
+;W[cq]WL[1635.337]CR[cq]
+;B[ck]BL[1565.377]CR[ck]
+;W[bq]WL[1634.245]CR[bq]
+;B[bo]BL[1558.647]CR[bo]
+;W[en]WL[1633.111]CR[en]
+;B[mc]BL[1545.713]CR[mc]
+;W[no]WL[1629.854]CR[no]
+;B[om]BL[1542.51]CR[om]
+;W[mm]WL[1628.439]CR[mm]
+;B[le]BL[1519.841]CR[le]
+;W[nf]WL[1627.113]CR[nf]
+;B[ne]BL[1518.56]CR[ne]
+;W[nh]WL[1624.338]CR[nh]
+;B[oe]BL[1500.82]CR[oe]
+;W[kg]WL[1621.179]CR[kg]
+;B[ph]BL[1493.956]CR[ph]
+;W[fk]WL[1618.879]CR[fk]
+;B[ej]BL[1467.929]CR[ej]
+;W[mk]WL[1614.475]CR[mk]
+;B[eh]BL[1450.242]CR[eh]
+;W[gh]WL[1610.9]CR[gh]
+;B[gf]BL[1436.223]CR[gf]
+;W[ig]WL[1607.516]CR[ig]
+;B[cf]BL[1413.312]CR[cf]
+;W[dg]WL[1599.691]CR[dg]
+;B[bi]BL[1400.82]CR[bi]
+;W[bh]WL[1593.575]CR[bh]
+;B[dh]BL[1392.803]CR[dh]
+;W[df]WL[1579.512]CR[df]
+;B[ci]BL[1379.183]CR[ci]
+;W[ah]WL[1572.823]CR[ah]
+;B[ai]BL[1373.727]CR[ai]
+;W[ce]WL[1568.14]CR[ce]
+;B[gi]BL[1343.127]CR[gi]
+;W[hj]WL[1563.582]CR[hj]
+;B[hi]BL[1340.581]CR[hi]
+;W[ii]WL[1559.688]CR[ii]
+;B[gj]BL[1337.164]CR[gj]
+;W[gk]WL[1555.366]CR[gk]
+;B[ij]BL[1327.406]CR[ij]
+;W[hk]WL[1550.405]CR[hk]
+;B[mg]BL[1300.758]CR[mg]
+;W[mf]WL[1544.867]CR[mf]
+;B[ng]BL[1298.208]CR[ng]
+;W[lg]WL[1535.834]CR[lg]
+;B[mh]BL[1279.759]CR[mh]
+;W[ji]WL[1528.644]CR[ji]
+;B[lf]BL[1273.89]CR[lf]
+;W[ge]WL[1523.104]CR[ge]
+;B[hd]BL[1264.843]CR[hd]
+;W[fg]WL[1520.567]CR[fg]
+;B[hf]BL[1245.826]CR[hf]
+;W[he]WL[1518.379]CR[he]
+;B[if]BL[1211.964]CR[if]
+;W[ie]WL[1515.554]CR[ie]
+;B[jf]BL[1205.669]CR[jf]
+;W[jg]WL[1512.432]CR[jg]
+;B[id]BL[1193.1]CR[id]
+;W[qr]WL[1509.277]CR[qr]
+;B[rr]BL[1191.161]CR[rr]
+;W[ni]WL[1506.255]CR[ni]
+;B[mi]BL[1172.48]CR[mi]
+;W[mj]WL[1502.416]CR[mj]
+;B[nj]BL[1143.269]CR[nj]
+;W[cb]WL[1498.427]CR[cb]
+;B[db]BL[1141.299]CR[db]
+;W[dl]WL[1495.968]CR[dl]
+;B[cl]BL[1138.949]CR[cl]
+;W[nk]WL[1492.944]CR[nk]
+;B[oj]BL[1135.68]CR[oj]
+;W[je]WL[1491.101]CR[je]
+;B[kf]BL[1132.007]CR[kf]
+;W[kd]WL[1488.26]CR[kd]
+;B[kc]BL[1115.489]CR[kc]
+;W[rs]WL[1484.564]CR[rs]
+;B[rq]BL[1108.369]CR[rq]
+;W[ap]WL[1482.446]CR[ap]
+;B[ao]BL[1106.245]CR[ao]
+;W[aq]WL[1480.453]CR[aq]
+;B[el]BL[1072.353]CR[el]
+;W[gm]WL[1478.912]CR[gm]
+;B[ca]BL[1028.171]CR[ca]
+;W[dm]WL[1477.564]CR[dm]
+;B[ek]BL[1015.285]CR[ek]
+;W[ba]WL[1476.088]CR[ba]
+;B[da]BL[1013.669]CR[da]
+;W[ok]WL[1474.024]CR[ok]
+;B[pk]BL[1004.646]CR[pk]
+;W[ld]WL[1472.134]CR[ld]
+;B[md]BL[998.826]CR[md]
+;W[bb]WL[1469.858]CR[bb]
+;B[jk]BL[963.552]CR[jk]
+;W[hh]WL[1468.57]CR[hh]
+;B[fh]BL[940.652]CR[fh]
+;W[op]WL[1467.028]CR[op]
+;B[gg]BL[931.154]CR[gg]
+;W[pq]WL[1465.406]CR[pq]
+;B[po]BL[926.618]CR[po]
+;W[lc]WL[1463.442]CR[lc]
+;B[lb]BL[921.9]CR[lb]
+;W[cm]WL[1460.436]CR[cm]
+;B[bm]BL[919.422]CR[bm]
+;W[on]WL[1458.651]CR[on]
+;B[ih]BL[890.776]CR[ih]
+;W[hg]WL[1455.611]CR[hg]
+;B[ki]BL[874.944]CR[ki]
+;W[jj]WL[1451.981]CR[jj]
+;B[ik]BL[865.067]CR[ik]
+;W[kj]WL[1448.094]CR[kj]
+;B[lj]BL[829.7]CR[lj]
+;W[lk]WL[1443.867]CR[lk]
+;B[li]BL[820.685]CR[li]
+;W[kk]WL[1439.235]CR[kk]
+;B[jm]BL[789.7]CR[jm]
+;W[pm]WL[1436.538]CR[pm]
+;B[pn]BL[780.657]CR[pn]
+;W[pl]WL[1434.788]CR[pl]
+;B[ql]BL[777.372]CR[ql]
+;W[ol]WL[1433.343]CR[ol]
+;B[qm]BL[770.988]CR[qm]
+;W[oo]WL[1431.996]CR[oo]
+;B[gl]BL[751.847]CR[gl]
+;W[hl]WL[1430.237]CR[hl]
+;B[fl]BL[742.006]CR[fl]
+;W[jl]WL[1425.857]CR[jl]
+;B[ff]BL[714.285]CR[ff]
+;W[eg]WL[1422.476]CR[eg]
+;B[ed]BL[709.275]CR[ed]
+;W[ee]WL[1419.41]CR[ee]
+;B[ef]BL[693.738]CR[ef]
+;W[cg]WL[1415.954]CR[cg]
+;B[jd]BL[682.202]CR[jd]
+;W[fj]WL[1412.697]CR[fj]
+;B[fi]BL[678.37]CR[fi]
+;W[im]WL[1410.065]CR[im]
+;B[bf]BL[655.421]CR[bf]
+;W[dk]WL[1405.372]CR[dk]
+;B[dj]BL[649.313]CR[dj]
+;W[kh]WL[1403.315]CR[kh]
+;B[of]BL[630.717]CR[of]
+;W[do]WL[1401.317]CR[do]
+;B[dn]BL[623.322]CR[dn]
+;W[em]WL[1399.855]CR[em]
+;B[fm]BL[616.498]CR[fm]
+;W[fn]WL[1398.501]CR[fn]
+;B[co]BL[524.22]CR[co]
+;W[sr]WL[1397.731]CR[sr]
+;B[sq]BL[521.841]CR[sq]
+;W[qs]WL[1397.104]CR[qs]
+;B[ss]BL[506.026]CR[ss]
+;W[cp]WL[1396.257]CR[cp]
+;B[bl]BL[494.456]CR[bl]
+;W[sr]WL[1395.787]CR[sr]
+;B[gn]BL[472.701]CR[gn]
+;W[hm]WL[1393.223]CR[hm]
+;B[ss]BL[470.589]CR[ss]
+;W[gc]WL[1392.209]CR[gc]
+;B[gb]BL[443.845]CR[gb]
+;W[sr]WL[1391.66]CR[sr]
+;B[kl]BL[425.405]CR[kl]
+;W[jn]WL[1390.055]CR[jn]
+;B[ss]BL[414.688]CR[ss]
+;W[og]WL[1389.039]CR[og]
+;B[me]BL[406.214]CR[me]
+;W[sr]WL[1387.957]CR[sr]
+;B[il]BL[396.522]CR[il]
+;W[jl]WL[1384.896]CR[jl]
+;B[ss]BL[395.251]CR[ss]
+;W[di]WL[1384.112]CR[di]
+;B[ei]BL[386.89]CR[ei]
+;W[sr]WL[1383.494]CR[sr]
+;B[eo]BL[376.775]CR[eo]
+;W[fo]WL[1381.954]CR[fo]
+;B[ss]BL[375.272]CR[ss]
+;W[cj]WL[1381.135]CR[cj]
+;B[bj]BL[372.36]CR[bj]
+;W[sr]WL[1380.536]CR[sr]
+;B[fp]BL[362.495]CR[fp]
+;W[ep]WL[1378.953]CR[ep]
+;B[ss]BL[360.762]CR[ss]
+;W[bn]WL[1378.292]CR[bn]
+;B[an]BL[358.601]CR[an]
+;W[sr]WL[1377.741]CR[sr]
+;B[go]BL[357.218]CR[go]
+;W[gp]WL[1376.762]CR[gp]
+;B[ss]BL[355.389]CR[ss]
+;W[am]WL[1376.098]CR[am]
+;B[al]BL[353.459]CR[al]
+;W[sr]WL[1375.579]CR[sr]
+;B[ad]BL[333.896]CR[ad]
+;W[af]WL[1374.827]CR[af]
+;B[ss]BL[332.016]CR[ss]
+;W[jh]WL[1374.199]CR[jh]
+;B[ab]BL[302.94]CR[ab]
+;W[ae]WL[1372.057]CR[ae]
+;B[be]BL[294.707]CR[be]
+;W[bd]WL[1370.284]CR[bd]
+;B[ag]BL[288.836]CR[ag]
+;W[ae]WL[1368.412]CR[ae]
+;B[af]BL[258.075]CR[af]
+;W[de]WL[1367.78]CR[de]
+;B[ac]BL[233.94]CR[ac]
+;W[bg]WL[1367.174]CR[bg]
+;B[ae]BL[231.943]CR[ae]
+(;W[ke]WL[1366.452]CR[ke]
+;B[sr]BL[198.784]CR[sr]
+;W[lh]WL[1365.791]CR[lh]C[Split [-\]: retarded robot....a19 not L15....
+]
+;B[]BL[181.323]
+;W[]WL[1365.791]TW[ih][ij][ik][jk][il][kl][ll][ml][nl][jm][km][lm][nm][om][gn][hn][in][kn][ln][mn][nn][eo][go][ho][io][jo][ko][lo][mo][fp][hp][ip][jp][kp][lp][mp][np][dq][eq][gq][hq][iq][jq][lq][mq][oq][ar][br][cr][dr][er][fr][gr][hr][ir][jr][kr][lr][mr][nr][or][as][bs][cs][ds][es][fs][gs][hs][is][js][ks][ls][ms][ns][os][ps]TB[ea][fa][ga][ha][ia][ja][ka][la][ma][na][oa][pa][qa][ra][sa][eb][fb][hb][ib][jb][kb][mb][nb][ob][pb][qb][rb][sb][gc][hc][ic][nc][oc][pc][rc][sc][nd][od][rd][sd][pe][qe][re][se][mf][nf][qf][rf][sf][og][pg][qg][rg][sg][nh][oh][qh][rh][sh][di][ni][oi][pi][qi][ri][si][aj][cj][qj][rj][sj][ak][bk][qk][rk][sk][rl][sl][am][rm][sm][bn][rn][sn][qo][ro][so][qp][rp][sp])
+(;W[aa]CR[aa]
+;B[ke]CR[ke]
+;W[bc]CR[bc]))




reply via email to

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