diff -N -r -u -X .ignore gnugo-copy/engine/reading.c gnugo/engine/reading.c
--- gnugo-copy/engine/reading.c	2007-03-08 10:08:15.515625000 +0100
+++ gnugo/engine/reading.c	2007-03-08 10:38:24.531250000 +0100
@@ -1036,14 +1036,12 @@
   int other;
   int liberties;
   int libs[MAXLIBS];
-  int *cur_lib, *last_lib;
   int adjs[MAXCHAIN];
   int *cur_adj, *last_adj;
   int r;
   int discard;
-  int aa, bb;
-  int acode;
-  const int *cur_delta;
+  int bb;
+  int dcode, acode;
 
   ASSERT1(IS_STONE(board[str]), str);
   ASSERT1(!attack(str, NULL), str);
@@ -1058,25 +1056,51 @@
    *
    * The test against 6 liberties is just an optimization.
    */
-  if (liberties == 1)
-    change_tactical_point(str, libs[0], WIN, moves, codes,
-			  worm[str].discarded_att_threats);
+  if (liberties == 1) {
+    bb = libs[0];
+    discard = 1;
+
+    if (trymove(bb, other, "attack_threats-D", str)) {
+      dcode = find_defense(bb, NULL);
+      if (dcode) {
+	change_tactical_point(str, bb, dcode, moves, codes,
+			      worm[str].discarded_att_threats);
+	discard = 0;
+      }
+      popgo();
+    }
+
+    if (discard)
+      movelist_change_discarded(bb, MAX_TACTICAL_POINTS,
+				worm[str].discarded_att_threats);
+  }
   else if (liberties < 6) {
+    int aa;
+    int *cur_lib, *last_lib;
+    const int *cur_delta;
+
     cur_lib = libs;
     last_lib = cur_lib + liberties;
 
     for (; cur_lib < last_lib; cur_lib++) {
       aa = *cur_lib;
+      discard = 1;
 
       /* Try to threaten on the liberty. */
       if (trymove(aa, other, "attack_threats-A", str)) {
        acode = attack(str, NULL);
-       if (acode)
+       if (acode) {
 	 change_tactical_point(str, aa, acode, moves, codes,
 			       worm[str].discarded_att_threats);
+	 discard = 0;
+       }
        popgo();
       }
 
+      if (discard)
+	movelist_change_discarded(aa, MAX_TACTICAL_POINTS,
+				  worm[str].discarded_att_threats);
+
       /* Try to threaten on second order liberties. */
       for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) {
        bb = aa + *cur_delta;
@@ -1111,8 +1135,6 @@
   cur_adj = adjs;
   last_adj = cur_adj + chainlinks(str, adjs);
   for (; cur_adj < last_adj; cur_adj++) {
-    int dcode;
-
     if (!attack_and_defend(*cur_adj, &acode, NULL, &dcode, NULL))
       continue;
 
diff -N -r -u -X .ignore gnugo-copy/engine/worm.c gnugo/engine/worm.c
--- gnugo-copy/engine/worm.c	2007-03-07 21:31:08.000000000 +0100
+++ gnugo/engine/worm.c	2007-03-08 12:16:29.187500000 +0100
@@ -461,17 +461,15 @@
 	&& worm[pos].origin == pos) {
 
       /* Find adjacent worms that can be easily captured, aka lunches. */
-      if (find_lunch(pos, &lunch)
-	  && ((acode = worm[lunch].attack_codes[0]) == WIN
-	      || acode == KO_A)) {
+      if (find_lunch(pos, &lunch)) {
 	DEBUG(DEBUG_WORMS, "lunch found for %1m at %1m\n", pos, lunch);
 	worm[pos].lunch = lunch;
 	propagate_worm(pos);
       }
       else {
 	/* Identify INESSENTIAL strings. */
-	if (!worm[pos].genus
-	    && !worm[pos].liberties2
+	if (!worm[pos].liberties2
+	    && !worm[pos].genus
 	    && !worm[pos].cutstone) {
 	  if (examine_cavity(pos, &edge) != GRAY && edge < 3) {
 	    DEBUG(DEBUG_WORMS, "Worm %1m identified as inessential.\n", pos);
@@ -965,46 +963,61 @@
 find_lunch(int str, int *lunch)
 {
   int pos;
-  int k;
+  int apos;
+  int lunch_pos = NO_MOVE;
+  int other = OTHER_COLOR(board[str]);
+  const int *cur_delta;
 
   ASSERT1(IS_STONE(board[str]), str);
   ASSERT1(stackp == 0, str);
 
-  *lunch = NO_MOVE;
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (board[pos] != OTHER_COLOR(board[str]))
+    if (board[pos] != other)
       continue;
-    for (k = 0; k < 8; k++) {
-      int apos = pos + delta[k];
+    for (cur_delta = delta; cur_delta < last_delta_8; cur_delta++) {
+      apos = pos + *cur_delta;
       if (IS_STONE(board[apos]) && is_same_worm(apos, str)) {
-	if (worm[pos].attack_codes[0] != 0 && !is_ko_point(pos)) {
+	if (worm[pos].attack_codes[0] >= KO_A && !is_ko_point(pos)) {
 	  /*
 	   * If several adjacent lunches are found, we pick the 
-	   * juiciest. First maximize cutstone, then minimize liberties. 
+	   * juiciest. First maximize attack_code, then cutstone,
+	   * then minimize liberties, then maximize size. 
 	   * We can only do this if the worm data is available, 
 	   * i.e. if stackp==0.
 	   */
-	  if (*lunch == NO_MOVE
-	      || worm[pos].cutstone > worm[*lunch].cutstone 
-	      || (worm[pos].cutstone == worm[*lunch].cutstone 
-		  && worm[pos].liberties < worm[*lunch].liberties)) {
-	    *lunch = worm[pos].origin;
+	  if (lunch_pos) {
+	    if (worm[pos].attack_codes[0]
+		< worm[lunch_pos].attack_codes[0])
+	      break;
+	    else if (worm[pos].attack_codes[0]
+		     == worm[lunch_pos].attack_codes[0]) {
+	      if (worm[pos].cutstone < worm[lunch_pos].cutstone)
+		break;
+	      else if (worm[pos].cutstone == worm[lunch_pos].cutstone) {
+		if (worm[pos].liberties > worm[lunch_pos].liberties)
+		  break;
+		else if (worm[pos].liberties == worm[lunch_pos].liberties) {
+		  if (worm[pos].size <= worm[lunch_pos].size)
+		    break;
+		}
+	      }
+	    }
 	  }
+
+	  lunch_pos = worm[pos].origin;
 	}
 	break;
       }
     }
   }
-  
-  if (*lunch != NO_MOVE)
-    return 1;
 
-  return 0;
+  *lunch = lunch_pos;
+  return lunch_pos;
 }
 
 
 /*
- * Test whether two worms are the same. Used by autohelpers.
+ * Test whether two worms are the same.
  * Before this function can be called, build_worms must have been run.
  */
 
@@ -1039,6 +1052,7 @@
 void
 change_defense(int str, int move, int dcode)
 {
+  DEBUG(DEBUG_WORMS, "change_defense: %1m %1m %d\n", str, move, dcode);
   change_tactical_point(str, move, dcode,
 			worm[str].defense_points, worm[str].defense_codes,
 			worm[str].discarded_defenses);
@@ -1075,6 +1089,8 @@
 void
 change_defense_threat(int str, int move, int dcode)
 {
+  DEBUG(DEBUG_WORMS, "change_defense_threat: %1m %1m %d\n", str,
+	move, dcode);
   change_tactical_point(str, move, dcode,
 			worm[str].defense_threat_points,
 			worm[str].defense_threat_codes,
@@ -1094,6 +1110,8 @@
 void
 change_attack_threat(int str, int move, int acode)
 {
+  DEBUG(DEBUG_WORMS, "change_attack_threat: %1m %1m %d\n", str,
+	move, acode);
   change_tactical_point(str, move, acode,
 			worm[str].attack_threat_points,
 			worm[str].attack_threat_codes,
@@ -1226,26 +1244,38 @@
     if (!IS_STONE(board[pos]) || !is_worm_origin(pos, pos))
        continue;
 
-    if (board[pos] == OTHER_COLOR(color)) {
-      for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
-	if (worm[pos].attack_codes[k] != 0)
-	  add_attack_move(worm[pos].attack_points[k], pos,
-			  worm[pos].attack_codes[k]);
-	if (worm[pos].attack_threat_codes[k] != 0)
-	  add_attack_threat_move(worm[pos].attack_threat_points[k], pos,
-				 worm[pos].attack_threat_codes[k]);
-      }
-    }
-      
     if (board[pos] == color) {
       for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
-	if (worm[pos].defense_codes[k] != 0)
+	if (worm[pos].defense_codes[k])
 	  add_defense_move(worm[pos].defense_points[k], pos,
 			   worm[pos].defense_codes[k]);
+	else
+	  break;
+      }
 
-	if (worm[pos].defense_threat_codes[k] != 0)
+      for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
+	if (worm[pos].defense_threat_codes[k])
 	  add_defense_threat_move(worm[pos].defense_threat_points[k], pos,
 				  worm[pos].defense_threat_codes[k]);
+	else
+	  break;
+      }
+    }
+    else { /* board[pos] == other */
+      for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
+	if (worm[pos].attack_codes[k])
+	  add_attack_move(worm[pos].attack_points[k], pos,
+			  worm[pos].attack_codes[k]);
+	else
+	  break;
+      }
+
+      for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
+	if (worm[pos].attack_threat_codes[k])
+	  add_attack_threat_move(worm[pos].attack_threat_points[k], pos,
+				 worm[pos].attack_threat_codes[k]);
+	else
+	  break;
       }
     }
   }
