Index: gnugo/config.h.in
===================================================================
RCS file: /sources/gnugo/gnugo/config.h.in,v
retrieving revision 1.43
diff -u -r1.43 config.h.in
--- gnugo/config.h.in	21 Oct 2005 11:01:16 -0000	1.43
+++ gnugo/config.h.in	30 Dec 2006 20:55:17 -0000
@@ -12,7 +12,7 @@
 /* Center oriented influence. Disabled by default. */
 #undef COSMIC_GNUGO
 
-/* Default level (strength). Up to 10 supported */
+/* Default level (strength). Up to 12 is recommended. */
 #undef DEFAULT_LEVEL
 
 /* Default hash table size in megabytes */
@@ -27,6 +27,9 @@
 /* GAIN/LOSS codes. Disabled by default. */
 #undef EXPERIMENTAL_OWL_EXT
 
+/* Disable unneeded things. 0 standard. */
+#undef FINAL_RELEASE
+
 /* The concatenation of the strings "GNU ", and PACKAGE. */
 #undef GNU_PACKAGE
 
@@ -103,6 +106,9 @@
 /* Semeai Variations. 500 default */
 #undef SEMEAI_NODE_LIMIT
 
+/* The size of a `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
 /* The size of a `long', as computed by sizeof. */
 #undef SIZEOF_LONG
 
Index: gnugo/configure
===================================================================
RCS file: /sources/gnugo/gnugo/configure,v
retrieving revision 1.125
diff -u -r1.125 configure
--- gnugo/configure	22 May 2006 16:38:08 -0000	1.125
+++ gnugo/configure	30 Dec 2006 20:55:20 -0000
@@ -2,7 +2,7 @@
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by Autoconf 2.52.
 #
-# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2006
 # Free Software Foundation, Inc.
 # This configure script is free software; the Free Software Foundation
 # gives unlimited permission to copy, distribute and modify it.
@@ -673,6 +673,8 @@
                                          analysis (default)
   --disable-socket-support           don't compile GTP over TCP/IP support
   --enable-socket-support            compile TCP/IP support (default)
+  --enable-final-release             turn off additional chekcs, stats, etc.
+  --disable-final-release            turn on additional chekcs, stats, etc.
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1444,6 +1446,12 @@
 
 fi;
 
+# Check whether --enable-final-release or --disable-final-release was given.
+if test "${enable-final-release+set}" = set; then
+  enableval="$enable_final_release"
+
+fi;
+
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -3377,6 +3385,50 @@
 #define SIZEOF_LONG $ac_cv_sizeof_long
 EOF
 
+echo "$as_me:3181: checking size of int" >&5
+echo $ECHO_N "checking size of int... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line 3391 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int
+main ()
+{
+FILE *f = fopen ("conftest.val", "w");
+if (!f)
+  exit (1);
+fprintf (f, "%d", (sizeof (int)));
+fclose (f);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:3408: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:3411: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:3413: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:3416: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f conftest.val
+echo "$as_me:3426: result: $ac_cv_sizeof_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int" >&6
+cat >>confdefs.h <<EOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+EOF
+
 for ac_func in vsnprintf gettimeofday usleep times
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -4104,6 +4156,18 @@
 
 fi
 
+if test "$enable_final_release" = "yes" ; then
+   cat >>confdefs.h <<\EOF
+#define FINAL_RELEASE 1
+EOF
+
+else
+   cat >>confdefs.h <<\EOF
+#define FINAL_RELEASE 0
+EOF
+
+fi
+
 if test "$enable_cosmic_gnugo" = "yes" ; then
    cat >>confdefs.h <<\EOF
 #define COSMIC_GNUGO 1
Index: gnugo/configure.in
===================================================================
RCS file: /sources/gnugo/gnugo/configure.in,v
retrieving revision 1.136
diff -u -r1.136 configure.in
--- gnugo/configure.in	22 May 2006 16:38:08 -0000	1.136
+++ gnugo/configure.in	30 Dec 2006 20:55:21 -0000
@@ -124,6 +124,10 @@
 AC_ARG_ENABLE(socket-support,
  [  --disable-socket-support           don't compile GTP over TCP/IP support
   --enable-socket-support            compile TCP/IP support (default)])
+  
+AC_ARG_ENABLE(final-release,
+ [  --enable-final-release     turn off additional chekcs, stats, etc.
+  --disable-final-release    turn on additional chekcs, stats, etc. (default)])
 
 AC_PROG_CC
 
@@ -178,6 +182,7 @@
    term_header="no"
 fi
 
+AC_CHECK_SIZEOF(int,,[#include <stdio.h>])
 AC_CHECK_SIZEOF(long,,[#include <stdio.h>])
 
 dnl vsnprintf not universally available
@@ -338,7 +343,7 @@
 dnl ------------ set default level  ----------
 
 AH_TEMPLATE([DEFAULT_LEVEL],
-[Default level (strength). Up to 10 supported])
+[Default level (strength). Up to 12 is recommended.])
 
 if test "$enable_level" ; then
    AC_DEFINE_UNQUOTED(DEFAULT_LEVEL, $enable_level)
@@ -491,6 +496,17 @@
    AC_DEFINE(OWL_THREATS, 0)
 fi
 
+dnl ------------ Final release -------------------
+
+AH_TEMPLATE([FINAL_RELEASE],
+[Disable unneeded things. 0 standard.])
+
+if test "$enable_final_release" = "yes" ; then
+   AC_DEFINE(FINAL_RELEASE, 1)
+else
+   AC_DEFINE(FINAL_RELEASE, 0)
+fi
+
 dnl ------------ additional valgrind macros ------
 
 AH_TEMPLATE([USE_VALGRIND],
Index: gnugo/engine/aftermath.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/aftermath.c,v
retrieving revision 1.61
diff -u -r1.61 aftermath.c
--- gnugo/engine/aftermath.c	18 May 2006 03:54:42 -0000	1.61
+++ gnugo/engine/aftermath.c	30 Dec 2006 20:55:24 -0000
@@ -288,20 +288,27 @@
     for (k = 0; k < 4; k++) {
       int dir = delta[k];
       int right = delta[(k+1)%4];
+      int checked_pos = pos + dir;
+
       if (!ON_BOARD(pos - dir)
-	  && board[pos + dir] == color
-	  && board[pos + dir + right] == other
-	  && board[pos + dir - right] == other
-	  && (libs > countlib(pos + dir)
-	      || (libs > 4
-		  && libs == countlib(pos + dir)))
-	  && (DRAGON2(pos + dir).safety == INVINCIBLE
-	      || DRAGON2(pos + dir).safety == STRONGLY_ALIVE)) {
-	int this_score = 20 * (owl_hotspot[pos] + reading_hotspot[pos]);
-	if (this_score > best_score) {
-	  best_score = this_score;
-	  best_scoring_move = pos;
-	}
+	  && board[checked_pos] == color
+	  && board[checked_pos + right] == other
+	  && board[checked_pos - right] == other) {
+
+	    int count_lib = countlib(checked_pos);
+	    int safety;
+
+	    if ((libs > count_lib
+	        || (libs > 4 && libs == count_lib))
+	    && ((safety = DRAGON2(checked_pos).safety) == INVINCIBLE
+	        || safety == STRONGLY_ALIVE)) {
+
+	  int this_score = 20 * (owl_hotspot[pos] + reading_hotspot[pos]);
+	  if (this_score > best_score) {
+	    best_score = this_score;
+	    best_scoring_move = pos;
+	  }
+	    }
       }
     }
   }
@@ -363,25 +370,27 @@
 	    score--;
 	  else {
 	    if (board[pos2] == color) {
+	      int count_stones = countstones(pos2);
+	      int count_lib = countlib(pos2);
 	      move_ok = 1;
 	      score += 7;
-	      if (countstones(pos2) > 2)
-		score++;
-	      if (countstones(pos2) > 4)
+	      if (count_stones > 4)
+		score += 2;
+	      else if (count_stones > 2)
 		score++;
-	      if (countlib(pos2) < 4)
-		score++;
-	      if (countlib(pos2) < 3)
+	      if (count_lib < 3)
+		score += 2;
+	      else if (count_lib < 4)
 		score++;
 	    }
-	    else {
+	    else { /* board[pos2] == other */
 	      int deltalib = (approxlib(pos, other, MAXLIBS, NULL)
 			      - countlib(pos2));
 	      move_ok = 1;
 	      score++;
-	      if (deltalib >= 0)
-		score++;
 	      if (deltalib > 0)
+		score += 2;
+	      else if (deltalib >= 0)
 		score++;
 	    }
 	    mark_string(pos2, mx, mark);
@@ -470,16 +479,18 @@
 
 	if (!mx[origin] && dragon[pos2].status == DEAD) {
 	  bonus++;
-	  if (k < 4 
-	      && countlib(pos2) <= 2 
-	      && countstones(pos2) >= 3)
-	    bonus++;
+	  if (k < 4) {
+	    int count_lib = countlib(pos2);
+	    if (count_lib <= 2
+	        && countstones(pos2) >= 3)
+	      bonus++;
 	  
-	  if (k < 4 && countlib(pos2) == 1)
-	    bonus += 3;
+	    if (count_lib == 1)
+	      bonus += 3;
+	  }
 	}
 	mx[origin] = 1;
-      }
+	  }
       else if (board[pos2] == color) {
 	dragons[pos] = pos2;
 	
@@ -491,18 +502,19 @@
 	
 	if (k < 4) {
 	  int apos = worm[pos2].origin;
+	  int count_lib = countlib(apos);
 	  
 	  if (!mx[apos]) {
 	    own_worms++;
 	    if (countstones(apos) == 1)
 	      bonus += 2;
-	    if (countlib(apos) < 6
-		&& approxlib(pos, color, 5, NULL) < countlib(apos))
+	    if (count_lib < 6
+		&& approxlib(pos, color, 5, NULL) < count_lib)
 	      bonus -= 5;
 	    mx[apos] = 1;
 	  }
 	  
-	  if (countlib(apos) <= 2) {
+	  if (count_lib <= 2) {
 	    int r;
 	    int important = 0;
 	    int safe_atari = 0;
@@ -612,8 +624,9 @@
       int move_ok = 1;
       if (libs < 5) {
 	for (k = 0; k < 4; k++) {
-	  if (board[move + delta[k]] == color
-	      && countlib(move + delta[k]) > libs)
+	  int checked_pos = move + delta[k];
+	  if (board[checked_pos] == color
+	      && countlib(checked_pos) > libs)
 	    break;
 	}
 	if (k < 4) {
@@ -733,7 +746,8 @@
      * potential move possible.
      */
     if (!self_atari_ok) {
-      while (countlib(pos) == 1) {
+      int count_lib;
+      while ((count_lib = countlib(pos)) == 1) {
 	int lib;
 	findlib(pos, 1, &lib);
 	move = lib;
@@ -741,7 +755,7 @@
 	  break;
       }
       
-      if (countlib(pos) == 1)
+      if (count_lib == 1)
 	move = NO_MOVE;
     }
 
Index: gnugo/engine/board.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/board.c,v
retrieving revision 1.119
diff -u -r1.119 board.c
--- gnugo/engine/board.c	18 May 2006 04:09:28 -0000	1.119
+++ gnugo/engine/board.c	30 Dec 2006 20:55:26 -0000
@@ -32,6 +32,7 @@
 #include "hash.h"
 #include "sgftree.h"
 #include "gg_utils.h"
+#include "gnugo.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -91,8 +92,42 @@
  * exceeds 40. But since we have no way to recover from running out of
  * stack space, we allocate with a substantial safety margin.
  */
+#ifdef INT_INTERSECTION
+#define STACK_SIZE 2 * 80 * MAXSTACK
+#else
 #define STACK_SIZE 80 * MAXSTACK
+#endif
+
+#ifdef INT_INTERSECTION
+
+#define CLEAR_STACKS() do { \
+  change_stack_pointer = change_stack; \
+  VALGRIND_MAKE_WRITABLE(change_stack, sizeof(change_stack)); \
+} while (0)
+
+/* Begin a record : address == NULL */
+#define BEGIN_CHANGE_RECORD()\
+((change_stack_pointer++)->address = NULL)
+
+/* PUSH_VERTEX should be the same as PUSH_VALUE when Intersection is
+ * int type */
+
+/* Save a value : store the address and the value in the stack */
+#define PUSH_VALUE(v)\
+(change_stack_pointer->address = &(v),\
+ (change_stack_pointer++)->value = (v))
+
+/* Save a board value : store the address and the value in the stack */
+#define PUSH_VERTEX(v)\
+(change_stack_pointer->address = &(v),\
+ (change_stack_pointer++)->value = (v))
+
+#define POP_MOVE()\
+  while ((--change_stack_pointer)->address)\
+  *(change_stack_pointer->address) =\
+  change_stack_pointer->value
 
+#else
 
 #define CLEAR_STACKS() do { \
   change_stack_pointer = change_stack; \
@@ -119,13 +154,11 @@
 #define POP_MOVE()\
   while ((--change_stack_pointer)->address)\
   *(change_stack_pointer->address) =\
-  change_stack_pointer->value
-
-
-#define POP_VERTICES()\
+  change_stack_pointer->value;
   while ((--vertex_stack_pointer)->address)\
   *(vertex_stack_pointer->address) =\
   vertex_stack_pointer->value
+#endif
 
 
 /* ================================================================ */
@@ -138,12 +171,14 @@
 static struct string_liberties_data string_libs[MAX_STRINGS];
 static struct string_neighbors_data string_neighbors[MAX_STRINGS];
 
-/* Stacks and stack pointers. */
+/* Stacks and stack pointers. Used for undoing changes on the board */
 static struct change_stack_entry change_stack[STACK_SIZE];
 static struct change_stack_entry *change_stack_pointer;
 
+#ifndef INT_INTERSECTION
 static struct vertex_stack_entry vertex_stack[STACK_SIZE];
 static struct vertex_stack_entry *vertex_stack_pointer;
+#endif
 
 
 /* Index into list of strings. The index is only valid if there is a
@@ -164,13 +199,14 @@
 /* Macros to traverse the stones of a string.
  *
  * Usage:
- * int s, pos;
- * s = find_the_string()
- * pos = FIRST_STONE(s);
+ * int first, s, pos;
+ * s = find_the_string();
+ * first = FIRST_STONE(s);
+ * pos = first;
  *   do {
  *    use_stone(pos);
  *    pos = NEXT_STONE(pos);
- *  } while (!BACK_TO_FIRST_STONE(s, pos));
+ *  } while (pos != first);
  */
 #define FIRST_STONE(s) \
   (string[s].origin)
@@ -178,9 +214,6 @@
 #define NEXT_STONE(pos) \
   (next_stone[pos])
 
-#define BACK_TO_FIRST_STONE(s, pos) \
-  ((pos) == string[s].origin)
-
 
 /* Assorted useful macros.
  *
@@ -197,8 +230,8 @@
 #define MARK_LIBERTY(pos) \
   ml[pos] = liberty_mark
 
-#define UNMARKED_STRING(pos) \
-  (string[string_number[pos]].mark != string_mark)
+#define UNMARKED_STRING(str_nr) \
+  (string[str_nr].mark != string_mark)
 
 /* Note that these two macros are not complementary. Both return
  * false if board[pos] != color.
@@ -211,10 +244,10 @@
   (board[pos] == color\
    && string[string_number[pos]].mark == string_mark)
 
-#define MARK_STRING(pos) string[string_number[pos]].mark = string_mark
+#define MARK_STRING(str_nr) string[str_nr].mark = string_mark
 
 #define STRING_AT_VERTEX(pos, s, color)\
-  ((board[pos] == color) && string_number[pos] == (s))
+  ((board[pos] == (color)) && string_number[pos] == (s))
 
 #define NEIGHBOR_OF_STRING(pos, s, color)\
   (STRING_AT_VERTEX(SOUTH(pos), s, color)\
@@ -245,12 +278,12 @@
   (STRING_AT_VERTEX(EAST(pos), s, color)\
    || STRING_AT_VERTEX(SOUTH(pos), s, color)\
    || STRING_AT_VERTEX(NORTH(pos), s, color))
-  
-#define LIBERTIES(pos)\
-  string[string_number[pos]].liberties
 
-#define COUNTSTONES(pos) \
-  string[string_number[pos]].size
+#define LIBERTIES(str_nr)\
+  string[str_nr].liberties
+
+#define COUNTSTONES(str_nr) \
+  string[str_nr].size
 
 #define ADD_LIBERTY(s, pos)\
   do {\
@@ -267,8 +300,8 @@
     ml[pos] = liberty_mark;\
   } while (0)
 
-#define ADD_NEIGHBOR(s, pos)\
-  string_neighbors[s].list[string[s].neighbors++] = string_number[pos]
+#define ADD_NEIGHBOR(s1, s2)\
+  string_neighbors[s1].list[string[s1].neighbors++] = s2
 
 #define DO_ADD_STONE(pos, color)\
   do {\
@@ -304,16 +337,28 @@
 static int do_trymove(int pos, int color, int ignore_ko);
 static void undo_trymove(void);
 
-static int do_approxlib(int pos, int color, int maxlib, int *libs);
-static int slow_approxlib(int pos, int color, int maxlib, int *libs);
-static int do_accuratelib(int pos, int color, int maxlib, int *libs);
+
+struct board_cache_entry {
+  int threshold; /* a number of checked, possible liberties
+                  * (liberties <= threshold) */
+  int liberties; /* number of liberties (if liberties == threshold
+                  * there is maybe more liberties) */
+  Hash_data position_hash;
+};
+
+inline static int do_approxlib(int pos, int color, int maxlib, int *libs,
+							   struct board_cache_entry *entry);
+inline static int slow_approxlib(int pos, int color, int maxlib, int *libs,
+								 struct board_cache_entry *entry);
+inline static int do_accuratelib(int pos, int color, int maxlib, int *libs,
+								 struct board_cache_entry *entry);
 
 static int is_superko_violation(int pos, int color, enum ko_rules type);
 
 static void new_position(void);
-static int propagate_string(int stone, int str);
-static void find_liberties_and_neighbors(int s);
-static int do_remove_string(int s);
+static int propagate_string(int stone_pos, int str_pos, int color);
+static void find_liberties_and_neighbors(int str_nr);
+static int do_remove_string(int str_nr);
 static void do_commit_suicide(int pos, int color);
 static void do_play_move(int pos, int color);
 
@@ -326,9 +371,9 @@
 /* Coordinates for the eight directions, ordered
  * south, west, north, east, southwest, northwest, northeast, southeast.
  */
-int deltai[8] = { 1,  0, -1,  0,  1, -1, -1, 1};
-int deltaj[8] = { 0, -1,  0,  1, -1, -1,  1, 1};
-int delta[8]  = { NS, -1, -NS, 1, NS-1, -NS-1, -NS+1, NS+1};
+const int deltai[8] = { 1,  0, -1,  0,  1, -1, -1, 1};
+const int deltaj[8] = { 0, -1,  0,  1, -1, -1,  1, 1};
+const int delta[8]  = { NS, -WE, -NS, WE, NS-WE, -NS-WE, -NS+WE, NS+WE};
 
 
 /* ================================================================ */
@@ -448,7 +493,7 @@
 
   handicap = 0;
   
-  hashdata_recalc(&board_hash, board, board_ko_pos);
+  hashdata_recalc(&board_hash, board, NO_MOVE);
   new_position();
 }
 
@@ -496,18 +541,20 @@
  *   }   
  *
  * The message can be written as a comment to an sgf file using 
- * sgfdump(). str can be NO_MOVE if it is not needed but otherwise  
- * the location of str is included in the comment.
+ * sgfdump().
+ * str_pos is currently not used by function
  */
 
 int 
-trymove(int pos, int color, const char *message, int str)
+trymove(int pos, int color, const char *message, int str_pos)
 {
-  UNUSED(str);
+  UNUSED(str_pos);
+
   /* Do the real work elsewhere. */
   if (!do_trymove(pos, color, 0))
     return 0;
 
+#ifndef GG_TURN_OFF_TRACES
   /* Store the move in an sgf tree if one is available. */
   if (sgf_dumptree) {
     char buf[100];
@@ -540,10 +587,16 @@
     sgftreeAddPlayLast(sgf_dumptree, color, I(pos), J(pos));
     sgftreeAddComment(sgf_dumptree, buf);
   }
-  
+#else
+  UNUSED(message);
+#endif
+
   if (count_variations)
     count_variations++;
+
+#ifndef GG_TURN_OFF_STATS
   stats.nodes++;
+#endif
 
   return 1;
 }
@@ -567,16 +620,19 @@
   if (!do_trymove(pos, color, 1))
     return 0;
 
+#ifndef GG_TURN_OFF_TRACES
   if (sgf_dumptree) {
     char buf[100];
     if (message == NULL)
       message = "UNKNOWN";
     if (komaster != EMPTY)
-      gg_snprintf(buf, 100, "tryko: %s (variation %d, %s, komaster %s:%s)", 
-		  message, count_variations, hashdata_to_string(&board_hash),
+      gg_snprintf(buf, 100, "tryko: %s at %s (variation %d, hash %s, komaster %s:%s)", 
+		  message, location_to_string(pos), count_variations,
+		  hashdata_to_string(&board_hash),
 		  color_to_string(komaster), location_to_string(kom_pos));
     else
-      gg_snprintf(buf, 100, "tryko: %s (variation %d, %s)", message,
+      gg_snprintf(buf, 100, "tryko: %s at %s (variation %d, hash %s)", message,
+		  location_to_string(pos),
 		  count_variations, hashdata_to_string(&board_hash));
 
     /* Add two pass moves to the SGF output to simulate the ko threat
@@ -595,14 +651,176 @@
     sgftreeAddPlayLast(sgf_dumptree, color, I(pos), J(pos));
     sgftreeAddComment(sgf_dumptree, buf);
   }
+#else
+  UNUSED(message);
+#endif
   
   if (count_variations)
     count_variations++;
+
+#ifndef GG_TURN_OFF_STATS
   stats.nodes++;
+#endif
+
+  return 1;
+}
+
+/*
+ * This function is used by komaster_trymove(). It performs checks made by trymove()
+ * and tryko(), so these functions have not to be called twice. It works like
+ * trymove() and it returns (by ko_move_allowed) the result of tryko(), but it
+ * doesn't call really_do_trymove() - we have to call it ourselves and function
+ * trykomaster_move does it for us.
+ */
+
+inline static int
+check_komaster_move(int pos, int color, int *ko_move_allowed)
+{
+  *ko_move_allowed = 0;
+
+  /* 1. The color must be BLACK or WHITE. */
+  gg_assert(color == BLACK || color == WHITE);
+ 
+  if (pos != PASS_MOVE) {
+    /* 2. Unless pass, the move must be inside the board. */
+    ASSERT_ON_BOARD1(pos);
+    
+    /* Update the reading tree shadow. */
+    shadow[pos] = 1;
+
+    /* 3. The location must be empty. */
+    if (board[pos] != EMPTY)
+      return 0;
+    
+    /* 4. Test if the location is the ko point. */
+	if (pos == board_ko_pos) {
+      /*    The ko position is guaranteed to have all neighbors of the
+       *    same color, or off board. If that color is the same as the
+       *    move the ko is being filled, it is always allowed. This
+       *    could be tested with has_neighbor() but here a faster test
+       *    suffices.
+       */
+	  if (board[WEST(pos)] == OTHER_COLOR(color)
+	      || board[EAST(pos)] == OTHER_COLOR(color))
+        *ko_move_allowed = 1;
+	}
+
+    /* 5. Test for suicide. */
+	if (is_suicide(pos, color)) {
+      *ko_move_allowed = 0;
+      return 0;
+    }
+  }
+
+  /* Check for stack overflow. */
+  if (stackp >= MAXSTACK-2) {
+    fprintf(stderr, 
+	    "gnugo: Truncating search. This is beyond my reading ability!\n");
+    /* FIXME: Perhaps it's best to just assert here and be done with it? */
+#if 0
+      ASSERT1(0 && "check_komaster_move stack overflow", pos);
+#endif
+#if 0
+    if (verbose > 0) {
+      showboard(0);
+      dump_stack();
+    }
+#endif
+    fflush(stderr);
+    *ko_move_allowed = 0;
+    return 0;
+  }
+
+  if (*ko_move_allowed)
+    return 0;
 
   return 1;
 }
 
+/*
+ * Function calls really_do_trymove, counts stats and does all traces.
+ * It is called by komaster_trymove after check_komaster_move checks
+ * if the move is possible.
+ */
+
+static void
+really_do_komastermove(int pos, int color, const char *message, int ko_move)
+{
+#ifndef GG_TURN_OFF_STATS
+  /* Only count trymove when we do create a new position. */
+  trymove_counter++;
+#endif
+  
+  /* So far, so good. Now push the move on the move stack. These are
+   * needed for dump_stack().
+   */
+  stack[stackp] = pos;
+  move_color[stackp] = color;
+
+  really_do_trymove(pos, color);
+
+#ifndef GG_TURN_OFF_TRACES
+  if (sgf_dumptree) {
+    char buf[100];
+
+    if (message == NULL)
+      message = "UNKNOWN";
+    
+    if (pos == NO_MOVE) {
+      if (komaster != EMPTY)
+	gg_snprintf(buf, 100, "komaster_trymove: %s (variation %d, hash %s, komaster %s:%s)", 
+		    message, count_variations, hashdata_to_string(&board_hash),
+		    color_to_string(komaster), location_to_string(kom_pos));
+      else
+	gg_snprintf(buf, 100, "komaster_trymove: %s (variation %d, hash %s)", message,
+		    count_variations, hashdata_to_string(&board_hash));
+    }
+    else {
+      if (komaster != EMPTY)
+	gg_snprintf(buf, 100, 
+		    "komaster_trymove: %s at %s (variation %d, hash %s, komaster %s:%s)", 
+		    message, location_to_string(pos), count_variations,
+		    hashdata_to_string(&board_hash),
+		    color_to_string(komaster),
+		    location_to_string(kom_pos));
+      else
+	gg_snprintf(buf, 100, "komaster_trymove: %s at %s (variation %d, hash %s)", 
+		    message, location_to_string(pos), count_variations,
+		    hashdata_to_string(&board_hash));
+    }
+
+    /* Add two pass moves to the SGF output to simulate the ko threat
+     * and the answer.
+     *
+     * The reason we add these is that certain SGF viewers, including
+     * Cgoban 1, won't properly display variations with illegal ko
+     * captures. SGF FF[4] compliant browsers should have no problem
+     * with this, though.
+     */
+    if (ko_move) {
+      sgftreeAddPlayLast(sgf_dumptree, color, -1, -1);
+      sgftreeAddComment(sgf_dumptree, "tenuki (ko threat)");
+      sgftreeAddPlayLast(sgf_dumptree, OTHER_COLOR(color), -1, -1);
+      sgftreeAddComment(sgf_dumptree, "tenuki (answers ko threat)");
+    }
+
+    sgftreeAddPlayLast(sgf_dumptree, color, I(pos), J(pos));
+    sgftreeAddComment(sgf_dumptree, buf);
+  }
+#else
+  UNUSED(message);
+  UNUSED(ko_move);
+#endif
+  
+  if (count_variations)
+    count_variations++;
+
+#ifndef GG_TURN_OFF_STATS
+  stats.nodes++;
+#endif
+}
+
+
 /* Really, really make a temporary move. It is assumed that all
  * necessary checks have already been made and likewise that various
  * administrative bookkeeping outside of the actual board logic has
@@ -614,19 +832,8 @@
   BEGIN_CHANGE_RECORD();
   PUSH_VALUE(board_ko_pos);
 
-  /*
-   * FIXME: Do we really have to store board_hash in a stack?
-   *
-   * Answer: No, we don't.  But for every stone that we add
-   *         or remove, we must call hashdata_invert_stone(). This is
-   *         not difficult per se, but the whole board.c 
-   *         will have to be checked, and there is lots of room
-   *         for mistakes.
-   *
-   *         At the same time, profiling shows that storing the
-   *         hashdata in a stack doesn't take a lot of time, so
-   *         this is not an urgent FIXME.
-   */
+  /* Restoring a hash value is faster than xoring hash codes of all
+   * undone stones */
   memcpy(&board_hash_stack[stackp], &board_hash, sizeof(board_hash));
 
   if (board_ko_pos != NO_MOVE)
@@ -667,12 +874,17 @@
       return 0;
     
     /* 4. The location must not be the ko point, unless ignore_ko == 1. */
-    if (!ignore_ko && pos == board_ko_pos) {
+	if (!ignore_ko && pos == board_ko_pos) {
+      /*    The ko position is guaranteed to have all neighbors of the
+       *    same color, or off board. If that color is the same as the
+       *    move the ko is being filled, it is always allowed. This
+       *    could be tested with has_neighbor() but here a faster test
+       *    suffices.
+       */
       if (board[WEST(pos)] == OTHER_COLOR(color)
-	  || board[EAST(pos)] == OTHER_COLOR(color)) {
-	return 0;
-      }
-    }
+          || board[EAST(pos)] == OTHER_COLOR(color))
+        return 0;
+	}
 
     /* 5. Test for suicide. */
     if (is_suicide(pos, color))
@@ -684,9 +896,9 @@
     fprintf(stderr, 
 	    "gnugo: Truncating search. This is beyond my reading ability!\n");
     /* FIXME: Perhaps it's best to just assert here and be done with it? */
-    if (0) {
+#if 0
       ASSERT1(0 && "trymove stack overflow", pos);
-    }
+#endif
 #if 0
     if (verbose > 0) {
       showboard(0);
@@ -698,8 +910,10 @@
   }
 
 
+#ifndef GG_TURN_OFF_STATS
   /* Only count trymove when we do create a new position. */
   trymove_counter++;
+#endif
   
   /* So far, so good. Now push the move on the move stack. These are
    * needed for dump_stack().
@@ -722,6 +936,7 @@
 {
   undo_trymove();
   
+#ifndef GG_TURN_OFF_TRACES
   if (sgf_dumptree) {
     char buf[100];
     int is_tryko = 0;
@@ -742,6 +957,7 @@
     if (is_tryko)
       sgf_dumptree->lastnode = sgf_dumptree->lastnode->parent->parent;
   }
+#endif
 }
 
 
@@ -760,13 +976,16 @@
 {
   gg_assert(change_stack_pointer - change_stack <= STACK_SIZE);
 
-  if (0) {
-    gprintf("Change stack size = %d\n", change_stack_pointer - change_stack);
-    gprintf("Vertex stack size = %d\n", vertex_stack_pointer - vertex_stack);
-  }
+#if 0
+  gprintf("Change stack size = %d\n", change_stack_pointer - change_stack);
+#ifdef INT_INTERSECTION
+  gprintf("Intersection is int, so we don't use vertex stack (all is on change stack)\n");
+#else
+  gprintf("Vertex stack size = %d\n", vertex_stack_pointer - vertex_stack);
+#endif
+#endif
 
   POP_MOVE();
-  POP_VERTICES();
   
   stackp--;
   memcpy(&board_hash, &(board_hash_stack[stackp]), sizeof(board_hash));
@@ -1015,9 +1234,10 @@
 get_last_opponent_move(int color)
 {
   int k;
+  const int other = OTHER_COLOR(color);
   
   for (k = move_history_pointer - 1; k >= 0; k--)
-    if (move_history_color[k] == OTHER_COLOR(color))
+    if (move_history_color[k] == other)
       return move_history_pos[k];
 
   return PASS_MOVE;
@@ -1060,7 +1280,7 @@
 int
 is_pass(int pos)
 {
-  return pos == 0;
+  return pos == PASS_MOVE;
 }
 
 
@@ -1078,7 +1298,7 @@
 is_legal(int pos, int color)
 {
   /* 0. A pass move is always legal. */
-  if (pos == 0)
+  if (pos == PASS_MOVE)
     return 1;
 
   /* 1. The move must be inside the board. */
@@ -1092,14 +1312,13 @@
   if (pos == board_ko_pos) {
     /*    The ko position is guaranteed to have all neighbors of the
      *    same color, or off board. If that color is the same as the
-     *    move the ko is being filled, which is always allowed. This
+     *    move the ko is being filled, it is always allowed. This
      *    could be tested with has_neighbor() but here a faster test
      *    suffices.
      */
-    if (board[WEST(pos)] == OTHER_COLOR(color)
-	|| board[EAST(pos)] == OTHER_COLOR(color)) {
+    if (board[WEST(pos)] == OTHER_COLOR(color) 
+        || board[EAST(pos)] == OTHER_COLOR(color))
       return 0;
-    }
   }
 
   /* Check for stack overflow. */
@@ -1107,9 +1326,9 @@
     fprintf(stderr, 
 	    "gnugo: Truncating search. This is beyond my reading ability!\n");
     /* FIXME: Perhaps it's best to just assert here and be done with it? */
-    if (0) {
+#if 0
       ASSERT1(0 && "is_legal stack overflow", pos);
-    }
+#endif
     return 0;
   }
 
@@ -1133,28 +1352,38 @@
 int 
 is_suicide(int pos, int color)
 {
+  int checked_pos;
+  int stone;
   ASSERT_ON_BOARD1(pos);
   ASSERT1(board[pos] == EMPTY, pos);
 
   /* Check for suicide. */
-  if (LIBERTY(SOUTH(pos))
-      || (ON_BOARD(SOUTH(pos))
-	  && ((board[SOUTH(pos)] == color) ^ (LIBERTIES(SOUTH(pos)) == 1))))
+  checked_pos = SOUTH(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY
+      || (ON_BOARD(checked_pos)
+          && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
 
-  if (LIBERTY(WEST(pos))
-      || (ON_BOARD(WEST(pos))
-	  && ((board[WEST(pos)] == color) ^ (LIBERTIES(WEST(pos)) == 1))))
+  checked_pos = WEST(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY
+      || (ON_BOARD(checked_pos)
+          && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
 
-  if (LIBERTY(NORTH(pos))
-      || (ON_BOARD(NORTH(pos))
-	  && ((board[NORTH(pos)] == color) ^ (LIBERTIES(NORTH(pos)) == 1))))
+  checked_pos = NORTH(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY
+      || (ON_BOARD(checked_pos)
+          && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
 
-  if (LIBERTY(EAST(pos))
-      || (ON_BOARD(EAST(pos))
-	  && ((board[EAST(pos)] == color) ^ (LIBERTIES(EAST(pos)) == 1))))
+  checked_pos = EAST(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY
+      || (ON_BOARD(checked_pos)
+          && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
 
   return 1;
@@ -1172,6 +1401,12 @@
   ASSERT1(board[pos] == EMPTY, pos);
 
   return (pos == board_ko_pos
+    /*    The ko position is guaranteed to have all neighbors of the
+     *    same color, or off board. If that color is the same as the
+     *    move the ko is being filled, it is always allowed. This
+     *    could be tested with has_neighbor() but here a faster test
+     *    suffices.
+     */
 	  && ((board[WEST(pos)] == OTHER_COLOR(color))
 	      || (board[EAST(pos)] == OTHER_COLOR(color))));
 }
@@ -1209,10 +1444,17 @@
    *    suffices.
    */
   if (ko_rule != NONE
-      && pos == board_ko_pos
-      && (board[WEST(pos)] == OTHER_COLOR(color)
-	  || board[EAST(pos)] == OTHER_COLOR(color)))
-    return 0;
+	  && pos == board_ko_pos) {
+    /*    The ko position is guaranteed to have all neighbors of the
+     *    same color, or off board. If that color is the same as the
+     *    move the ko is being filled, it is always allowed. This
+     *    could be tested with has_neighbor() but here a faster test
+     *    suffices.
+     */
+      if (board[WEST(pos)] == OTHER_COLOR(color)
+          || board[EAST(pos)] == OTHER_COLOR(color))
+        return 0;
+  }
 
   /* 5. Check for suicide. Suicide rule options:
    *    FORBIDDEN   - No suicides allowed.
@@ -1231,8 +1473,9 @@
    *    SSK          - Repetition of a previous position with the same
    *                   player to move forbidden.
    */
-  if (is_superko_violation(pos, color, ko_rule))
-    return 0;
+  if (ko_rule != SIMPLE && ko_rule != NONE)
+    if (is_superko_violation(pos, color, ko_rule))
+      return 0;
   
   return 1;
 }
@@ -1265,9 +1508,6 @@
  * 3.5.1 four of them were removed to simplify the code and because it
  * no longer seemed interesting to be able to switch. The remaining
  * komaster scheme was previously known as komaster scheme 5 (or V).
- *
- * FIXME: This function could be optimized by integrating the
- * trymove()/tryko() code.
  */
 
 /* V. Complex scheme, O to move.
@@ -1284,68 +1524,89 @@
  * 2. Komaster is O:
  * 2a) Only nested ko captures are allowed. Kom_pos is moved to the
  *     new removed stone.
- * 2b) If komaster fills the ko at kom_pos then komaster reverts to
- *     EMPTY.
+ * 2b) If the ko has been resolved in favor of the komaster (when the ko is
+ *     filled or kom_pos is no longer a ko because of some capture) then the
+ *     komaster reverts to EMPTY.
  * 
  * 3. Komaster is X:
- *    Play at kom_pos is not allowed. Any other ko capture
- *    is allowed. If O takes another ko, komaster becomes GRAY_X.
+ *    Play at kom_pos is not allowed if it is the ko recapture. Any other
+ *    ko capture is allowed. If O takes another ko, komaster becomes GRAY_X.
  * 
  * 4. Komaster is GRAY_O or GRAY_X:
- *    Ko captures are not allowed. If the ko at kom_pos is
- *    filled then the komaster reverts to EMPTY.
+ *    Ko captures are not allowed. If the ko has been resolved in favor of
+ *    the komaster (when the ko is filled or kom_pos is no longer a ko because
+ *    of some capture) then the komaster reverts to EMPTY.
  *
  * 5. Komaster is WEAK_KO:
  * 5a) After a non-ko move komaster reverts to EMPTY.
  * 5b) Unconditional ko capture is only allowed if it is nested ko capture.
- *     Komaster is changed to WEAK_X and kom_pos to the old value of
- *     board_ko_pos.
+ *     Kom_pos is moved to the old value of board_ko_pos.
  * 5c) Conditional ko capture is allowed according to the rules of 1b.
  */
 int
 komaster_trymove(int pos, int color, const char *message, int str,
 		 int *is_conditional_ko, int consider_conditional_ko)
 {
-  int other = OTHER_COLOR(color);
   int ko_move;
   int kpos;
-  int previous_board_ko_pos = board_ko_pos;
+  int previous_board_ko_pos;
+  int ko_move_allowed;
+
+  UNUSED(str);
 
   *is_conditional_ko = 0;
   ko_move = is_ko(pos, color, &kpos);
 
   if (ko_move) {
-    /* If opponent is komaster we may not capture his ko. */
-    if (komaster == other && pos == kom_pos)
-      return 0;
-
-    /* If komaster is gray we may not capture ko at all. */
-    if (komaster == GRAY_WHITE || komaster == GRAY_BLACK)
-      return 0;
-
-    /* If we are komaster, we may only do nested captures. */
-    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 && !DIAGONAL_NEIGHBORS(kpos, kom_pos))
-	return 0;
+    switch (komaster) {
+      case EMPTY:
+        break;
+
+      case GRAY_WHITE:
+      case GRAY_BLACK:
+        /* If komaster is gray we may not capture ko at all. */
+        return 0;
+
+      case WEAK_KO:
+        /* If komaster is WEAK_KO, we may only do nested ko capture or
+         * conditional ko capture.
+         */
+        if (pos != board_ko_pos && !DIAGONAL_NEIGHBORS(kpos, kom_pos))
+	      return 0;
+        break;
+
+      default:
+        if (komaster == color) {
+          /* If we are komaster, we may only do nested captures. */
+          if (!DIAGONAL_NEIGHBORS(kpos, kom_pos))
+            return 0;
+        }
+        else { // komaster == OTHER_COLOR(color)
+          /* If opponent is komaster we may not capture his ko. */
+          if (pos == kom_pos)
+            return 0;
+        }
+        break;
     }
   }
 
-  if (!trymove(pos, color, message, str)) {
+  previous_board_ko_pos = board_ko_pos;
+
+  if (check_komaster_move(pos, color, &ko_move_allowed))
+    really_do_komastermove(pos, color, message, 0);
+  else {
+    /* Conditional ko capture */
     if (!consider_conditional_ko)
       return 0;
 
-    if (!tryko(pos, color, message))
+    if (!ko_move_allowed)
       return 0; /* Suicide. */
+
+    really_do_komastermove(pos, color, message, 1);
       
     *is_conditional_ko = 1;
 
-    /* Conditional ko capture, set komaster parameters. */
+    /* Conditional ko capture, set komaster parameters (1b and 5c). */
     if (komaster == EMPTY || komaster == WEAK_KO) {
       set_new_komaster(color);
       set_new_kom_pos(kpos);
@@ -1355,23 +1616,23 @@
 
   if (!ko_move) {
     /* If we are komaster, check whether the ko was resolved by the
-     * current move. If that is the case, revert komaster to EMPTY.
+     * current move. If that is the case, revert komaster to EMPTY (2b and 4).
      *
      * The ko has been resolved in favor of the komaster if it has
-     * been filled, or if it is no longer a ko and an opponent move
-     * there is suicide.
+     * been filled, or if an opponent move there is suicide (it is no
+     * longer a ko then).
      */
-    if (((komaster == color
+    if ((komaster == color
 	  || (komaster == GRAY_WHITE && color == WHITE)
 	  || (komaster == GRAY_BLACK && color == BLACK))
-	 && (IS_STONE(board[kom_pos])
-	     || (!is_ko(kom_pos, other, NULL)
-		 && is_suicide(kom_pos, other))))) {
+	 && (board[kom_pos] == color
+	     || (board[kom_pos] == EMPTY
+	         && is_suicide(kom_pos, OTHER_COLOR(color))))) {
       set_new_komaster(EMPTY);
       set_new_kom_pos(NO_MOVE);
     }
-
-    if (komaster == WEAK_KO) {
+    /* After the non-ko move set the komaster to EMPTY (5a). */
+    else if (komaster == WEAK_KO) {
       set_new_komaster(EMPTY);
       set_new_kom_pos(NO_MOVE);
     }
@@ -1379,19 +1640,20 @@
     return 1;
   }
 
-  if (komaster == other) {
+  if (komaster == OTHER_COLOR(color)) {
+    /* After a ko capture set komaster to GRAY_X (3). */
     if (color == WHITE)
       set_new_komaster(GRAY_BLACK);
     else
       set_new_komaster(GRAY_WHITE);
   }
   else if (komaster == color) {
-    /* This is where we update kom_pos after a nested capture. */
+    /* This is where we update kom_pos after a nested capture (2a). */
     set_new_kom_pos(kpos);
   }
   else {
     /* We can reach here when komaster is EMPTY or WEAK_KO. If previous
-     * move was also a ko capture, we now set komaster to WEAK_KO.
+     * move was also a ko capture, we now set komaster to WEAK_KO (1a and 5b).
      */
     if (previous_board_ko_pos != NO_MOVE) {
       set_new_komaster(WEAK_KO);
@@ -1451,8 +1713,8 @@
 }
 
 
-/* Returns true if the empty vertex respectively the string at pos1 is
- * adjacent to the empty vertex respectively the string at pos2.
+/* Returns true if the empty vertex or the string at pos1 is
+ * adjacent to the empty vertex or the string at pos2.
  */
 int
 are_neighbors(int pos1, int pos2)
@@ -1471,21 +1733,20 @@
   }
 }
 
-
-/* Count the number of liberties of the string at pos. pos must not be
- * empty.
+/* Count the number of liberties of the string at str_pos.
+ * str_pos must not be empty
  */
 int
-countlib(int str)
+countlib(int str_pos)
 {
-  ASSERT1(IS_STONE(board[str]), str);
-  
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
+
   /* We already know the number of liberties. Just look it up. */
-  return string[string_number[str]].liberties;
+  return string[string_number[str_pos]].liberties;
 }
 
 
-/* Find the liberties of the string at str. str must not be
+/* Find the liberties of the string at str_pos. str_pos must not be
  * empty. The locations of up to maxlib liberties are written into
  * libs[]. The full number of liberties is returned.
  *
@@ -1495,15 +1756,16 @@
  */
 
 int
-findlib(int str, int maxlib, int *libs)
+findlib(int str_pos, int maxlib, int *libs)
 {
   int k;
   int liberties;
-  int s;
-  
-  ASSERT1(IS_STONE(board[str]), str);
-  ASSERT1(libs != NULL, str);
-  
+  int to_copy;
+  int str_nr;
+
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
+  ASSERT1(libs != NULL, str_pos);
+
   /* We already have the list of liberties and only need to copy it to
    * libs[].
    *
@@ -1512,15 +1774,16 @@
    * we have to traverse the stones in the string in order to find
    * where the liberties are.
    */
-  s = string_number[str];
-  liberties = string[s].liberties;
+  str_nr = string_number[str_pos];
+  liberties = string[str_nr].liberties;
+  to_copy = maxlib > liberties ? liberties : maxlib;
 
   if (liberties <= MAX_LIBERTIES || maxlib <= MAX_LIBERTIES) {
     /* The easy case, it suffices to copy liberty locations from the
      * incrementally updated list.
      */
-    for (k = 0; k < maxlib && k < liberties; k++)
-      libs[k] = string_libs[s].list[k];
+    for (k = 0; k < to_copy; k++)
+      libs[k] = string_libs[str_nr].list[k];
   }
   else {
     /* The harder case, where we have to traverse the stones in the
@@ -1528,36 +1791,40 @@
      * the start of the chain since we will run out of liberties
      * before that happens.
      */
-    int pos;
+    int pos, checked_pos;
     liberty_mark++;
-    for (k = 0, pos = FIRST_STONE(s);
-	 k < maxlib && k < liberties;
+    for (k = 0, pos = FIRST_STONE(str_nr);
+	 k < to_copy;
 	 pos = NEXT_STONE(pos)) {
-      if (UNMARKED_LIBERTY(SOUTH(pos))) {
-	libs[k++] = SOUTH(pos);
-	MARK_LIBERTY(SOUTH(pos));
-	if (k >= maxlib)
+      checked_pos = SOUTH(pos);
+      if (UNMARKED_LIBERTY(checked_pos)) {
+	libs[k++] = checked_pos;
+	MARK_LIBERTY(checked_pos);
+	if (k >= to_copy)
 	  break;
       }
       
-      if (UNMARKED_LIBERTY(WEST(pos))) {
-	libs[k++] = WEST(pos);
-	MARK_LIBERTY(WEST(pos));
-	if (k >= maxlib)
+      checked_pos = WEST(pos);
+      if (UNMARKED_LIBERTY(checked_pos)) {
+	libs[k++] = checked_pos;
+	MARK_LIBERTY(checked_pos);
+	if (k >= to_copy)
 	  break;
       }
       
-      if (UNMARKED_LIBERTY(NORTH(pos))) {
-	libs[k++] = NORTH(pos);
-	MARK_LIBERTY(NORTH(pos));
-	if (k >= maxlib)
+      checked_pos = NORTH(pos);
+      if (UNMARKED_LIBERTY(checked_pos)) {
+	libs[k++] = checked_pos;
+	MARK_LIBERTY(checked_pos);
+	if (k >= to_copy)
 	  break;
       }
       
-      if (UNMARKED_LIBERTY(EAST(pos))) {
-	libs[k++] = EAST(pos);
-	MARK_LIBERTY(EAST(pos));
-	if (k >= maxlib)
+      checked_pos = EAST(pos);
+      if (UNMARKED_LIBERTY(checked_pos)) {
+	libs[k++] = checked_pos;
+	MARK_LIBERTY(checked_pos);
+	if (k >= to_copy)
 	  break;
       }
     }
@@ -1588,6 +1855,8 @@
   int ally1 = -1;
   int ally2 = -1;
   int fast_liberties = 0;
+  int checked_pos;
+  int str_nr;
 
   ASSERT1(board[pos] == EMPTY, pos);
   ASSERT1(IS_STONE(color), pos);
@@ -1599,23 +1868,23 @@
     ally1 = string_number[SOUTH(pos)];
 
     if (board[WEST(pos)] == color
-	&& string_number[WEST(pos)] != ally1) {
-      ally2 = string_number[WEST(pos)];
+	&& (str_nr = string_number[WEST(pos)]) != ally1) {
+      ally2 = str_nr;
 
       if (board[NORTH(pos)] == color
-	  && string_number[NORTH(pos)] != ally1
-	  && string_number[NORTH(pos)] != ally2)
+	  && (str_nr = string_number[NORTH(pos)]) != ally1
+	  && str_nr != ally2)
 	return -1;
     }
     else if (board[NORTH(pos)] == color
-	     && string_number[NORTH(pos)] != ally1)
-      ally2 = string_number[NORTH(pos)];
+	     && (str_nr = string_number[NORTH(pos)]) != ally1)
+      ally2 = str_nr;
 
-    if (board[EAST(pos)] == color
-	&& string_number[EAST(pos)] != ally1) {
+    if (board[checked_pos = EAST(pos)] == color
+	&& string_number[checked_pos] != ally1) {
       if (ally2 < 0)
-	ally2 = string_number[EAST(pos)];
-      else if (string_number[EAST(pos)] != ally2)
+	ally2 = string_number[checked_pos];
+      else if (string_number[checked_pos] != ally2)
 	return -1;
     }
   }
@@ -1623,24 +1892,24 @@
     ally1 = string_number[WEST(pos)];
 
     if (board[NORTH(pos)] == color
-	&& string_number[NORTH(pos)] != ally1) {
-      ally2 = string_number[NORTH(pos)];
+	&& (str_nr = string_number[NORTH(pos)]) != ally1) {
+      ally2 = str_nr;
 
       if (board[EAST(pos)] == color
-	  && string_number[EAST(pos)] != ally1
-	  && string_number[EAST(pos)] != ally2)
+	  && (str_nr = string_number[EAST(pos)]) != ally1
+	  && str_nr != ally2)
 	return -1;
     }
     else if (board[EAST(pos)] == color
-	     && string_number[EAST(pos)] != ally1)
-      ally2 = string_number[EAST(pos)];
+	     && (str_nr = string_number[EAST(pos)]) != ally1)
+      ally2 = str_nr;
   }
   else if (board[NORTH(pos)] == color) {
     ally1 = string_number[NORTH(pos)];
     
     if (board[EAST(pos)] == color
-	&& string_number[EAST(pos)] != ally1)
-      ally2 = string_number[EAST(pos)];
+	&& (str_nr = string_number[EAST(pos)]) != ally1)
+      ally2 = str_nr;
   }
   else if (board[EAST(pos)] == color)
     ally1 = string_number[EAST(pos)];
@@ -1674,21 +1943,25 @@
       fast_liberties += string[ally1].liberties - 1;
     }
     else {				/* Two allies */
-      if (LIBERTY(SOUTH(pos))
-	  && !NON_SOUTH_NEIGHBOR_OF_STRING(SOUTH(pos), ally1, color)
-	  && !NON_SOUTH_NEIGHBOR_OF_STRING(SOUTH(pos), ally2, color))
+      int checked_pos = SOUTH(pos);
+      if (LIBERTY(checked_pos)
+	  && !NON_SOUTH_NEIGHBOR_OF_STRING(checked_pos, ally1, color)
+	  && !NON_SOUTH_NEIGHBOR_OF_STRING(checked_pos, ally2, color))
 	fast_liberties++;
-      if (LIBERTY(WEST(pos))
-	  && !NON_WEST_NEIGHBOR_OF_STRING(WEST(pos), ally1, color)
-	  && !NON_WEST_NEIGHBOR_OF_STRING(WEST(pos), ally2, color))
+      checked_pos = WEST(pos);
+      if (LIBERTY(checked_pos)
+	  && !NON_WEST_NEIGHBOR_OF_STRING(checked_pos, ally1, color)
+	  && !NON_WEST_NEIGHBOR_OF_STRING(checked_pos, ally2, color))
 	fast_liberties++;
-      if (LIBERTY(NORTH(pos))
-	  && !NON_NORTH_NEIGHBOR_OF_STRING(NORTH(pos), ally1, color)
-	  && !NON_NORTH_NEIGHBOR_OF_STRING(NORTH(pos), ally2, color))
+      checked_pos = NORTH(pos);
+      if (LIBERTY(checked_pos)
+	  && !NON_NORTH_NEIGHBOR_OF_STRING(checked_pos, ally1, color)
+	  && !NON_NORTH_NEIGHBOR_OF_STRING(checked_pos, ally2, color))
 	fast_liberties++;
-      if (LIBERTY(EAST(pos))
-	  && !NON_EAST_NEIGHBOR_OF_STRING(EAST(pos), ally1, color)
-	  && !NON_EAST_NEIGHBOR_OF_STRING(EAST(pos), ally2, color))
+      checked_pos = EAST(pos);
+      if (LIBERTY(checked_pos)
+	  && !NON_EAST_NEIGHBOR_OF_STRING(checked_pos, ally1, color)
+	  && !NON_EAST_NEIGHBOR_OF_STRING(checked_pos, ally2, color))
 	fast_liberties++;
 
       fast_liberties += string[ally1].liberties + string[ally2].liberties
@@ -1700,17 +1973,18 @@
    */
   else {
     int k;
+    int other = OTHER_COLOR(color);
 
     for (k = 0; k < 4; k++) {
-      int neighbor = pos + delta[k];
+      int neighbor_pos = pos + delta[k];
 
-      if (LIBERTY(neighbor)
-	  && (ally1 < 0 || !NEIGHBOR_OF_STRING(neighbor, ally1, color))
-	  && (ally2 < 0 || !NEIGHBOR_OF_STRING(neighbor, ally2, color)))
+      if (LIBERTY(neighbor_pos)
+	  && (ally1 < 0 || !NEIGHBOR_OF_STRING(neighbor_pos, ally1, color))
+	  && (ally2 < 0 || !NEIGHBOR_OF_STRING(neighbor_pos, ally2, color)))
 	fast_liberties++;
-      else if (board[neighbor] == OTHER_COLOR(color)	/* A capture */
-	       && LIBERTIES(neighbor) == 1) {
-	int neighbor_size = COUNTSTONES(neighbor);
+      else if (board[neighbor_pos] == other
+               && LIBERTIES(string_number[neighbor_pos]) == 1) { /* A capture */
+	int neighbor_size = COUNTSTONES(string_number[neighbor_pos]);
 
 	if (neighbor_size == 1 || (neighbor_size == 2 && ally1 < 0))
 	  fast_liberties++;
@@ -1722,7 +1996,7 @@
     if (ally1 >= 0) {
       fast_liberties += string[ally1].liberties - 1;
       if (ally2 >= 0)
-	fast_liberties += string[ally2].liberties
+    fast_liberties += string[ally2].liberties
 	  - count_common_libs(string[ally1].origin, string[ally2].origin);
     }
   }
@@ -1730,18 +2004,9 @@
   return fast_liberties;
 }
 
+#define USE_BOARD_CACHES 1
 
-/* Effectively true unless we store full position in hash. */
-#define USE_BOARD_CACHES	(NUM_HASHVALUES <= 4)
-
-struct board_cache_entry {
-  int threshold;
-  int liberties;
-  Hash_data position_hash;
-};
-
-
-/* approxlib() cache. */
+/* approxlib() cache. Stores data for both colors */
 static struct board_cache_entry approxlib_cache[BOARDMAX][2];
 
 
@@ -1751,12 +2016,7 @@
 void
 clear_approxlib_cache(void)
 {
-  int pos;
-
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    approxlib_cache[pos][0].threshold = 0;
-    approxlib_cache[pos][1].threshold = 0;
-  }
+  memset(approxlib_cache, 0, sizeof(approxlib_cache));
 }
 
 
@@ -1778,7 +2038,7 @@
 
 #ifdef USE_BOARD_CACHES
 
-  struct board_cache_entry *entry = &approxlib_cache[pos][color - 1];
+  struct board_cache_entry *entry = &approxlib_cache[pos][color - WHITE];
 
   ASSERT1(board[pos] == EMPTY, pos);
   ASSERT1(IS_STONE(color), pos);
@@ -1812,9 +2072,9 @@
   entry->threshold = maxlib;
 
   if (maxlib <= MAX_LIBERTIES)
-    liberties = do_approxlib(pos, color, maxlib, libs);
+    liberties = do_approxlib(pos, color, maxlib, libs, entry);
   else
-    liberties = slow_approxlib(pos, color, maxlib, libs);
+    liberties = slow_approxlib(pos, color, maxlib, libs, entry);
 
   entry->liberties = liberties;
   entry->position_hash = board_hash;
@@ -1842,11 +2102,13 @@
 
 
 /* Does the real work of approxlib(). */
-static int
-do_approxlib(int pos, int color, int maxlib, int *libs)
+inline static int
+do_approxlib(int pos, int color, int maxlib, int *libs,
+             struct board_cache_entry *entry)
 {
   int k;
   int liberties = 0;
+  int checked_pos, str_nr, str_libs, checked_lib;
 
   /* Look for empty neighbors and the liberties of the adjacent
    * strings of the given color. The algorithm below won't work
@@ -1862,112 +2124,128 @@
   liberty_mark++;
   MARK_LIBERTY(pos);
 
-  if (UNMARKED_LIBERTY(SOUTH(pos))) {
-    if (libs != NULL)
-      libs[liberties] = SOUTH(pos);
-    liberties++;
-    /* Stop counting if we reach maxlib. */
-    if (liberties >= maxlib)
-      return liberties;
-    MARK_LIBERTY(SOUTH(pos));
+  checked_pos = SOUTH(pos);
+  if (board[checked_pos] == EMPTY) {
+    if (ml[checked_pos] != liberty_mark) {
+      if (libs != NULL)
+        libs[liberties] = checked_pos;
+      liberties++;
+      /* Stop counting if we reach maxlib. */
+      if (liberties >= maxlib)
+        return liberties;
+      MARK_LIBERTY(checked_pos);
+    }
   }
-  else if (board[SOUTH(pos)] == color) {
-    int s = string_number[SOUTH(pos)];
-    for (k = 0; k < string[s].liberties; k++) {
-      int lib = string_libs[s].list[k];
-      if (UNMARKED_LIBERTY(lib)) {
+  else if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    str_libs = string[str_nr].liberties;
+    for (k = 0; k < str_libs; k++) {
+      checked_lib = string_libs[str_nr].list[k];
+      if (UNMARKED_LIBERTY(checked_lib)) {
 	if (libs != NULL)
-	  libs[liberties] = lib;
+	  libs[liberties] = checked_lib;
 	liberties++;
 	if (liberties >= maxlib)
 	  return liberties;
-	MARK_LIBERTY(lib);
+	MARK_LIBERTY(checked_lib);
       }
     }
   }
   
-  if (UNMARKED_LIBERTY(WEST(pos))) {
-    if (libs != NULL)
-      libs[liberties] = WEST(pos);
-    liberties++;
-    /* Stop counting if we reach maxlib. */
-    if (liberties >= maxlib)
-      return liberties;
-    MARK_LIBERTY(WEST(pos));
+  checked_pos = WEST(pos);
+  if (board[checked_pos] == EMPTY) {
+    if (ml[checked_pos] != liberty_mark) {
+      if (libs != NULL)
+        libs[liberties] = checked_pos;
+      liberties++;
+      /* Stop counting if we reach maxlib. */
+      if (liberties >= maxlib)
+        return liberties;
+      MARK_LIBERTY(checked_pos);
+    }
   }
-  else if (board[WEST(pos)] == color) {
-    int s = string_number[WEST(pos)];
-    for (k = 0; k < string[s].liberties; k++) {
-      int lib = string_libs[s].list[k];
-      if (UNMARKED_LIBERTY(lib)) {
+  else if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    str_libs = string[str_nr].liberties;
+    for (k = 0; k < str_libs; k++) {
+      checked_lib = string_libs[str_nr].list[k];
+      if (UNMARKED_LIBERTY(checked_lib)) {
 	if (libs != NULL)
-	  libs[liberties] = lib;
+	  libs[liberties] = checked_lib;
 	liberties++;
 	if (liberties >= maxlib)
 	  return liberties;
-	MARK_LIBERTY(lib);
+	MARK_LIBERTY(checked_lib);
       }
     }
   }
   
-  if (UNMARKED_LIBERTY(NORTH(pos))) {
-    if (libs != NULL)
-      libs[liberties] = NORTH(pos);
-    liberties++;
-    /* Stop counting if we reach maxlib. */
-    if (liberties >= maxlib)
-      return liberties;
-    MARK_LIBERTY(NORTH(pos));
+  checked_pos = NORTH(pos);
+  if (board[checked_pos] == EMPTY) {
+    if (ml[checked_pos] != liberty_mark) {
+      if (libs != NULL)
+        libs[liberties] = checked_pos;
+      liberties++;
+      /* Stop counting if we reach maxlib. */
+      if (liberties >= maxlib)
+        return liberties;
+      MARK_LIBERTY(checked_pos);
+    }
   }
-  else if (board[NORTH(pos)] == color) {
-    int s = string_number[NORTH(pos)];
-    for (k = 0; k < string[s].liberties; k++) {
-      int lib = string_libs[s].list[k];
-      if (UNMARKED_LIBERTY(lib)) {
+  else if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    str_libs = string[str_nr].liberties;
+    for (k = 0; k < str_libs; k++) {
+      checked_lib = string_libs[str_nr].list[k];
+      if (UNMARKED_LIBERTY(checked_lib)) {
 	if (libs != NULL)
-	  libs[liberties] = lib;
+	  libs[liberties] = checked_lib;
 	liberties++;
 	if (liberties >= maxlib)
 	  return liberties;
-	MARK_LIBERTY(lib);
+	MARK_LIBERTY(checked_lib);
       }
     }
   }
-  
-  if (UNMARKED_LIBERTY(EAST(pos))) {
-    if (libs != NULL)
-      libs[liberties] = EAST(pos);
-    liberties++;
-    /* Unneeded since we're about to leave. */
+
+  checked_pos = EAST(pos);
+  if (board[checked_pos] == EMPTY) {
+    if (ml[checked_pos] != liberty_mark) {
+      if (libs != NULL)
+        libs[liberties] = checked_pos;
+      liberties++;
+/* Unneeded since we're about to leave. */
 #if 0
-    if (liberties >= maxlib)
-      return liberties;
-    MARK_LIBERTY(EAST(pos));
+      if (liberties >= maxlib)
+        return liberties;
+      MARK_LIBERTY(checked_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_libs[s].list[k];
-      if (UNMARKED_LIBERTY(lib)) {
+  else if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    str_libs = string[str_nr].liberties;
+    for (k = 0; k < str_libs; k++) {
+      checked_lib = string_libs[str_nr].list[k];
+      if (UNMARKED_LIBERTY(checked_lib)) {
 	if (libs != NULL)
-	  libs[liberties] = lib;
+	  libs[liberties] = checked_lib;
 	liberties++;
 	if (liberties >= maxlib)
 	  return liberties;
-	MARK_LIBERTY(lib);
+	MARK_LIBERTY(checked_lib);
       }
     }
-  }  
+  }
 
 #if USE_BOARD_CACHES
   /* If we reach here, then we have counted _all_ the liberties, so
    * we set threshold to MAXLIBS (the result is the same regardless
    * of `maxlib' value).
    */
-  if (!libs)
-    approxlib_cache[pos][color - 1].threshold = MAXLIBS;
+  entry->threshold = MAXLIBS;
 #endif
+
   return liberties;
 }
 
@@ -1977,47 +2255,52 @@
  * strings. This is a fallback used by approxlib() when a faster
  * algorithm can't be used.
  */
-static int
-slow_approxlib(int pos, int color, int maxlib, int *libs)
+inline static int
+slow_approxlib(int pos, int color, int maxlib, int *libs,
+               struct board_cache_entry *entry)
 {
   int k;
   int liberties = 0;
+  int checked_pos, checked_pos2;
+  int pos2, str_nr, first_stone;
 
   liberty_mark++;
   MARK_LIBERTY(pos);
   string_mark++;
+
   for (k = 0; k < 4; k++) {
-    int d = delta[k];
-    if (UNMARKED_LIBERTY(pos + d)) {
-      if (libs)
-	libs[liberties] = pos + d;
-      liberties++;
-      if (liberties == maxlib)
-	return liberties;
-      MARK_LIBERTY(pos + d);
-    }
-    else if (board[pos + d] == color
-	     && UNMARKED_STRING(pos + d)) {
-      int s = string_number[pos + d];
-      int pos2;
-      pos2 = FIRST_STONE(s);
+    checked_pos = pos + delta[k];
+    if (board[checked_pos] == EMPTY) {
+      if (ml[checked_pos] != liberty_mark) {
+        if (libs)
+          libs[liberties] = checked_pos;
+        liberties++;
+        if (liberties >= maxlib)
+          return liberties;
+        MARK_LIBERTY(checked_pos);
+      }
+    }
+    else if (board[checked_pos] == color
+             && UNMARKED_STRING(str_nr = string_number[checked_pos])) {
+      first_stone = FIRST_STONE(str_nr);
+      pos2 = first_stone;
       do {
 	int l;
 	for (l = 0; l < 4; l++) {
-	  int d2 = delta[l];
-	  if (UNMARKED_LIBERTY(pos2 + d2)) {
+	  checked_pos2 = pos2 + delta[l];
+	  if (UNMARKED_LIBERTY(checked_pos2)) {
 	    if (libs)
-	      libs[liberties] = pos2 + d2;
+	      libs[liberties] = checked_pos2;
 	    liberties++;
-	    if (liberties == maxlib)
+	    if (liberties >= maxlib)
 	      return liberties;
-	    MARK_LIBERTY(pos2 + d2);
+	    MARK_LIBERTY(checked_pos2);
 	  }
 	}
 
 	pos2 = NEXT_STONE(pos2);
-      } while (!BACK_TO_FIRST_STONE(s, pos2));
-      MARK_STRING(pos + d);
+      } while (pos2 != first_stone);
+      MARK_STRING(str_nr);
     }
   }
 
@@ -2026,14 +2309,13 @@
    * we set threshold to MAXLIBS (the result is the same regardless
    * of `maxlib' value).
    */
-  if (!libs)
-    approxlib_cache[pos][color - 1].threshold = MAXLIBS;
+  entry->threshold = MAXLIBS;
 #endif
   return liberties;
 }
 
 
-/* accuratelib() cache. */
+/* accuratelib() cache. Stores data for both colors */
 static struct board_cache_entry accuratelib_cache[BOARDMAX][2];
 
 
@@ -2043,12 +2325,7 @@
 void
 clear_accuratelib_cache(void)
 {
-  int pos;
-
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    accuratelib_cache[pos][0].threshold = 0;
-    accuratelib_cache[pos][1].threshold = 0;
-  }
+  memset(accuratelib_cache, 0, sizeof(accuratelib_cache));
 }
 
 
@@ -2076,7 +2353,7 @@
 
 #ifdef USE_BOARD_CACHES
 
-  struct board_cache_entry *entry = &accuratelib_cache[pos][color - 1];
+  struct board_cache_entry *entry = &accuratelib_cache[pos][color - WHITE];
 
   ASSERT1(board[pos] == EMPTY, pos);
   ASSERT1(IS_STONE(color), pos);
@@ -2102,13 +2379,14 @@
     }
   }
 
-  liberties = do_accuratelib(pos, color, maxlib, libs);
-
-  /* If accuratelib() found less than `maxlib' liberties, then its
-   * result is certainly independent of `maxlib' and we set threshold
-   * to MAXLIBS.
+  /* We initialize the cache entry threshold to `maxlib'. If do_accuratelib()
+   * finds all the liberties (that is, it doesn't use `maxlib' value for
+   * an early return), it will set threshold to MAXLIBS itself.
    */
-  entry->threshold = liberties < maxlib ? MAXLIBS : maxlib;
+  entry->threshold = maxlib;
+
+  liberties = do_accuratelib(pos, color, maxlib, libs, entry);
+
   entry->liberties = liberties;
   entry->position_hash = board_hash;
 
@@ -2132,137 +2410,155 @@
 
 
 /* Does the real work of accuratelib(). */
-static int
-do_accuratelib(int pos, int color, int maxlib, int *libs)
+inline static int
+do_accuratelib(int pos, int color, int maxlib, int *libs,
+               struct board_cache_entry *entry)
 {
   int k, l;
-  int liberties = 0;
+  int lib_count = 0;
   int lib;
   int captured[4];
   int captures = 0;
+  int first_stone;
+  int stone_pos;
+  int checked_lib;
 
   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;
+    int checked_pos = pos + delta[k];
+    if (board[checked_pos] == EMPTY) {
+      if (ml[checked_pos] != liberty_mark) {
+        /* A trivial liberty */
+        if (libs)
+          libs[lib_count] = checked_pos;
+        lib_count++;
+        if (lib_count >= maxlib)
+          return lib_count;
 
-      MARK_LIBERTY(pos2);
-    }
-    else if (UNMARKED_COLOR_STRING(pos2, color)) {
-      /* An own neighbor string */
-      struct string_data *s = &string[string_number[pos2]];
-      struct string_liberties_data *sl = &string_libs[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 = sl->list[l];
-	  if (UNMARKED_LIBERTY(lib)) {
-	    if (libs)
-	      libs[liberties] = lib;
-	    liberties++;
-	    if (liberties >= maxlib)
-	      return liberties;
-
-	    MARK_LIBERTY(lib);
-	  }
-	}
+        MARK_LIBERTY(checked_pos);
       }
-      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;
+    }
+    else if (board[checked_pos] == color) {
+      int neighbor_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(neighbor_nr)) {
+        /* An own neighbor string */
+        int liberties = string[neighbor_nr].liberties;
+
+        if (liberties <= MAX_LIBERTIES || maxlib <= MAX_LIBERTIES - 1) {
+	  /* The easy case - we already have all (necessary) liberties of
+	   * the string listed
+	   */
+	  struct string_liberties_data *sl = string_libs + neighbor_nr;
+	  for (l = 0; l < liberties; l++) {
+	    lib = sl->list[l];
+	    if (UNMARKED_LIBERTY(lib)) {
+	      if (libs)
+	        libs[lib_count] = lib;
+	      lib_count++;
+	      if (lib_count >= maxlib)
+	        return lib_count;
 
-	    MARK_LIBERTY(EAST(stone));
+	      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.
+	   */
+	  stone_pos = checked_pos;
+	  do {
+	    checked_lib = SOUTH(stone_pos);
+	    if (UNMARKED_LIBERTY(checked_lib)) {
+	      if (libs)
+	        libs[lib_count] = checked_lib;
+	      lib_count++;
+	      if (lib_count >= maxlib)
+	        return lib_count;
+
+	      MARK_LIBERTY(checked_lib);
+	    }
+
+	    checked_lib = WEST(stone_pos);
+	    if (UNMARKED_LIBERTY(checked_lib)) {
+	      if (libs)
+	        libs[lib_count] = checked_lib;
+	      lib_count++;
+	      if (lib_count >= maxlib)
+	        return lib_count;
+
+	      MARK_LIBERTY(checked_lib);
+	    }
+
+	    checked_lib = NORTH(stone_pos);
+	    if (UNMARKED_LIBERTY(checked_lib)) {
+	      if (libs)
+	        libs[lib_count] = checked_lib;
+	      lib_count++;
+	      if (lib_count >= maxlib)
+	        return lib_count;
+
+	      MARK_LIBERTY(checked_lib);
+	    }
+
+	    checked_lib = EAST(stone_pos);
+	    if (UNMARKED_LIBERTY(checked_lib)) {
+	      if (libs)
+	        libs[lib_count] = checked_lib;
+	      lib_count++;
+	      if (lib_count >= maxlib)
+	        return lib_count;
+
+	      MARK_LIBERTY(checked_lib);
+	    }
+
+	    stone_pos = NEXT_STONE(stone_pos);
+	  } while (stone_pos != checked_pos);
+        }
 
-	  stone = NEXT_STONE(stone);
-	} while (stone != pos2);
+        MARK_STRING(neighbor_nr);
       }
-
-      MARK_STRING(pos2);
     }
-    else if (board[pos2] == OTHER_COLOR(color)
-	     && string[string_number[pos2]].liberties == 1) {
+    else if (board[checked_pos] == OTHER_COLOR(color)
+             && string[string_number[checked_pos]].liberties == 1) {
       /* A capture. */
-      captured[captures++] = pos2;
+      captured[captures++] = checked_pos;
     }
   }
 
   /* Now we look at all the captures found in the previous step */
   for (k = 0; k < captures; k++) {
-    lib = captured[k];
+    int capture_nr;
+    first_stone = 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 (!MARKED_COLOR_STRING(SOUTH(first_stone), color)
+	&& !MARKED_COLOR_STRING(WEST(first_stone), color)
+	&& !MARKED_COLOR_STRING(NORTH(first_stone), color)
+	&& !MARKED_COLOR_STRING(EAST(first_stone), color)) {
       if (libs)
-	libs[liberties] = lib;
-      liberties++;
-      if (liberties >= maxlib)
-	return liberties;
+	libs[lib_count] = first_stone;
+      lib_count++;
+      if (lib_count >= maxlib)
+	return lib_count;
+      stone_pos = NEXT_STONE(first_stone);
+      if (stone_pos == first_stone)
+        continue;
     }
+    else
+      stone_pos = first_stone;
 
     /* Check if we already know of this capture. */
+    capture_nr = string_number[stone_pos];
     for (l = 0; l < k; l++)
-      if (string_number[captured[l]] == string_number[lib])
+      if (string_number[captured[l]] == capture_nr)
 	break;
 
     if (l == k) {
@@ -2271,58 +2567,70 @@
        * 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 (MARKED_COLOR_STRING(SOUTH(stone_pos), color)
+	    || MARKED_COLOR_STRING(WEST(stone_pos), color)
+	    || MARKED_COLOR_STRING(NORTH(stone_pos), color)
+	    || MARKED_COLOR_STRING(EAST(stone_pos), color)) {
 	  if (libs)
-	    libs[liberties] = lib;
-	  liberties++;
-	  if (liberties >= maxlib)
-	    return liberties;
+	    libs[lib_count] = stone_pos;
+	  lib_count++;
+	  if (lib_count >= maxlib)
+	    return lib_count;
 	}
 
-	lib = NEXT_STONE(lib);
-      } while (lib != captured[k]);
+	stone_pos = NEXT_STONE(stone_pos);
+      } while (stone_pos != first_stone);
     }
   }
 
-  return liberties;
-}
+#if USE_BOARD_CACHES
+  /* If we reach here, then we have counted _all_ the liberties, so
+   * we set threshold to MAXLIBS (the result is the same regardless
+   * of `maxlib' value).
+   */
+  entry->threshold = MAXLIBS;
+#endif
 
+  return lib_count;
+}
 
-/* Find the number of common liberties of the two strings at str1 and str2.
+/* Find the number of common liberties of the two strings at
+ * str1_pos and str2_pos.
  */
 
 int
-count_common_libs(int str1, int str2)
+count_common_libs(int str1_pos, int str2_pos)
 {
   int all_libs1[MAXLIBS], *libs1;
   int liberties1, liberties2;
+  int str1_nr, str2_nr;
   int commonlibs = 0;
-  int k, n, tmp;
-  
-  ASSERT_ON_BOARD1(str1);
-  ASSERT_ON_BOARD1(str2);
-  ASSERT1(IS_STONE(board[str1]), str1);
-  ASSERT1(IS_STONE(board[str2]), str2);
-  
-  n = string_number[str1];
-  liberties1 = string[n].liberties;
-  
-  if (liberties1 > string[string_number[str2]].liberties) {
-    n = string_number[str2];
-    liberties1 = string[n].liberties;
-    tmp = str1;
-    str1 = str2;
-    str2 = tmp;
+  int k;
+  int color;
+
+  ASSERT_ON_BOARD1(str1_pos);
+  ASSERT_ON_BOARD1(str2_pos);
+  ASSERT1(IS_STONE(board[str1_pos]), str1_pos);
+  ASSERT1(IS_STONE(board[str2_pos]), str2_pos);
+
+  str1_nr = string_number[str1_pos];
+  str2_nr = string_number[str2_pos];
+  liberties1 = string[str1_nr].liberties;
+  liberties2 = string[str2_nr].liberties;
+  
+  if (liberties1 > liberties2) {
+    int tmp;
+    tmp = liberties1;
+    liberties1 = liberties2;
+    liberties2 = tmp;
+    tmp = str1_nr;
+    str1_nr = str2_nr;
+    str2_nr = tmp;
   }
 
   if (liberties1 <= MAX_LIBERTIES) {
     /* Speed optimization: don't copy liberties with findlib */
-    libs1 = string_libs[n].list;
-    n = string_number[str2];
-    liberties2 = string[n].liberties;
+    libs1 = string_libs[str1_nr].list;
     
     if (liberties2 <= MAX_LIBERTIES) {
       /* Speed optimization: NEIGHBOR_OF_STRING is quite expensive */
@@ -2331,30 +2639,30 @@
       for (k = 0; k < liberties1; k++)
 	MARK_LIBERTY(libs1[k]);
 
-      libs1 = string_libs[n].list;
+      libs1 = string_libs[str2_nr].list;
       for (k = 0; k < liberties2; k++)
-	if (!UNMARKED_LIBERTY(libs1[k]))
+	if (ml[libs1[k]] == liberty_mark)
 	  commonlibs++;
 
       return commonlibs;
     }
   }
   else {
-    findlib(str1, MAXLIBS, all_libs1);
+    findlib(str1_pos, MAXLIBS, all_libs1);
     libs1 = all_libs1;
   }
   
+  color = string[str2_nr].color;
   for (k = 0; k < liberties1; k++)
-    if (NEIGHBOR_OF_STRING(libs1[k], string_number[str2], board[str2]))
+    if (NEIGHBOR_OF_STRING(libs1[k], str2_nr, color))
       commonlibs++;
   
   return commonlibs;
 }
 
-
-/* Find the common liberties of the two strings at str1 and str2. The
- * locations of up to maxlib common liberties are written into libs[].
- * The full number of common liberties is returned.
+/* Find the common liberties of the two strings at str1_pos and
+ * str2_pos. The locations of up to maxlib common liberties are
+ * written into libs[]. The full number of common liberties is returned.
  *
  * If you want the locations of all common liberties, whatever their
  * number, you should pass MAXLIBS as the value for maxlib and
@@ -2362,35 +2670,39 @@
  */
 
 int
-find_common_libs(int str1, int str2, int maxlib, int *libs)
+find_common_libs(int str1_pos, int str2_pos, int maxlib, int *libs)
 {
   int all_libs1[MAXLIBS], *libs1;
   int liberties1, liberties2;
+  int str1_nr, str2_nr;
   int commonlibs = 0;
-  int k, n, tmp;
-  
-  ASSERT_ON_BOARD1(str1);
-  ASSERT_ON_BOARD1(str2);
-  ASSERT1(IS_STONE(board[str1]), str1);
-  ASSERT1(IS_STONE(board[str2]), str2);
-  ASSERT1(libs != NULL, str1);
-  
-  n = string_number[str1];
-  liberties1 = string[n].liberties;
-  
-  if (liberties1 > string[string_number[str2]].liberties) {
-    n = string_number[str2];
-    liberties1 = string[n].liberties;
-    tmp = str1;
-    str1 = str2;
-    str2 = tmp;
+  int k;
+  int color;
+
+  ASSERT_ON_BOARD1(str1_pos);
+  ASSERT_ON_BOARD1(str2_pos);
+  ASSERT1(IS_STONE(board[str1_pos]), str1_pos);
+  ASSERT1(IS_STONE(board[str2_pos]), str2_pos);
+  ASSERT1(libs != NULL, str1_pos);
+
+  str1_nr = string_number[str1_pos];
+  str2_nr = string_number[str2_pos];
+  liberties1 = string[str1_nr].liberties;
+  liberties2 = string[str2_nr].liberties;
+  
+  if (liberties1 > liberties2) {
+    int tmp;
+    tmp = liberties1;
+    liberties1 = liberties2;
+    liberties2 = tmp;
+    tmp = str1_nr;
+    str1_nr = str2_nr;
+    str2_nr = tmp;
   }
   
   if (liberties1 <= MAX_LIBERTIES) {
     /* Speed optimization: don't copy liberties with findlib */
-    libs1 = string_libs[n].list;
-    n = string_number[str2];
-    liberties2 = string[n].liberties;
+    libs1 = string_libs[str1_nr].list;
 
     if (liberties2 <= MAX_LIBERTIES) {
       /* Speed optimization: NEIGHBOR_OF_STRING is quite expensive */
@@ -2399,9 +2711,9 @@
       for (k = 0; k < liberties1; k++)
 	MARK_LIBERTY(libs1[k]);
       
-      libs1 = string_libs[n].list;
+      libs1 = string_libs[str2_nr].list;
       for (k = 0; k < liberties2; k++)
-	if (!UNMARKED_LIBERTY(libs1[k])) {
+	if (ml[libs1[k]] == liberty_mark) {
           if (commonlibs < maxlib)
 	    libs[commonlibs] = libs1[k];
 	  commonlibs++;
@@ -2411,12 +2723,13 @@
     }
   }
   else {
-    findlib(str1, MAXLIBS, all_libs1);
+    findlib(str1_pos, MAXLIBS, all_libs1);
     libs1 = all_libs1;
   }
   
+  color = string[str2_nr].color;
   for (k = 0; k < liberties1; k++)
-    if (NEIGHBOR_OF_STRING(libs1[k], string_number[str2], board[str2])) {
+    if (NEIGHBOR_OF_STRING(libs1[k], str2_nr, color)) {
       if (commonlibs < maxlib)
 	libs[commonlibs] = libs1[k];
       commonlibs++;
@@ -2430,38 +2743,45 @@
  * If they do and lib != NULL, one common liberty is returned in *lib.
  */
 int
-have_common_lib(int str1, int str2, int *lib)
+have_common_lib(int str1_pos, int str2_pos, int *lib)
 {
   int all_libs1[MAXLIBS], *libs1;
-  int liberties1;
-  int k, n, tmp;
-  
-  ASSERT_ON_BOARD1(str1);
-  ASSERT_ON_BOARD1(str2);
-  ASSERT1(IS_STONE(board[str1]), str1);
-  ASSERT1(IS_STONE(board[str2]), str2);
-  
-  n = string_number[str1];
-  liberties1 = string[n].liberties;
-  
-  if (liberties1 > string[string_number[str2]].liberties) {
-    n = string_number[str2];
-    liberties1 = string[n].liberties;
-    tmp = str1;
-    str1 = str2;
-    str2 = tmp;
+  int liberties1, liberties2;
+  int str1_nr, str2_nr;
+  int k;
+  int color;
+
+  ASSERT_ON_BOARD1(str1_pos);
+  ASSERT_ON_BOARD1(str2_pos);
+  ASSERT1(IS_STONE(board[str1_pos]), str1_pos);
+  ASSERT1(IS_STONE(board[str2_pos]), str2_pos);
+
+  str1_nr = string_number[str1_pos];
+  str2_nr = string_number[str2_pos];
+  liberties1 = string[str1_nr].liberties;
+  liberties2 = string[str2_nr].liberties;
+  
+  if (liberties1 > liberties2) {
+    int tmp;
+    tmp = liberties1;
+    liberties1 = liberties2;
+    liberties2 = tmp;
+    tmp = str1_nr;
+    str1_nr = str2_nr;
+    str2_nr = tmp;
   }
   
   if (liberties1 <= MAX_LIBERTIES)
     /* Speed optimization: don't copy liberties with findlib */
-    libs1 = string_libs[n].list;
+    libs1 = string_libs[str1_nr].list;
   else {
-    findlib(str1, MAXLIBS, all_libs1);
+    findlib(str1_pos, MAXLIBS, all_libs1);
     libs1 = all_libs1;
   }
 
+  color = string[str2_nr].color;
   for (k = 0; k < liberties1; k++) {
-    if (NEIGHBOR_OF_STRING(libs1[k], string_number[str2], board[str2])) {
+    if (NEIGHBOR_OF_STRING(libs1[k], str2_nr, color)) {
       if (lib)
 	*lib = libs1[k];
       return 1;
@@ -2478,37 +2798,39 @@
  */
 
 int
-countstones(int str)
+countstones(int str_pos)
 {
-  ASSERT_ON_BOARD1(str);
-  ASSERT1(IS_STONE(board[str]), str);
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
-  return COUNTSTONES(str);
+  return COUNTSTONES(string_number[str_pos]);
 }
 
 
-/* Find the stones of the string at str. str must not be
+/* Find the stones of the string at str_pos. str_pos must not be
  * empty. The locations of up to maxstones stones are written into
  * stones[]. The full number of stones is returned.
  */
 
 int
-findstones(int str, int maxstones, int *stones)
+findstones(int str_pos, int maxstones, int *stones)
 {
-  int s;
+  int str_nr;
   int size;
   int pos;
   int k;
-  
-  ASSERT_ON_BOARD1(str);
-  ASSERT1(IS_STONE(board[str]), str);
+  int limit;
 
-  s = string_number[str];
-  size = string[s].size;
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
+
+  str_nr = string_number[str_pos];
+  size = string[str_nr].size;
   
   /* Traverse the stones of the string, by following the cyclic chain. */
-  pos = FIRST_STONE(s);
-  for (k = 0; k < maxstones && k < size; k++) {
+  pos = FIRST_STONE(str_nr);
+  limit = maxstones > size ? size : maxstones;
+  for (k = 0; k < limit; k++) {
     stones[k] = pos;
     pos = NEXT_STONE(pos);
   }
@@ -2517,34 +2839,39 @@
 }
 
 
-/* Counts how many stones in str1 are directly adjacent to str2.
- * A limit can be given in the maxstones parameter so that the
- * function returns immediately. See fast_defense() in reading.c
+/* Counts how many stones in one string are directly adjacent to
+ * the second string. A limit can be given in the maxstones parameter
+ * so that the function returns immediately.
  */
 
 int
-count_adjacent_stones(int str1, int str2, int maxstones)
+count_adjacent_stones(int str1_pos, int str2_pos, int maxstones)
 {
-  int s1, s2;
+  int str1_nr, str2_nr;
   int size;
   int pos;
   int k;
   int count = 0;
+  int color2;
 
-  ASSERT_ON_BOARD1(str1);
-  ASSERT1(IS_STONE(board[str1]), str1);
-  ASSERT_ON_BOARD1(str2);
-  ASSERT1(IS_STONE(board[str2]), str2);
-
-  s1 = string_number[str1];
-  s2 = string_number[str2];
-  size = string[s1].size;
+  ASSERT_ON_BOARD1(str1_pos);
+  ASSERT1(IS_STONE(board[str1_pos]), str1_pos);
+  ASSERT_ON_BOARD1(str2_pos);
+  ASSERT1(IS_STONE(board[str2_pos]), str2_pos);
+
+  str1_nr = string_number[str1_pos];
+  str2_nr = string_number[str2_pos];
+  size = string[str1_nr].size;
 
   /* Traverse the stones of the string, by following the cyclic chain. */
-  pos = FIRST_STONE(s1);
-  for (k = 0; k < size && count < maxstones; k++) {
-    if (NEIGHBOR_OF_STRING(pos, s2, board[str2]))
+  color2 = board[str2_pos];
+  pos = FIRST_STONE(str1_nr);
+  for (k = 0; k < size; k++) {
+    if (NEIGHBOR_OF_STRING(pos, str2_nr, color2)) {
       count++;
+      if (count >= maxstones)
+        return count;
+    }
     pos = NEXT_STONE(pos);
   }
 
@@ -2553,136 +2880,173 @@
 
 
 /* chainlinks returns (in the (adj) array) the chains surrounding
- * the string at (str). The number of chains is returned.
+ * the string at (str_pos). The number of chains is returned.
  */
 
 int 
-chainlinks(int str, int adj[MAXCHAIN])
+chainlinks(int str_pos, int adj[MAXCHAIN])
 {
-  struct string_data *s;
   struct string_neighbors_data *sn;
   int k;
+  int neighbors;
 
-  ASSERT1(IS_STONE(board[str]), str);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
   /* We already have the list ready, just copy it and fill in the
    * desired information.
    */
-  s = &string[string_number[str]];
-  sn = &string_neighbors[string_number[str]];
-  for (k = 0; k < s->neighbors; k++)
+  neighbors = string[string_number[str_pos]].neighbors;
+  sn = string_neighbors + string_number[str_pos];
+  for (k = 0; k < neighbors; k++)
     adj[k] = string[sn->list[k]].origin;
 
-  return s->neighbors;
+  return neighbors;
 }
 
 
 /* chainlinks2 returns (in adj array) those chains surrounding
- * the string at str which have exactly lib liberties. The number
- * of such chains is returned.
+ * the string at str_pos which have exactly lib liberties.
+ * The number of such chains is returned.
  */
 
 int
-chainlinks2(int str, int adj[MAXCHAIN], int lib)
+chainlinks2(int str_pos, int adj[MAXCHAIN], int lib)
 {
-  struct string_data *s, *t;
   struct string_neighbors_data *sn;
   int k;
-  int neighbors;
+  int neighbors, max_neighbors;
 
-  ASSERT1(IS_STONE(board[str]), str);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
   /* We already have the list ready, just copy the strings with the
    * right number of liberties.
    */
   neighbors = 0;
-  s = &string[string_number[str]];
-  sn = &string_neighbors[string_number[str]];
-  for (k = 0; k < s->neighbors; k++) {
-    t = &string[sn->list[k]];
-    if (t->liberties == lib)
-      adj[neighbors++] = t->origin;
+  max_neighbors = string[string_number[str_pos]].neighbors;
+  sn = string_neighbors + string_number[str_pos];
+  for (k = 0; k < max_neighbors; k++) {
+    if (string[sn->list[k]].liberties == lib)
+      adj[neighbors++] = string[sn->list[k]].origin;
   }
   return neighbors;
 }
 
 
 /* chainlinks3 returns (in adj array) those chains surrounding
- * the string at str, which have less or equal lib liberties.
+ * the string at str_pos, which have less or equal lib liberties.
  * The number of such chains is returned.
  */
 
 int
-chainlinks3(int str, int adj[MAXCHAIN], int lib)
+chainlinks3(int str_pos, int adj[MAXCHAIN], int lib)
 {
-  struct string_data *s, *t;
   struct string_neighbors_data *sn;
   int k;
-  int neighbors;
+  int neighbors, max_neighbors;
 
-  ASSERT1(IS_STONE(board[str]), str);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
   /* We already have the list ready, just copy the strings with the
    * right number of liberties.
    */
   neighbors = 0;
-  s = &string[string_number[str]];
-  sn = &string_neighbors[string_number[str]];
-  for (k = 0; k < s->neighbors; k++) {
-    t = &string[sn->list[k]];
-    if (t->liberties <= lib)
-      adj[neighbors++] = t->origin;
+  max_neighbors = string[string_number[str_pos]].neighbors;
+  sn = string_neighbors + string_number[str_pos];
+  for (k = 0; k < max_neighbors; k++) {
+    if (string[sn->list[k]].liberties <= lib)
+      adj[neighbors++] = string[sn->list[k]].origin;
   }
   return neighbors;
 }
 
 
 /* extended_chainlinks() returns (in the (adj) array) the opponent
- * strings being directly adjacent to (str) or having a common liberty
- * with (str). The number of such strings is returned.
+ * strings being directly adjacent to string at (str_pos) or having
+ * a common liberty with that string. The number of such strings is
+ * returned.
  *
  * If the both_colors parameter is true, also own strings sharing a
  * liberty are returned.
  */
 
 int 
-extended_chainlinks(int str, int adj[MAXCHAIN], int both_colors)
+extended_chainlinks(int str_pos, int adj[MAXCHAIN], int both_colors)
 {
-  struct string_data *s;
   struct string_neighbors_data *sn;
   int n;
-  int k;
   int r;
   int libs[MAXLIBS];
   int liberties;
+  int checked_pos;
+  int color;
+  int other;
+  int neighbors;
+  int str_nr;
 
-  ASSERT1(IS_STONE(board[str]), str);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
+
+  str_nr = string_number[str_pos];
+  color = string[str_nr].color;
+  other = OTHER_COLOR(color);
+  sn = string_neighbors + str_nr;
+  string_mark++;
 
   /* We already have the list of directly adjacent strings ready, just
-   * copy it and mark the strings.
+   * copy it and mark the strings. We also mark ourselves in case
+   * both_colors is true.
    */
-  s = &string[string_number[str]];
-  sn = &string_neighbors[string_number[str]];
-  string_mark++;
-  for (n = 0; n < s->neighbors; n++) {
+  MARK_STRING(str_nr);
+
+  neighbors = string[str_nr].neighbors;
+  for (n = 0; n < neighbors; n++) {
     adj[n] = string[sn->list[n]].origin;
-    MARK_STRING(adj[n]);
+    MARK_STRING(sn->list[n]);
   }
 
   /* Get the liberties. */
-  liberties = findlib(str, MAXLIBS, libs);
+  liberties = findlib(str_pos, MAXLIBS, libs);
 
-  /* Look for unmarked opponent strings next to a liberty and add the
+  /* Look for unmarked strings next to a liberty and add the
    * ones which are found to the output.
    */
   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;
-	MARK_STRING(adj[n]);
-	n++;
+    checked_pos = SOUTH(libs[r]);
+    if (board[checked_pos] == other
+        || (both_colors && board[checked_pos] == color)) {
+      str_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(str_nr)) {
+        MARK_STRING(str_nr);
+        adj[n++] = string[str_nr].origin;
+      }
+    }
+
+    checked_pos = WEST(libs[r]);
+    if (board[checked_pos] == other
+        || (both_colors && board[checked_pos] == color)) {
+      str_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(str_nr)) {
+        MARK_STRING(str_nr);
+        adj[n++] = string[str_nr].origin;
+      }
+    }
+
+    checked_pos = NORTH(libs[r]);
+    if (board[checked_pos] == other
+        || (both_colors && board[checked_pos] == color)) {
+      str_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(str_nr)) {
+        MARK_STRING(str_nr);
+        adj[n++] = string[str_nr].origin;
+      }
+    }
+
+    checked_pos = EAST(libs[r]);
+    if (board[checked_pos] == other
+        || (both_colors && board[checked_pos] == color)) {
+      str_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(str_nr)) {
+        MARK_STRING(str_nr);
+        adj[n++] = string[str_nr].origin;
       }
     }
   }
@@ -2698,11 +3062,12 @@
  */
 
 int
-find_origin(int str)
+find_origin(int str_pos)
 {
-  ASSERT1(IS_STONE(board[str]), str);
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
-  return string[string_number[str]].origin;
+  return string[string_number[str_pos]].origin;
 }
 
 
@@ -2723,6 +3088,9 @@
    * has more than one spare liberty we immediately return 0.
    */
   int far_liberties = 0;
+  int checked_pos;
+  int stone;
+  int liberties;
   
   ASSERT_ON_BOARD1(pos);
   ASSERT1(board[pos] == EMPTY, pos);
@@ -2731,62 +3099,82 @@
   /* 1. Try first to solve the problem without much work. */
   string_mark++;
   
-  if (LIBERTY(SOUTH(pos)))
+  checked_pos = SOUTH(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY)
     trivial_liberties++;
-  else if (board[SOUTH(pos)] == color) {
-    if (LIBERTIES(SOUTH(pos)) > 2)
+  else if (stone == color) {
+    liberties = LIBERTIES(string_number[checked_pos]);
+    if (liberties > 2)
       return 0;
-    if (LIBERTIES(SOUTH(pos)) == 2)
+    if (liberties == 2)
       far_liberties++;
   }
-  else if (board[SOUTH(pos)] == other
-          && LIBERTIES(SOUTH(pos)) == 1 && UNMARKED_STRING(SOUTH(pos))) {
-    captures++;
-    MARK_STRING(SOUTH(pos));
+  else if (stone == other) {
+    int str_nr = string_number[checked_pos];
+    if (LIBERTIES(str_nr) == 1 && UNMARKED_STRING(str_nr)) {
+      MARK_STRING(str_nr);
+      captures++;
+    }
   }
 
-  if (LIBERTY(WEST(pos)))
+  checked_pos = WEST(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY)
     trivial_liberties++;
-  else if (board[WEST(pos)] == color) {
-    if (LIBERTIES(WEST(pos)) > 2)
+  else if (stone == color) {
+    liberties = LIBERTIES(string_number[checked_pos]);
+    if (liberties > 2)
       return 0;
-    if (LIBERTIES(WEST(pos)) == 2)
+    if (liberties == 2)
       far_liberties++;
   }
-  else if (board[WEST(pos)] == other
-          && LIBERTIES(WEST(pos)) == 1 && UNMARKED_STRING(WEST(pos))) {
-    captures++;
-    MARK_STRING(WEST(pos));
+  else if (stone == other) {
+    int str_nr = string_number[checked_pos];
+    if (LIBERTIES(str_nr) == 1 && UNMARKED_STRING(str_nr)) {
+      MARK_STRING(str_nr);
+      captures++;
+    }
   }
 
-  if (LIBERTY(NORTH(pos)))
+  checked_pos = NORTH(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY)
     trivial_liberties++;
-  else if (board[NORTH(pos)] == color) {
-    if (LIBERTIES(NORTH(pos)) > 2)
+  else if (stone == color) {
+    liberties = LIBERTIES(string_number[checked_pos]);
+    if (liberties > 2)
       return 0;
-    if (LIBERTIES(NORTH(pos)) == 2)
+    if (liberties == 2)
       far_liberties++;
   }
-  else if (board[NORTH(pos)] == other
-          && LIBERTIES(NORTH(pos)) == 1 && UNMARKED_STRING(NORTH(pos))) {
-    captures++;
-    MARK_STRING(NORTH(pos));
+  else if (stone == other) {
+    int str_nr = string_number[checked_pos];
+    if (LIBERTIES(str_nr) == 1 && UNMARKED_STRING(str_nr)) {
+      MARK_STRING(str_nr);
+      captures++;
+    }
   }
 
-  if (LIBERTY(EAST(pos)))
+  checked_pos = EAST(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY)
     trivial_liberties++;
-  else if (board[EAST(pos)] == color) {
-    if (LIBERTIES(EAST(pos)) > 2)
+  else if (stone == color) {
+    liberties = LIBERTIES(string_number[checked_pos]);
+    if (liberties > 2)
       return 0;
-    if (LIBERTIES(EAST(pos)) == 2)
+    if (liberties == 2)
       far_liberties++;
   }
-  else if (board[EAST(pos)] == other
-          && LIBERTIES(EAST(pos)) == 1 && UNMARKED_STRING(EAST(pos))) {
-    captures++;
+  else if (stone == other) {
+    int str_nr = string_number[checked_pos];
+    if (LIBERTIES(str_nr) == 1 && UNMARKED_STRING(str_nr)) {
 #if 0
-    MARK_STRING(EAST(pos));
+      MARK_STRING(str_nr);
 #endif
+      captures++;
+    }
   }
 
   /* Each captured string is guaranteed to produce at least one
@@ -2808,53 +3196,90 @@
 
 
 /*
- * Returns true if pos is a liberty of the string at str.
+ * Returns true if pos is a liberty of the string at str_pos.
+ * Checks whether pos is a liberty.
  */
 
 int
-liberty_of_string(int pos, int str)
+liberty_of_string(int pos, int str_pos)
 {
   ASSERT_ON_BOARD1(pos);
-  ASSERT_ON_BOARD1(str);
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
+  
   if (IS_STONE(board[pos]))
     return 0;
 
-  return NEIGHBOR_OF_STRING(pos, string_number[str], board[str]);
+  return NEIGHBOR_OF_STRING(pos, string_number[str_pos], board[str_pos]);
+}
+
+/*
+ * Returns true if pos is a liberty of the string at str_pos.
+ * str_pos must be a liberty.
+ */
+
+int
+liberty_of_string2(int pos, int str_pos)
+{
+  ASSERT_ON_BOARD1(pos);
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
+  gg_assert(LIBERTY(pos));
+
+  return NEIGHBOR_OF_STRING(pos, string_number[str_pos], board[str_pos]);
 }
 
 
 /*
- * Returns true if pos is a second order liberty of the string at str.
+ * Returns true if pos is a second order liberty of the string
+ * at str_pos.
  */
 int
-second_order_liberty_of_string(int pos, int str)
+second_order_liberty_of_string(int pos, int str_pos)
 {
-  int k;
+  int str_nr;
+  int color;
+
   ASSERT_ON_BOARD1(pos);
-  ASSERT_ON_BOARD1(str);
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
-  for (k = 0; k < 4; k++)
-    if (board[pos + delta[k]] == EMPTY
-	&& NEIGHBOR_OF_STRING(pos + delta[k], string_number[str], board[str]))
-      return 1;
+  color = board[str_pos];
+  str_nr = string_number[str_pos];
+
+  if (board[SOUTH(pos)] == EMPTY
+      && NEIGHBOR_OF_STRING(SOUTH(pos), str_nr, color))
+    return 1;
+
+  if (board[EAST(pos)] == EMPTY
+      && NEIGHBOR_OF_STRING(EAST(pos), str_nr, color))
+    return 1;
+
+  if (board[NORTH(pos)] == EMPTY
+      && NEIGHBOR_OF_STRING(NORTH(pos), str_nr, color))
+    return 1;
+
+  if (board[WEST(pos)] == EMPTY
+      && NEIGHBOR_OF_STRING(WEST(pos), str_nr, color))
+    return 1;
 
   return 0;
 }
 
 
 /*
- * Returns true if pos is adjacent to the string at str.
+ * Returns true if pos is adjacent to the string at str_pos.
  */
 
 int
-neighbor_of_string(int pos, int str)
+neighbor_of_string(int pos, int str_pos)
 {
-  int color = board[str];
-
-  ASSERT1(IS_STONE(color), str);
   ASSERT_ON_BOARD1(pos);
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
-  return NEIGHBOR_OF_STRING(pos, string_number[str], color);
+  return NEIGHBOR_OF_STRING(pos, string_number[str_pos], board[str_pos]);
 }
 
 /*
@@ -2874,41 +3299,53 @@
 }
 
 /*
- * Returns true if str1 and str2 belong to the same string.
+ * Returns true if str1_pos and str2_pos belong to the same string.
  */
 
 int
-same_string(int str1, int str2)
+same_string(int str1_pos, int str2_pos)
 {
-  ASSERT_ON_BOARD1(str1);
-  ASSERT_ON_BOARD1(str2);
-  ASSERT1(IS_STONE(board[str1]), str1);
-  ASSERT1(IS_STONE(board[str2]), str2);
+  ASSERT_ON_BOARD1(str1_pos);
+  ASSERT_ON_BOARD1(str2_pos);
+  ASSERT1(IS_STONE(board[str1_pos]), str1_pos);
+  ASSERT1(IS_STONE(board[str2_pos]), str2_pos);
 
-  return string_number[str1] == string_number[str2];
+  return string_number[str1_pos] == string_number[str2_pos];
 }
 
 
 /*
- * Returns true if the strings at str1 and str2 are adjacent.
+ * Returns true if the strings at str1_pos and str2_pos are adjacent.
  */
 
 int
-adjacent_strings(int str1, int str2)
+adjacent_strings(int str1_pos, int str2_pos)
 {
-  int s1, s2;
   int k;
+  int neighbors1, neighbors2;
+  int str1_nr, str2_nr;
+  int *neighbors_list;
+
+  ASSERT_ON_BOARD1(str1_pos);
+  ASSERT_ON_BOARD1(str2_pos);
+  ASSERT1(IS_STONE(board[str1_pos]), str1_pos);
+  ASSERT1(IS_STONE(board[str2_pos]), str2_pos);
+
+  str1_nr = string_number[str1_pos];
+  str2_nr = string_number[str2_pos];
+  neighbors1 = string[str1_nr].neighbors;
+  neighbors2 = string[str2_nr].neighbors;
+
+  if (neighbors1 > neighbors2) {
+    neighbors_list = string_neighbors[str2_nr].list;
+    neighbors1 = neighbors2;
+    str2_nr = str1_nr;
+  }
+  else
+    neighbors_list = string_neighbors[str1_nr].list;
   
-  ASSERT_ON_BOARD1(str1);
-  ASSERT_ON_BOARD1(str2);
-  ASSERT1(IS_STONE(board[str1]), str1);
-  ASSERT1(IS_STONE(board[str2]), str2);
-
-  s1 = string_number[str1];
-  s2 = string_number[str2];
-
-  for (k = 0; k < string[s1].neighbors; k++)
-    if (string_neighbors[s1].list[k] == s2)
+  for (k = 0; k < neighbors1; k++)
+    if (neighbors_list[k] == str2_nr)
       return 1;
 
   return 0;
@@ -2933,51 +3370,56 @@
   int other = OTHER_COLOR(color);
   int captures = 0;
   int kpos = 0;
+  int checked_pos;
   
   ASSERT_ON_BOARD1(pos);
   ASSERT1(color == WHITE || color == BLACK, pos);
 
-  if (ON_BOARD(SOUTH(pos))) {
-    if (board[SOUTH(pos)] != other)
+  checked_pos = SOUTH(pos);
+  if (ON_BOARD(checked_pos)) {
+    if (board[checked_pos] != other)
       return 0;
-    else if (LIBERTIES(SOUTH(pos)) == 1) {
-      kpos = SOUTH(pos);
-      captures += string[string_number[SOUTH(pos)]].size;
+    else if (LIBERTIES(string_number[checked_pos]) == 1) {
+      kpos = checked_pos;
+      captures += string[string_number[checked_pos]].size;
       if (captures > 1)
-	return 0;
+        return 0;
     }
   }
   
-  if (ON_BOARD(WEST(pos))) {
-    if (board[WEST(pos)] != other)
+  checked_pos = WEST(pos);
+  if (ON_BOARD(checked_pos)) {
+    if (board[checked_pos] != other)
       return 0;
-    else if (LIBERTIES(WEST(pos)) == 1) {
-      kpos = WEST(pos);
-      captures += string[string_number[WEST(pos)]].size;
+    else if (LIBERTIES(string_number[checked_pos]) == 1) {
+      kpos = checked_pos;
+      captures += string[string_number[checked_pos]].size;
       if (captures > 1)
-	return 0;
+        return 0;
     }
   }
-  
-  if (ON_BOARD(NORTH(pos))) {
-    if (board[NORTH(pos)] != other)
+
+  checked_pos = NORTH(pos);
+  if (ON_BOARD(checked_pos)) {
+    if (board[checked_pos] != other)
       return 0;
-    else if (LIBERTIES(NORTH(pos)) == 1) {
-      kpos = NORTH(pos);
-      captures += string[string_number[NORTH(pos)]].size;
+    else if (LIBERTIES(string_number[checked_pos]) == 1) {
+      kpos = checked_pos;
+      captures += string[string_number[checked_pos]].size;
       if (captures > 1)
-	return 0;
+        return 0;
     }
   }
   
-  if (ON_BOARD(EAST(pos))) {
-    if (board[EAST(pos)] != other)
+  checked_pos = EAST(pos);
+  if (ON_BOARD(checked_pos)) {
+    if (board[checked_pos] != other)
       return 0;
-    else if (LIBERTIES(EAST(pos)) == 1) {
-      kpos = EAST(pos);
-      captures += string[string_number[EAST(pos)]].size;
+    else if (LIBERTIES(string_number[checked_pos]) == 1) {
+      kpos = checked_pos;
+      captures += string[string_number[checked_pos]].size;
       if (captures > 1)
-	return 0;
+        return 0;
     }
   }
   
@@ -3008,10 +3450,9 @@
       return 1;
   }
   else {
-    struct string_data *s = &string[string_number[pos]];
-    struct string_liberties_data *sl = &string_libs[string_number[pos]];
+    struct string_data *s = string + string_number[pos];
     if (s->liberties == 1 && s->size == 1
-	&& is_ko(sl->list[0], OTHER_COLOR(s->color), NULL))
+	&& is_ko(string_libs[string_number[pos]].list[0], OTHER_COLOR(s->color), NULL))
       return 1;
   }
 
@@ -3032,7 +3473,7 @@
 static int
 is_superko_violation(int pos, int color, enum ko_rules type)
 {
-  Hash_data this_board_hash = board_hash;
+  Hash_data this_board_hash;
   Hash_data new_board_hash;
   int k;
 
@@ -3040,6 +3481,8 @@
   if (type == NONE || type == SIMPLE)
     return 0;
 
+  this_board_hash = board_hash;
+
   if (board_ko_pos != NO_MOVE)
     hashdata_invert_ko(&this_board_hash, board_ko_pos);
 
@@ -3073,16 +3516,16 @@
 
   ASSERT1(board[pos] == EMPTY, pos);
 
-  if (board[SOUTH(pos)] == other && LIBERTIES(SOUTH(pos)) == 1)
+  if (board[SOUTH(pos)] == other && LIBERTIES(string_number[SOUTH(pos)]) == 1)
     return 1;
   
-  if (board[WEST(pos)] == other && LIBERTIES(WEST(pos)) == 1)
+  if (board[WEST(pos)] == other && LIBERTIES(string_number[WEST(pos)]) == 1)
     return 1;
   
-  if (board[NORTH(pos)] == other && LIBERTIES(NORTH(pos)) == 1)
+  if (board[NORTH(pos)] == other && LIBERTIES(string_number[NORTH(pos)]) == 1)
     return 1;
   
-  if (board[EAST(pos)] == other && LIBERTIES(EAST(pos)) == 1)
+  if (board[EAST(pos)] == other && LIBERTIES(string_number[EAST(pos)]) == 1)
     return 1;
 
   return 0;
@@ -3129,12 +3572,10 @@
 }
 
 /* Return the number of stones of the indicated color(s) on the board.
- * This only counts stones in the permanent position, not stones placed
- * by trymove() or tryko(). Use stones_on_board(BLACK | WHITE) to get
- * the total number of stones on the board.
- *
- * FIXME: This seems wrong, it uses the modified board, not the permanent
- * one. /ab
+ * This function is used only to count stones in the permanent position,
+ * not stones placed by trymove() or tryko().
+ * Use stones_on_board(BLACK | WHITE) to get the total number of stones
+ * on the board.
  */
 int
 stones_on_board(int color)
@@ -3204,7 +3645,7 @@
 new_position(void)
 {
   int pos;
-  int s;
+  int str_nr;
 
   position_number++;
   next_string = 0;
@@ -3221,18 +3662,15 @@
   /* propagate_string relies on non-assigned stones to have
    * string_number -1.
    */
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
-    if (ON_BOARD(pos))
-      string_number[pos] = -1;
+  memset(string_number, -1, sizeof(string_number));
 
   /* Find the existing strings. */
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (!ON_BOARD(pos))
-      continue;
-    if (IS_STONE(board[pos]) && string_number[pos] == -1) {
+    int stone = board[pos];
+    if (IS_STONE(stone) && string_number[pos] == -1) {
       string_number[pos] = next_string;
-      string[next_string].size = propagate_string(pos, pos);
-      string[next_string].color = board[pos];
+      string[next_string].size = propagate_string(pos, pos, stone);
+      string[next_string].color = stone;
       string[next_string].origin = pos;
       string[next_string].mark = 0;
       next_string++;
@@ -3241,24 +3679,25 @@
   }
   
   /* Fill in liberty and neighbor info. */
-  for (s = 0; s < next_string; s++) {
-    find_liberties_and_neighbors(s);
+  for (str_nr = 0; str_nr < next_string; str_nr++) {
+    find_liberties_and_neighbors(str_nr);
   }
 }
 
-
-#if 0
-
 /*
- * Debug function. Dump all string information.
+ * Debug function. Dump all incremental board information.
  */
 
-static void
+void
 dump_incremental_board(void)
 {
   int pos;
   int s;
   int i;
+  int first_stone;
+  int row = 0;
+
+  fprintf(stderr, "\n");
   
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
     if (!ON_BOARD(pos))
@@ -3267,7 +3706,11 @@
       fprintf(stderr, " . ");
     else
       fprintf(stderr, "%2d ", string_number[pos]);
-    fprintf(stderr, "\n");
+    row++;
+	if (row == board_size) {
+      fprintf(stderr, "\n");
+      row = 0;
+    }
   }
 
   for (s = 0; s < next_string; s++) {
@@ -3280,57 +3723,59 @@
 	    string[s].liberties, string[s].neighbors);
     gprintf("%ostones:");
 
-    pos = FIRST_STONE(s);
+    first_stone = FIRST_STONE(s);
+    pos = first_stone;
     do {
       gprintf("%o %1m", pos);
       pos = NEXT_STONE(pos);
-    } while (!BACK_TO_FIRST_STONE(s, pos));
+    } while (pos != first_stone);
     
     gprintf("%o\nliberties:");
-    for (i = 0; i < string[s].liberties; i++)
-      gprintf("%o %1m", string[s].libs[i]);
+    for (i = 0; i < string[s].liberties && i < MAX_LIBERTIES; i++)
+      gprintf("%o %1m", string_libs[s].list[i]);
+
+    if (string[s].liberties > MAX_LIBERTIES)
+      gprintf("...");
     
     gprintf("%o\nneighbors:");
     for (i = 0; i < string[s].neighbors; i++)
-      gprintf("%o %d(%1m)", string[s].neighborlist[i],
-	      string[string[s].neighborlist[i]].origin);
+      gprintf("%o %d(%1m)", string_neighbors[s].list[i],
+	      string[string_neighbors[s].list[i]].origin);
     gprintf("%o\n\n");
   }
 }
-#endif
-
 
 /* Build a string and its cyclic list representation from scratch.
- * propagate_string(stone, str) adds the stone (stone) to the string
- * (str) and recursively continues with not already included friendly
- * neighbors. To start a new string at (stone), use
- * propagate_string(stone, stone). The size of the string is returned.
+ * propagate_string(stone_pos, str_pos, color) adds the stone (stone_pos)
+ * to the string (str) and recursively continues with not already
+ * included friendly neighbors. To start a new string at (stone), use
+ * propagate_string(stone, stone, color). The size of the string is
+ * returned.
  */
 
 static int
-propagate_string(int stone, int str)
+propagate_string(int stone_pos, int str_pos, int color)
 {
   int size = 1;
   int k;
   
-  if (stone == str) {
+  if (stone_pos == str_pos) {
     /* Start a new string. */
-    next_stone[stone] = stone;
+    next_stone[stone_pos] = stone_pos;
   }
   else {
-    /* Link the stone at (stone) to the string including (str) */
-    string_number[stone] = string_number[str];
-    next_stone[stone] = next_stone[str];
-    next_stone[str] = stone;
+    /* Link the stone at (stone_pos) to the string including (str_pos) */
+    string_number[stone_pos] = string_number[str_pos];
+    next_stone[stone_pos] = next_stone[str_pos];
+    next_stone[str_pos] = stone_pos;
   }
 
   /* Look in all four directions for more stones to add. */
   for (k = 0; k < 4; k++) {
-    int d = delta[k];
-    if (ON_BOARD(stone + d)
-	&& board[stone + d] == board[stone]
-	&& string_number[stone + d] == -1)
-      size += propagate_string(stone + d, str);
+    int new_pos = stone_pos + delta[k];
+    if (board[new_pos] == color
+	&& string_number[new_pos] == -1)
+      size += propagate_string(new_pos, str_pos, color);
   }
   
   return size;
@@ -3342,55 +3787,82 @@
  */
 
 static void
-find_liberties_and_neighbors(int s)
+find_liberties_and_neighbors(int str_nr)
 {
   int pos;
-  int other = OTHER_COLOR(string[s].color);
+  int other = OTHER_COLOR(string[str_nr].color);
+  int first_stone;
 
   /* Clear the marks. */
   liberty_mark++;
   string_mark++;
 
   /* Traverse the stones of the string, by following the cyclic chain. */
-  pos = FIRST_STONE(s);
+  first_stone = FIRST_STONE(str_nr);
+  pos = first_stone;
   do {
+    int checked_pos;
     /* Look in each direction for new liberties or new neighbors. Mark
      * already visited liberties and neighbors.
      */
-    if (UNMARKED_LIBERTY(SOUTH(pos))) {
-      ADD_AND_MARK_LIBERTY(s, SOUTH(pos));
+    checked_pos = SOUTH(pos);
+    if (board[checked_pos] == EMPTY) {
+      if (ml[checked_pos] != liberty_mark) {
+        ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
+      }
     }
-    else if (UNMARKED_COLOR_STRING(SOUTH(pos), other)) {
-      ADD_NEIGHBOR(s, SOUTH(pos));
-      MARK_STRING(SOUTH(pos));
+    else if (board[checked_pos] == other) {
+      int neighbor_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(neighbor_nr)) {
+        MARK_STRING(neighbor_nr);
+        ADD_NEIGHBOR(str_nr, neighbor_nr);
+      }
     }
     
-    if (UNMARKED_LIBERTY(WEST(pos))) {
-      ADD_AND_MARK_LIBERTY(s, WEST(pos));
+    checked_pos = WEST(pos);
+    if (board[checked_pos] == EMPTY) {
+      if (ml[checked_pos] != liberty_mark) {
+        ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
+      }
     }
-    else if (UNMARKED_COLOR_STRING(WEST(pos), other)) {
-      ADD_NEIGHBOR(s, WEST(pos));
-      MARK_STRING(WEST(pos));
+    else if (board[checked_pos] == other) {
+      int neighbor_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(neighbor_nr)) {
+        MARK_STRING(neighbor_nr);
+        ADD_NEIGHBOR(str_nr, neighbor_nr);
+      }
     }
     
-    if (UNMARKED_LIBERTY(NORTH(pos))) {
-      ADD_AND_MARK_LIBERTY(s, NORTH(pos));
+    checked_pos = NORTH(pos);
+    if (board[checked_pos] == EMPTY) {
+      if (ml[checked_pos] != liberty_mark) {
+        ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
+      }
     }
-    else if (UNMARKED_COLOR_STRING(NORTH(pos), other)) {
-      ADD_NEIGHBOR(s, NORTH(pos));
-      MARK_STRING(NORTH(pos));
+    else if (board[checked_pos] == other) {
+      int neighbor_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(neighbor_nr)) {
+        MARK_STRING(neighbor_nr);
+        ADD_NEIGHBOR(str_nr, neighbor_nr);
+      }
     }
     
-    if (UNMARKED_LIBERTY(EAST(pos))) {
-      ADD_AND_MARK_LIBERTY(s, EAST(pos));
+    checked_pos = EAST(pos);
+    if (board[checked_pos] == EMPTY) {
+      if (ml[checked_pos] != liberty_mark) {
+        ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
+      }
     }
-    else if (UNMARKED_COLOR_STRING(EAST(pos), other)) {
-      ADD_NEIGHBOR(s, EAST(pos));
-      MARK_STRING(EAST(pos));
+    else if (board[checked_pos] == other) {
+      int neighbor_nr = string_number[checked_pos];
+      if (UNMARKED_STRING(neighbor_nr)) {
+        MARK_STRING(neighbor_nr);
+        ADD_NEIGHBOR(str_nr, neighbor_nr);
+      }
     }
-    
+
     pos = NEXT_STONE(pos);
-  } while (!BACK_TO_FIRST_STONE(s, pos));
+  } while (pos != first_stone);
 }
 
 
@@ -3399,45 +3871,47 @@
  */
 
 static void
-update_liberties(int s)
+update_liberties(int str_nr)
 {
   int pos;
   int k;
+  int first_stone;
 
   /* Push the old information. */
-  PUSH_VALUE(string[s].liberties);
-  for (k = 0; k < string[s].liberties && k < MAX_LIBERTIES; k++) {
-    PUSH_VALUE(string_libs[s].list[k]);
+  PUSH_VALUE(string[str_nr].liberties);
+  for (k = 0; k < string[str_nr].liberties && k < MAX_LIBERTIES; k++) {
+    PUSH_VALUE(string_libs[str_nr].list[k]);
   }
-  string[s].liberties = 0;
+  string[str_nr].liberties = 0;
 
   /* Clear the liberty mark. */
   liberty_mark++;
 
   /* Traverse the stones of the string, by following the cyclic chain. */
-  pos = FIRST_STONE(s);
+  first_stone = FIRST_STONE(str_nr);
+  pos = first_stone;
   do {
     /* Look in each direction for new liberties. Mark already visited
      * liberties. 
      */
     if (UNMARKED_LIBERTY(SOUTH(pos))) {
-      ADD_AND_MARK_LIBERTY(s, SOUTH(pos));
+      ADD_AND_MARK_LIBERTY(str_nr, SOUTH(pos));
     }
-    
+
     if (UNMARKED_LIBERTY(WEST(pos))) {
-      ADD_AND_MARK_LIBERTY(s, WEST(pos));
+      ADD_AND_MARK_LIBERTY(str_nr, WEST(pos));
     }
     
     if (UNMARKED_LIBERTY(NORTH(pos))) {
-      ADD_AND_MARK_LIBERTY(s, NORTH(pos));
+      ADD_AND_MARK_LIBERTY(str_nr, NORTH(pos));
     }
     
     if (UNMARKED_LIBERTY(EAST(pos))) {
-      ADD_AND_MARK_LIBERTY(s, EAST(pos));
+      ADD_AND_MARK_LIBERTY(str_nr, EAST(pos));
     }
-    
+
     pos = NEXT_STONE(pos);
-  } while (!BACK_TO_FIRST_STONE(s, pos));
+  } while (pos != first_stone);
 }
 
 
@@ -3446,14 +3920,16 @@
  */
 
 static void
-remove_neighbor(int str_number, int n)
+remove_neighbor(int str_number, int removed_nr)
 {
   int k;
+#ifndef GG_TURN_OFF_ASSERTS
   int done = 0;
-  struct string_data *s = &string[str_number];
-  struct string_neighbors_data *sn = &string_neighbors[str_number];
+#endif
+  struct string_data *s = string + str_number;
+  struct string_neighbors_data *sn = string_neighbors + str_number;
   for (k = 0; k < s->neighbors; k++)
-    if (sn->list[k] == n) {
+    if (sn->list[k] == removed_nr) {
       /* We need to push the last entry too because it may become
        * destroyed later.
        */
@@ -3462,10 +3938,14 @@
       PUSH_VALUE(s->neighbors);
       sn->list[k] = sn->list[s->neighbors - 1];
       s->neighbors--;
+#ifndef GG_TURN_OFF_ASSERTS
       done = 1;
+#endif
       break;
     }
+#ifndef GG_TURN_OFF_ASSERTS
   gg_assert(done);
+#endif
 }
 
 
@@ -3478,8 +3958,8 @@
 remove_liberty(int str_number, int pos)
 {
   int k;
-  struct string_data *s = &string[str_number];
-  struct string_liberties_data *sl = &string_libs[str_number];
+  struct string_data *s = string + str_number;
+  struct string_liberties_data *sl = string_libs + str_number;
   
   if (s->liberties > MAX_LIBERTIES)
     update_liberties(str_number);
@@ -3505,21 +3985,26 @@
  */
 
 static int
-do_remove_string(int s)
+do_remove_string(int str_nr)
 {
   int pos;
   int k;
-  int size = string[s].size;
+  int *str_neighbors_list = string_neighbors[str_nr].list;
+  struct string_data *str_data = string + str_nr;
+  int size = str_data->size;
+  int neighbors = str_data->neighbors;
+  int first_stone;
 
   /* Traverse the stones of the string, by following the cyclic chain. */
-  pos = FIRST_STONE(s);
+  first_stone = FIRST_STONE(str_nr);
+  pos = first_stone;
   do {
     /* Push color, string number and cyclic chain pointers. */
     PUSH_VALUE(string_number[pos]);
     PUSH_VALUE(next_stone[pos]);
     DO_REMOVE_STONE(pos);
     pos = NEXT_STONE(pos);
-  } while (!BACK_TO_FIRST_STONE(s, pos));
+  } while (pos != first_stone);
 
   /* The neighboring strings have obtained some new liberties and lost
    * a neighbor.  For speed reasons we handle two most common cases
@@ -3527,51 +4012,53 @@
    * update_liberties().
    */
   if (size == 1) {
-    for (k = 0; k < string[s].neighbors; k++) {
-      int neighbor = string_neighbors[s].list[k];
-
-      remove_neighbor(neighbor, s);
-      PUSH_VALUE(string[neighbor].liberties);
-
-      if (string[neighbor].liberties < MAX_LIBERTIES)
-	string_libs[neighbor].list[string[neighbor].liberties] = pos;
-      string[neighbor].liberties++;
+    for (k = 0; k < neighbors; k++) {
+      int neighbor_nr = str_neighbors_list[k];
+      int *neighbor_libs = &(string[neighbor_nr].liberties);
+
+      remove_neighbor(neighbor_nr, str_nr);
+      PUSH_VALUE(*neighbor_libs);
+
+      if (*neighbor_libs < MAX_LIBERTIES)
+	string_libs[neighbor_nr].list[*neighbor_libs] = pos;
+      (*neighbor_libs)++;
     }
   }
   else if (size == 2) {
-    int other = OTHER_COLOR(string[s].color);
+    int other = OTHER_COLOR(str_data->color);
     int pos2 = NEXT_STONE(pos);
 
-    for (k = 0; k < string[s].neighbors; k++) {
-      int neighbor = string_neighbors[s].list[k];      
-
-      remove_neighbor(neighbor, s);
-      PUSH_VALUE(string[neighbor].liberties);
-
-      if (NEIGHBOR_OF_STRING(pos, neighbor, other)) {
-	if (string[neighbor].liberties < MAX_LIBERTIES)
-	  string_libs[neighbor].list[string[neighbor].liberties] = pos;
-	string[neighbor].liberties++;
+    for (k = 0; k < neighbors; k++) {
+      int neighbor_nr = str_neighbors_list[k];  
+      int *neighbor_libs = &(string[neighbor_nr].liberties);
+
+      remove_neighbor(neighbor_nr, str_nr);
+      PUSH_VALUE(*neighbor_libs);
+
+      if (NEIGHBOR_OF_STRING(pos, neighbor_nr, other)) {
+	if (*neighbor_libs < MAX_LIBERTIES)
+	  string_libs[neighbor_nr].list[*neighbor_libs] = pos;
+	(*neighbor_libs)++;
       }
 
-      if (NEIGHBOR_OF_STRING(pos2, neighbor, other)) {
-	if (string[neighbor].liberties < MAX_LIBERTIES)
-	  string_libs[neighbor].list[string[neighbor].liberties] = pos2;
-	string[neighbor].liberties++;
+      if (NEIGHBOR_OF_STRING(pos2, neighbor_nr, other)) {
+	if (*neighbor_libs < MAX_LIBERTIES)
+	  string_libs[neighbor_nr].list[*neighbor_libs] = pos2;
+	(*neighbor_libs)++;
       }
     }
   }
   else {
-    for (k = 0; k < string[s].neighbors; k++) {
-      remove_neighbor(string_neighbors[s].list[k], s);
-      update_liberties(string_neighbors[s].list[k]);
+    for (k = 0; k < neighbors; k++) {
+      remove_neighbor(str_neighbors_list[k], str_nr);
+      update_liberties(str_neighbors_list[k]);
     }
   }
 
   /* Update the number of captured stones. These are assumed to
    * already have been pushed.
    */
-  if (string[s].color == WHITE)
+  if (str_data->color == WHITE)
     white_captured += size;
   else
     black_captured += size;
@@ -3584,27 +4071,27 @@
  * string for it.
  */
 static void
-create_new_string(int pos)
+create_new_string(int pos, int color)
 {
-  int s;
-  int color = board[pos];
+  int str_nr;
   int other = OTHER_COLOR(color);
+  int checked_pos;
 
   /* Get the next free string number. */
   PUSH_VALUE(next_string);
-  s = next_string++;
-  PARANOID1(s < MAX_STRINGS, pos);
-  string_number[pos] = s;
+  str_nr = next_string++;
+  PARANOID1(str_nr < MAX_STRINGS, pos);
+  string_number[pos] = str_nr;
   /* Set up a size one cycle for the string. */
   next_stone[pos] = pos;
 
   /* Set trivially known values and initialize the rest to zero. */
-  string[s].color = color;
-  string[s].size = 1;
-  string[s].origin = pos;
-  string[s].liberties = 0;
-  string[s].neighbors = 0;
-  string[s].mark = 0;
+  string[str_nr].color = color;
+  string[str_nr].size = 1;
+  string[str_nr].origin = pos;
+  string[str_nr].liberties = 0;
+  string[str_nr].neighbors = 0;
+  string[str_nr].mark = 0;
 
   /* Clear the string mark. */
   string_mark++;
@@ -3612,59 +4099,71 @@
   /* In each direction, look for a liberty or a nonmarked opponent
    * neighbor. Mark visited neighbors. There is no need to mark the
    * liberties since we can't find them twice. */
-  if (LIBERTY(SOUTH(pos))) {
-    ADD_LIBERTY(s, SOUTH(pos));
+  checked_pos = SOUTH(pos);
+  if (LIBERTY(checked_pos)) {
+    ADD_LIBERTY(str_nr, checked_pos);
+  }
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      /* Add the neighbor to our list. */
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      /* Add us to our neighbor's list. */
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
   }
-  else if (UNMARKED_COLOR_STRING(SOUTH(pos), other)) {
-    int s2 = string_number[SOUTH(pos)];
-    /* Add the neighbor to our list. */
-    ADD_NEIGHBOR(s, SOUTH(pos));
-    /* Add us to our neighbor's list. */
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
-    MARK_STRING(SOUTH(pos));
-  }
-  
-  if (LIBERTY(WEST(pos))) {
-    ADD_LIBERTY(s, WEST(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(WEST(pos), other)) {
-    int s2 = string_number[WEST(pos)];
-    /* Add the neighbor to our list. */
-    ADD_NEIGHBOR(s, WEST(pos));
-    /* Add us to our neighbor's list. */
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
-    MARK_STRING(WEST(pos));
-  }
-  
-  if (LIBERTY(NORTH(pos))) {
-    ADD_LIBERTY(s, NORTH(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(NORTH(pos), other)) {
-    int s2 = string_number[NORTH(pos)];
-    /* Add the neighbor to our list. */
-    ADD_NEIGHBOR(s, NORTH(pos));
-    /* Add us to our neighbor's list. */
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
-    MARK_STRING(NORTH(pos));
-  }
-  
-  if (LIBERTY(EAST(pos))) {
-    ADD_LIBERTY(s, EAST(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(EAST(pos), other)) {
-    int s2 = string_number[EAST(pos)];
-    /* Add the neighbor to our list. */
-    ADD_NEIGHBOR(s, EAST(pos));
-    /* Add us to our neighbor's list. */
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
-    /* No need to mark since no visits left. */
+  
+  checked_pos = WEST(pos);
+  if (LIBERTY(checked_pos)) {
+    ADD_LIBERTY(str_nr, checked_pos);
+  }
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      /* Add the neighbor to our list. */
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      /* Add us to our neighbor's list. */
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
+  }
+  
+  checked_pos = NORTH(pos);
+  if (LIBERTY(checked_pos)) {
+    ADD_LIBERTY(str_nr, checked_pos);
+  }
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      /* Add the neighbor to our list. */
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      /* Add us to our neighbor's list. */
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
+  }
+  
+  checked_pos = EAST(pos);
+  if (LIBERTY(checked_pos)) {
+    ADD_LIBERTY(str_nr, checked_pos);
+  }
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      /* No need to mark since no visits left. */
 #if 0
-    MARK_STRING(EAST(pos));
+      MARK_STRING(neighbor_nr);
 #endif
+      /* Add the neighbor to our list. */
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      /* Add us to our neighbor's list. */
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
   }
 }
 
@@ -3673,193 +4172,209 @@
  * new stone to that string.
  */
 static void
-extend_neighbor_string(int pos, int s)
+extend_neighbor_string(int pos, int str_nr, int color)
 {
   int k;
   int liberties_updated = 0;
-  int color = board[pos];
   int other = OTHER_COLOR(color);
+  int checked_pos;
+  int *neighbors_list = string_neighbors[str_nr].list;
 
   /* Link in the stone in the cyclic list. */
-  int pos2 = string[s].origin;
-  next_stone[pos] = next_stone[pos2];
-  PUSH_VALUE(next_stone[pos2]);
-  next_stone[pos2] = pos;
+  int origin = string[str_nr].origin;
+  next_stone[pos] = next_stone[origin];
+  PUSH_VALUE(next_stone[origin]);
+  next_stone[origin] = pos;
   
   /* Do we need to update the origin? */
-  if (pos < pos2) {
-    PUSH_VALUE(string[s].origin);
-    string[s].origin = pos;
+  if (pos < origin) {
+    PUSH_VALUE(string[str_nr].origin);
+    string[str_nr].origin = pos;
   }
   
-  string_number[pos] = s;
+  string_number[pos] = str_nr;
 
   /* The size of the string has increased by one. */
-  PUSH_VALUE(string[s].size);
-  string[s].size++;
+  PUSH_VALUE(string[str_nr].size);
+  string[str_nr].size++;
 
   /* If s has too many liberties, we don't know where they all are and
    * can't update the liberties with the algorithm we otherwise
    * use. In that case we can only recompute the liberties from
    * scratch.
    */
-  if (string[s].liberties > MAX_LIBERTIES) {
-    update_liberties(s);
+  if (string[str_nr].liberties > MAX_LIBERTIES) {
+    update_liberties(str_nr);
     liberties_updated = 1;
   }
   else {
     /* The place of the new stone is no longer a liberty. */
-    remove_liberty(s, pos);
+    remove_liberty(str_nr, pos);
   }
 
   /* Mark old neighbors of the string. */
   string_mark++;
-  for (k = 0; k < string[s].neighbors; k++)
-    string[string_neighbors[s].list[k]].mark = string_mark;
+  for (k = 0; k < string[str_nr].neighbors; k++)
+    string[neighbors_list[k]].mark = string_mark;
 
   /* Look at the neighbor locations of pos for new liberties and/or
    * neighbor strings.
    */
 
   /* If we find a liberty, look two steps away to determine whether
-   * this already is a liberty of s.
+   * this already is a liberty of the string.
    */
-  if (LIBERTY(SOUTH(pos))) {
+  checked_pos = SOUTH(pos);
+  if (LIBERTY(checked_pos)) {
     if (!liberties_updated
-	&& !NON_SOUTH_NEIGHBOR_OF_STRING(SOUTH(pos), s, color))
-      ADD_LIBERTY(s, SOUTH(pos));
+        && !NON_SOUTH_NEIGHBOR_OF_STRING(checked_pos, str_nr, color))
+      ADD_LIBERTY(str_nr, checked_pos);
   }
-  else if (UNMARKED_COLOR_STRING(SOUTH(pos), other)) {
-    int s2 = string_number[SOUTH(pos)];
-    PUSH_VALUE(string[s].neighbors);
-    ADD_NEIGHBOR(s, SOUTH(pos));
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
-    MARK_STRING(SOUTH(pos));
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      PUSH_VALUE(string[str_nr].neighbors);
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
   }
   
-  if (LIBERTY(WEST(pos))) {
+  checked_pos = WEST(pos);
+  if (LIBERTY(checked_pos)) {
     if (!liberties_updated
-	&& !NON_WEST_NEIGHBOR_OF_STRING(WEST(pos), s, color))
-      ADD_LIBERTY(s, WEST(pos));
+        && !NON_WEST_NEIGHBOR_OF_STRING(checked_pos, str_nr, color))
+      ADD_LIBERTY(str_nr, checked_pos);
   }
-  else if (UNMARKED_COLOR_STRING(WEST(pos), other)) {
-    int s2 = string_number[WEST(pos)];
-    PUSH_VALUE(string[s].neighbors);
-    ADD_NEIGHBOR(s, WEST(pos));
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
-    MARK_STRING(WEST(pos));
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      PUSH_VALUE(string[str_nr].neighbors);
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
   }
   
-  if (LIBERTY(NORTH(pos))) {
+  checked_pos = NORTH(pos);
+  if (LIBERTY(checked_pos)) {
     if (!liberties_updated
-	&& !NON_NORTH_NEIGHBOR_OF_STRING(NORTH(pos), s, color))
-      ADD_LIBERTY(s, NORTH(pos));
+        && !NON_NORTH_NEIGHBOR_OF_STRING(checked_pos, str_nr, color))
+      ADD_LIBERTY(str_nr, checked_pos);
   }
-  else if (UNMARKED_COLOR_STRING(NORTH(pos), other)) {
-    int s2 = string_number[NORTH(pos)];
-    PUSH_VALUE(string[s].neighbors);
-    ADD_NEIGHBOR(s, NORTH(pos));
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
-    MARK_STRING(NORTH(pos));
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      PUSH_VALUE(string[str_nr].neighbors);
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
   }
   
-  if (LIBERTY(EAST(pos))) {
+  checked_pos = EAST(pos);
+  if (LIBERTY(checked_pos)) {
     if (!liberties_updated
-	&& !NON_EAST_NEIGHBOR_OF_STRING(EAST(pos), s, color))
-      ADD_LIBERTY(s, EAST(pos));
+        && !NON_EAST_NEIGHBOR_OF_STRING(checked_pos, str_nr, color))
+      ADD_LIBERTY(str_nr, checked_pos);
   }
-  else if (UNMARKED_COLOR_STRING(EAST(pos), other)) {
-    int s2 = string_number[EAST(pos)];
-    PUSH_VALUE(string[s].neighbors);
-    ADD_NEIGHBOR(s, EAST(pos));
-    PUSH_VALUE(string[s2].neighbors);
-    ADD_NEIGHBOR(s2, pos);
+  else if (board[checked_pos] == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
 #if 0
-    MARK_STRING(EAST(pos));
+      MARK_STRING(neighbor_nr);
 #endif
+      PUSH_VALUE(string[str_nr].neighbors);
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
   }
-  
 }
 
 
-/* Incorporate the string at pos with the string s.
+/* Incorporate the string at ass_pos with the string str_nr.
  */
 
 static void
-assimilate_string(int s, int pos)
+assimilate_string(int str_nr, int ass_pos)
 {
   int k;
   int last;
-  int s2 = string_number[pos];
-  string[s].size += string[s2].size;
-
-  /* Walk through the s2 stones and change string number. Also pick up
-   * the last stone in the cycle for later use.
+  int ass_nr = string_number[ass_pos];
+  int first_stone;
+  string[str_nr].size += string[ass_nr].size;
+
+  /* Walk through the assimilated string stones and change
+   * string number. Also pick up the last stone in the cycle
+   * for later use.
    */
-  pos = FIRST_STONE(s2);
+  first_stone = FIRST_STONE(ass_nr);
+  ass_pos = first_stone;
   do {
-    PUSH_VALUE(string_number[pos]);
-    string_number[pos] = s;
-    last = pos;
-    pos = NEXT_STONE(pos);
-  } while (!BACK_TO_FIRST_STONE(s2, pos));
+    PUSH_VALUE(string_number[ass_pos]);
+    string_number[ass_pos] = str_nr;
+    last = ass_pos;
+    ass_pos = NEXT_STONE(ass_pos);
+  } while (ass_pos != first_stone);
 
   /* Link the two cycles together. */
   {
-    int pos2 = string[s].origin;
+    int str_pos = string[str_nr].origin;
     PUSH_VALUE(next_stone[last]);
-    PUSH_VALUE(next_stone[pos2]);
-    next_stone[last] = next_stone[pos2];
-    next_stone[pos2] = string[s2].origin;
+    PUSH_VALUE(next_stone[str_pos]);
+    next_stone[last] = next_stone[str_pos];
+    next_stone[str_pos] = string[ass_nr].origin;
     
     /* Do we need to update the origin? */
-    if (string[s2].origin < pos2)
-      string[s].origin = string[s2].origin;
+    if (string[ass_nr].origin < str_pos)
+      string[str_nr].origin = string[ass_nr].origin;
   }
 
-  /* Pick up the liberties of s2 that we don't already have.
-   * It is assumed that the liberties of s have been marked before
-   * this function is called.
+  /* Pick up the liberties of the assimilated string that we don't
+   * already have. It is assumed that the liberties of str_nr have
+   * been marked before this function is called.
    */
-  if (string[s2].liberties <= MAX_LIBERTIES) {
-    for (k = 0; k < string[s2].liberties; k++) {
-      int pos2 = string_libs[s2].list[k];
-      if (UNMARKED_LIBERTY(pos2)) {
-	ADD_AND_MARK_LIBERTY(s, pos2);
+  if (string[ass_nr].liberties <= MAX_LIBERTIES) {
+    for (k = 0; k < string[ass_nr].liberties; k++) {
+      int lib_pos = string_libs[ass_nr].list[k];
+      if (UNMARKED_LIBERTY(lib_pos)) {
+	ADD_AND_MARK_LIBERTY(str_nr, lib_pos);
       }
     }
   }
   else {
-    /* If s2 had too many liberties the above strategy wouldn't be
-     * effective, since not all liberties are listed in
-     * libs[] the chain of stones for s2 is no
-     * longer available (it has already been merged with s) so we
-     * can't reconstruct the s2 liberties. Instead we capitulate and
-     * rebuild the list of liberties for s (including the neighbor
-     * strings assimilated so far) from scratch.
+    /* If the assimilated string had too many liberties the above
+     * strategy wouldn't be effective, since not all liberties are
+     * listed in libs[] the chain of stones for the assimilated string
+     * is no longer available (it has already been merged with str_nr)
+     * so we can't reconstruct the ass_nr liberties. Instead we capitulate
+     * and rebuild the list of liberties for str_nr (including the
+     * neighbor strings assimilated so far) from scratch.
      */
     liberty_mark++;          /* Reset the mark. */
-    string[s].liberties = 0; /* To avoid pushing the current list. */
-    update_liberties(s);
+    string[str_nr].liberties = 0; /* To avoid pushing the current list. */
+    update_liberties(str_nr);
   }
 
-  /* Remove s2 as neighbor to the neighbors of s2 and instead add s if
-   * they don't already have added it. Also add the neighbors of s2 as
-   * neighbors of s, unless they already have been added. The already
-   * known neighbors of s are assumed to have been marked before this
+  /* Remove the assimilated string as neighbor to the neighbors of the
+   * assimilated string and instead add str_nr if they don't already have
+   * added it. Also add the neighbors of the assimilated string as
+   * neighbors of str_nr, unless they already have been added. The already
+   * known neighbors of str_nr are assumed to have been marked before this
    * function is called.
    */
-  for (k = 0; k < string[s2].neighbors; k++) {
-    int t = string_neighbors[s2].list[k];
-    remove_neighbor(t, s2);
-    if (string[t].mark != string_mark) {
-      PUSH_VALUE(string[t].neighbors);
-      string_neighbors[t].list[string[t].neighbors++] = s;
-      string_neighbors[s].list[string[s].neighbors++] = t;
-      string[t].mark = string_mark;
+  for (k = 0; k < string[ass_nr].neighbors; k++) {
+    int neighbor_nr = string_neighbors[ass_nr].list[k];
+    remove_neighbor(neighbor_nr, ass_nr);
+    if (string[neighbor_nr].mark != string_mark) {
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      string_neighbors[neighbor_nr].list[string[neighbor_nr].neighbors++] = str_nr;
+      string_neighbors[str_nr].list[string[str_nr].neighbors++] = neighbor_nr;
+      string[neighbor_nr].mark = string_mark;
     }
   }
 }
@@ -3870,33 +4385,34 @@
  */
 
 static void
-assimilate_neighbor_strings(int pos)
+assimilate_neighbor_strings(int pos, int color)
 {
-  int s;
-  int color = board[pos];
+  int str_nr;
   int other = OTHER_COLOR(color);
+  int checked_pos;
+  int stone;
 
   /* Get the next free string number. */
   PUSH_VALUE(next_string);
-  s = next_string++;
-  PARANOID1(s < MAX_STRINGS, pos); 
-  string_number[pos] = s;
+  str_nr = next_string++;
+  PARANOID1(str_nr < MAX_STRINGS, pos); 
+  string_number[pos] = str_nr;
   /* Set up a size one cycle for the string. */
   next_stone[pos] = pos;
   
   /* Set trivially known values and initialize the rest to zero. */
-  string[s].color = color;
-  string[s].size = 1;
-  string[s].origin = pos;
-  string[s].liberties = 0;
-  string[s].neighbors = 0;
+  string[str_nr].color = color;
+  string[str_nr].size = 1;
+  string[str_nr].origin = pos;
+  string[str_nr].liberties = 0;
+  string[str_nr].neighbors = 0;
 
   /* Clear the marks. */
   liberty_mark++;
   string_mark++;
 
   /* Mark ourselves. */
-  string[s].mark = string_mark;
+  string[str_nr].mark = string_mark;
 
   /* Look in each direction for
    *
@@ -3905,62 +4421,90 @@
    *    neighbors, unless already visited.
    * 3. friendly string: Assimilate.
    */
-  if (UNMARKED_LIBERTY(SOUTH(pos))) {
-    ADD_AND_MARK_LIBERTY(s, SOUTH(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(SOUTH(pos), other)) {
-    ADD_NEIGHBOR(s, SOUTH(pos));
-    PUSH_VALUE(string[string_number[SOUTH(pos)]].neighbors);
-    ADD_NEIGHBOR(string_number[SOUTH(pos)], pos);
-    MARK_STRING(SOUTH(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(SOUTH(pos), color)) {
-    assimilate_string(s, SOUTH(pos));
-  }
-
-  if (UNMARKED_LIBERTY(WEST(pos))) {
-    ADD_AND_MARK_LIBERTY(s, WEST(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(WEST(pos), other)) {
-    ADD_NEIGHBOR(s, WEST(pos));
-    PUSH_VALUE(string[string_number[WEST(pos)]].neighbors);
-    ADD_NEIGHBOR(string_number[WEST(pos)], pos);
-    MARK_STRING(WEST(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(WEST(pos), color)) {
-    assimilate_string(s, WEST(pos));
-  }
-  
-  if (UNMARKED_LIBERTY(NORTH(pos))) {
-    ADD_AND_MARK_LIBERTY(s, NORTH(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(NORTH(pos), other)) {
-    ADD_NEIGHBOR(s, NORTH(pos));
-    PUSH_VALUE(string[string_number[NORTH(pos)]].neighbors);
-    ADD_NEIGHBOR(string_number[NORTH(pos)], pos);
-    MARK_STRING(NORTH(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(NORTH(pos), color)) {
-    assimilate_string(s, NORTH(pos));
-  }
-  
-  if (UNMARKED_LIBERTY(EAST(pos))) {
+  checked_pos = SOUTH(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY) {
+    if (ml[checked_pos] != liberty_mark)
+      ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
+  }
+  else if (stone == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
+  }
+  else if (stone == color) {
+    if (UNMARKED_STRING(string_number[checked_pos]))
+      assimilate_string(str_nr, checked_pos);
+  }
+
+  checked_pos = WEST(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY) {
+    if (ml[checked_pos] != liberty_mark)
+      ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
+  }
+  else if (stone == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
+  }
+  else if (stone == color) {
+    if (UNMARKED_STRING(string_number[checked_pos]))
+      assimilate_string(str_nr, checked_pos);
+  }
+  
+  checked_pos = NORTH(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY) {
+    if (ml[checked_pos] != liberty_mark)
+      ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
+  }
+  else if (stone == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
+      MARK_STRING(neighbor_nr);
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
+  }
+  else if (stone == color) {
+    if (UNMARKED_STRING(string_number[checked_pos]))
+      assimilate_string(str_nr, checked_pos);
+  }
+  
+  checked_pos = EAST(pos);
+  stone = board[checked_pos];
+  if (stone == EMPTY) {
+    if (ml[checked_pos] != liberty_mark)
 #if 0
-    ADD_AND_MARK_LIBERTY(s, EAST(pos));
+      ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
 #else
-    ADD_LIBERTY(s, EAST(pos));
+      ADD_LIBERTY(str_nr, checked_pos);
 #endif
   }
-  else if (UNMARKED_COLOR_STRING(EAST(pos), other)) {
-    ADD_NEIGHBOR(s, EAST(pos));
-    PUSH_VALUE(string[string_number[EAST(pos)]].neighbors);
-    ADD_NEIGHBOR(string_number[EAST(pos)], pos);
+  else if (stone == other) {
+    int neighbor_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(neighbor_nr)) {
 #if 0
-    MARK_STRING(EAST(pos));
+      MARK_STRING(neighbor_nr);
 #endif
+      ADD_NEIGHBOR(str_nr, neighbor_nr);
+      PUSH_VALUE(string[neighbor_nr].neighbors);
+      ADD_NEIGHBOR(neighbor_nr, str_nr);
+    }
   }
-  else if (UNMARKED_COLOR_STRING(EAST(pos), color)) {
-    assimilate_string(s, EAST(pos));
+  else if (stone == color) {
+    if (UNMARKED_STRING(string_number[checked_pos]))
+      assimilate_string(str_nr, checked_pos);
   }
 }
 
@@ -3994,7 +4538,8 @@
 
 /* Play a move without legality checking. This is a low-level function,
  * it assumes that the move is not a suicide. Such cases must be handled
- * where the function is called.
+ * where the function is called. Before the function is called, one has
+ * to store captured stones and board_ko_pos on the stack.
  */
 
 static void
@@ -4003,7 +4548,9 @@
   int other = OTHER_COLOR(color);
   int captured_stones = 0;
   int neighbor_allies = 0;
-  int s = -1;
+  int extend_nr = -1;
+  int checked_pos;
+  int str_nr;
 
   /* Clear string mark. */
   string_mark++;
@@ -4019,76 +4566,100 @@
    * color, remove captured strings and remove `pos' as liberty for opponent
    * strings that are not captured.
    */
-  if (board[SOUTH(pos)] == color) {
+  checked_pos = SOUTH(pos);
+  if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    MARK_STRING(str_nr);
     neighbor_allies++;
-    s = string_number[SOUTH(pos)];
-    MARK_STRING(SOUTH(pos));
+    extend_nr = str_nr;
   }
-  else if (board[SOUTH(pos)] == other) {
-    if (LIBERTIES(SOUTH(pos)) > 1) {
-      remove_liberty(string_number[SOUTH(pos)], pos);
-      MARK_STRING(SOUTH(pos));
+  else if (board[checked_pos] == other) {
+    str_nr = string_number[checked_pos];
+    if (LIBERTIES(str_nr) > 1) {
+      MARK_STRING(str_nr);
+      remove_liberty(str_nr, pos);
     }
     else
-      captured_stones += do_remove_string(string_number[SOUTH(pos)]);
+      captured_stones += do_remove_string(str_nr);
   }
 
-  if (UNMARKED_COLOR_STRING(WEST(pos), color)) {
-    neighbor_allies++;
-    s = string_number[WEST(pos)];
-    MARK_STRING(WEST(pos));
-  }
-  else if (UNMARKED_COLOR_STRING(WEST(pos), other)) {
-    if (LIBERTIES(WEST(pos)) > 1) {
-      remove_liberty(string_number[WEST(pos)], pos);
-      MARK_STRING(WEST(pos));
+  checked_pos = WEST(pos);
+  if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(str_nr)) {
+      MARK_STRING(str_nr);
+      neighbor_allies++;
+      extend_nr = str_nr;
+    }
+  }
+  else if (board[checked_pos] == other) {
+    str_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(str_nr)) {
+      if (LIBERTIES(str_nr) > 1) {
+        MARK_STRING(str_nr);
+        remove_liberty(str_nr, pos);
+      }
+      else
+        captured_stones += do_remove_string(str_nr);
     }
-    else
-      captured_stones += do_remove_string(string_number[WEST(pos)]);
   }
 
-  if (UNMARKED_COLOR_STRING(NORTH(pos), color)) {
-    neighbor_allies++;
-    s = string_number[NORTH(pos)];
-    MARK_STRING(NORTH(pos));
+  checked_pos = NORTH(pos);
+  if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(str_nr)) {
+      MARK_STRING(str_nr);
+      neighbor_allies++;
+      extend_nr = str_nr;
+    }
   }
-  else if (UNMARKED_COLOR_STRING(NORTH(pos), other)) {
-    if (LIBERTIES(NORTH(pos)) > 1) {
-      remove_liberty(string_number[NORTH(pos)], pos);
-      MARK_STRING(NORTH(pos));
+  else if (board[checked_pos] == other) {
+    str_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(str_nr)) {
+      if (LIBERTIES(str_nr) > 1) {
+        MARK_STRING(str_nr);
+        remove_liberty(str_nr, pos);
+      }
+      else
+        captured_stones += do_remove_string(str_nr);
     }
-    else
-      captured_stones += do_remove_string(string_number[NORTH(pos)]);
   }
 
-  if (UNMARKED_COLOR_STRING(EAST(pos), color)) {
-    neighbor_allies++;
-    s = string_number[EAST(pos)];
+  checked_pos = EAST(pos);
+  if (board[checked_pos] == color) {
+    str_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(str_nr)) {
 #if 0
-    MARK_STRING(EAST(pos));
+      MARK_STRING(str_nr);
 #endif
+      neighbor_allies++;
+      extend_nr = str_nr;
+    }
   }
-  else if (UNMARKED_COLOR_STRING(EAST(pos), other)) {
-    if (LIBERTIES(EAST(pos)) > 1) {
-      remove_liberty(string_number[EAST(pos)], pos);
+  else if (board[checked_pos] == other) {
+    str_nr = string_number[checked_pos];
+    if (UNMARKED_STRING(str_nr)) {
+      if (LIBERTIES(str_nr) > 1) {
 #if 0
-      MARK_STRING(EAST(pos));
+        MARK_STRING(str_nr);
 #endif
+        remove_liberty(str_nr, pos);
+      }
+      else
+        captured_stones += do_remove_string(str_nr);
     }
-    else
-      captured_stones += do_remove_string(string_number[EAST(pos)]);
   }
 
   /* Choose strategy depending on the number of friendly neighbors. */
   if (neighbor_allies == 0)
-    create_new_string(pos);
+    create_new_string(pos, color);
   else if (neighbor_allies == 1) {
-    gg_assert(s >= 0);
-    extend_neighbor_string(pos, s);
+    gg_assert(extend_nr >= 0);
+    extend_neighbor_string(pos, extend_nr, color);
     return; /* can't be a ko, we're done */
   }
   else {
-    assimilate_neighbor_strings(pos);
+    assimilate_neighbor_strings(pos, color);
     return; /* can't be a ko, we're done */
   }
 
@@ -4098,14 +4669,14 @@
    * No need to push board_ko_pos on the stack, 
    * because this has been done earlier.
    */
-  s = string_number[pos];
-  if (string[s].liberties == 1
-      && string[s].size == 1
+  str_nr = string_number[pos];
+  gg_assert(string[str_nr].size == 1); /* true if neighbor_allies == 0 */
+  if (string[str_nr].liberties == 1
       && captured_stones == 1) {
     /* In case of a double ko: clear old ko position first. */
     if (board_ko_pos != NO_MOVE)
       hashdata_invert_ko(&board_hash, board_ko_pos);
-    board_ko_pos = string_libs[s].list[0];
+    board_ko_pos = string_libs[str_nr].list[0];
     hashdata_invert_ko(&board_hash, board_ko_pos);
   }
 }
@@ -4124,12 +4695,14 @@
  */
 #define NO_UNROLL 0
 void
-incremental_order_moves(int move, int color, int str,
+incremental_order_moves(int move, int color, int target_pos,
 			int *number_edges, int *number_same_string,
 			int *number_own, int *number_opponent,
 			int *captured_stones, int *threatened_stones,
 			int *saved_stones, int *number_open)
 {
+  int target_nr = string_number[target_pos];
+
 #if NO_UNROLL == 1
   int pos;
   int k;
@@ -4145,7 +4718,7 @@
       (*number_open)++;
     else {
       int s = string_number[pos];
-      if (string_number[str] == s)
+      if (target_nr == s)
 	(*number_same_string)++;
       
       if (board[pos] == color) {
@@ -4165,44 +4738,44 @@
 	      (*saved_stones) += t->size;
 	  }
 	}
-	else if (string[s].liberties == 2 && UNMARKED_STRING(pos)) {
+	else if (string[s].liberties == 2 && UNMARKED_STRING(s)) {
 	  (*threatened_stones) += string[s].size;
-	  MARK_STRING(pos);
+	  MARK_STRING(s);
 	}
       }
     }
   }
   
 #else
-#define code1(arg) \
-  if (!ON_BOARD(arg)) \
+#define code1(pos, stone) \
+  if (stone == GRAY) \
     (*number_edges)++; \
-  else if (board[arg] == EMPTY) \
+  else if (stone == EMPTY) \
     (*number_open)++; \
   else { \
-    int s = string_number[arg]; \
-    if (string_number[str] == s) \
+    int str_nr = string_number[pos]; \
+    if (target_nr == str_nr) \
       (*number_same_string)++; \
-    if (board[arg] == color) { \
+    if (stone == color) { \
       (*number_own)++; \
-      if (string[s].liberties == 1) \
-	(*saved_stones) += string[s].size; \
+      if (string[str_nr].liberties == 1) \
+	(*saved_stones) += string[str_nr].size; \
     } \
     else { \
       (*number_opponent)++; \
-      if (string[s].liberties == 1) { \
+      if (string[str_nr].liberties == 1) { \
 	int r; \
-	struct string_data *t; \
-	(*captured_stones) += string[s].size; \
-	for (r = 0; r < string[s].neighbors; r++) { \
-	  t = &string[string_neighbors[s].list[r]]; \
-	  if (t->liberties == 1) \
-	    (*saved_stones) += t->size; \
+	int *neighbors_list = string_neighbors[str_nr].list; \
+	int neighbors = string[str_nr].neighbors; \
+	(*captured_stones) += string[str_nr].size; \
+	for (r = 0; r < neighbors; r++) { \
+	  if (string[neighbors_list[r]].liberties == 1) \
+	    (*saved_stones) += string[neighbors_list[r]].size; \
 	} \
       } \
-      else if (string[s].liberties == 2 && UNMARKED_STRING(arg)) { \
-	(*threatened_stones) += string[s].size; \
-        MARK_STRING(arg); \
+      else if (string[str_nr].liberties == 2 && UNMARKED_STRING(str_nr)) { \
+	MARK_STRING(str_nr); \
+	(*threatened_stones) += string[str_nr].size; \
       } \
     } \
   }
@@ -4210,10 +4783,25 @@
   /* Clear the string mark. */
   string_mark++;
 
-  code1(SOUTH(move));
-  code1(WEST(move));
-  code1(NORTH(move));
-  code1(EAST(move));
+  {
+    int checked_pos, checked_stone;
+
+    checked_pos = SOUTH(move);
+    checked_stone = board[checked_pos];
+    code1(checked_pos, checked_stone);
+
+    checked_pos = WEST(move);
+    checked_stone = board[checked_pos];
+    code1(checked_pos, checked_stone);
+
+    checked_pos = NORTH(move);
+    checked_stone = board[checked_pos];
+    code1(checked_pos, checked_stone);
+
+    checked_pos = EAST(move);
+    checked_stone = board[checked_pos];
+    code1(checked_pos, checked_stone);
+  }
 #endif
 }
 
Index: gnugo/engine/board.h
===================================================================
RCS file: /sources/gnugo/gnugo/engine/board.h,v
retrieving revision 1.34
diff -u -r1.34 board.h
--- gnugo/engine/board.h	18 May 2006 04:09:28 -0000	1.34
+++ gnugo/engine/board.h	30 Dec 2006 20:55:26 -0000
@@ -36,7 +36,13 @@
  * character access is very slow.
  */
 
+/* simple test for old machines */
+#if SIZEOF_INT >= 4
+#define INT_INTERSECTION
+typedef int Intersection;
+#else
 typedef unsigned char Intersection;
+#endif
 
 /* FIXME: This is very ugly but we can't include hash.h until we have
  * defined Intersection. And we do need to include it before using
@@ -135,6 +141,7 @@
 
 /* Note that POS(-1, -1) == 0
  * DELTA() is defined so that POS(i+di, j+dj) = POS(i, j) + DELTA(di, dj).
+ * For details look in the documentation.
  */
 #define BOARDSIZE     ((MAX_BOARD + 2) * (MAX_BOARD + 1) + 1)
 #define BOARDMIN      (MAX_BOARD + 2)
@@ -148,17 +155,17 @@
 #define NS            (MAX_BOARD + 1)
 #define WE            1
 #define SOUTH(pos)    ((pos) + NS)
-#define WEST(pos)     ((pos) - 1)
+#define WEST(pos)     ((pos) - WE)
 #define NORTH(pos)    ((pos) - NS)
-#define EAST(pos)     ((pos) + 1)
-#define SW(pos)       ((pos) + NS - 1)
-#define NW(pos)       ((pos) - NS - 1)
-#define NE(pos)       ((pos) - NS + 1)
-#define SE(pos)       ((pos) + NS + 1)
+#define EAST(pos)     ((pos) + WE)
+#define SW(pos)       ((pos) + NS - WE)
+#define NW(pos)       ((pos) - NS - WE)
+#define NE(pos)       ((pos) - NS + WE)
+#define SE(pos)       ((pos) + NS + WE)
 #define SS(pos)       ((pos) + 2 * NS)
-#define WW(pos)       ((pos) - 2)
+#define WW(pos)       ((pos) - 2 * WE)
 #define NN(pos)       ((pos) - 2 * NS)
-#define EE(pos)       ((pos) + 2)
+#define EE(pos)       ((pos) + 2 * WE)
 
 #define DIRECT_NEIGHBORS(pos1, pos2)		\
   ((pos1) == SOUTH(pos2)			\
@@ -260,8 +267,6 @@
 /* Functions handling the permanent board state. */
 void clear_board(void);
 int test_gray_border(void);
-void setup_board(Intersection new_board[MAX_BOARD][MAX_BOARD], int ko_pos,
-                 int *last, float new_komi, int w_captured, int b_captured);
 void add_stone(int pos, int color);
 void remove_stone(int pos);
 void play_move(int pos, int color);
@@ -277,7 +282,7 @@
 int stones_on_board(int color);
 
 /* Functions handling the variable board state. */
-int trymove(int pos, int color, const char *message, int str);
+int trymove(int pos, int color, const char *message, int str_pos);
 int tryko(int pos, int color, const char *message);
 void popgo(void);
 int komaster_trymove(int pos, int color,
@@ -291,6 +296,8 @@
 void dump_stack(void);
 void do_dump_stack(void);
 
+void dump_incremental_board(void);
+
 void reset_trymove_counter(void);
 int get_trymove_counter(void);
 
@@ -312,38 +319,39 @@
 int square_dist(int pos1, int pos2);
 
 /* Basic string information. */
-int find_origin(int str);
-int chainlinks(int str, int adj[MAXCHAIN]);
-int chainlinks2(int str, int adj[MAXCHAIN], int lib);
-int chainlinks3(int str, int adj[MAXCHAIN], int lib);
-int extended_chainlinks(int str, int adj[MAXCHAIN], int both_colors);
-
-int liberty_of_string(int pos, int str);
-int second_order_liberty_of_string(int pos, int str);
-int neighbor_of_string(int pos, int str);
+int find_origin(int str_pos);
+int chainlinks(int str_pos, int adj[MAXCHAIN]);
+int chainlinks2(int str_pos, int adj[MAXCHAIN], int lib);
+int chainlinks3(int str_pos, int adj[MAXCHAIN], int lib);
+int extended_chainlinks(int str_pos, int adj[MAXCHAIN], int both_colors);
+
+int liberty_of_string(int pos, int str_pos);
+int liberty_of_string2(int pos, int str_pos);
+int second_order_liberty_of_string(int pos, int str_pos);
+int neighbor_of_string(int pos, int str_pos);
 int has_neighbor(int pos, int color);
-int same_string(int str1, int str2);
-int adjacent_strings(int str1, int str2);
+int same_string(int str1_pos, int str2_pos);
+int adjacent_strings(int str1_pos, int str2_pos);
 void mark_string(int str, signed char mx[BOARDMAX], signed char mark);
 int are_neighbors(int pos1, int pos2);
 
-/* Count and/or find liberties at (pos). */
-int countlib(int str);
-int findlib(int str, int maxlib, int *libs);
+/* Count and/or find liberties at (pos) */
+int countlib(int str_pos);
+int findlib(int str_pos, int maxlib, int *libs);
 int fastlib(int pos, int color, int ignore_captures);
 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);
+int count_common_libs(int str1_pos, int str2_pos);
+int find_common_libs(int str1_pos, int str2_pos, int maxlib, int *libs);
+int have_common_lib(int str1_pos, int str2_pos, int *lib);
 
 /* Count the number of stones in a string. */
-int countstones(int str);
-int findstones(int str, int maxstones, int *stones);
-int count_adjacent_stones(int str1, int str2, int maxstones);
+int countstones(int str_pos);
+int findstones(int str_pos, int maxstones, int *stones);
+int count_adjacent_stones(int str1_pos, int str2_pos, int maxstones);
 
 /* Special function for reading.c */
-void incremental_order_moves(int move, int color, int string,
+void incremental_order_moves(int move, int color, int target_pos,
 			     int *number_edges, int *number_same_string,
 			     int *number_own, int *number_opponent,
 			     int *captured_stones, int *threatened_stones,
@@ -381,9 +389,9 @@
  * south, west, north, east, southwest, northwest, northeast, southeast.
  * Defined in board.c.
  */
-extern int deltai[8]; /* = { 1,  0, -1,  0,  1, -1, -1, 1}; */
-extern int deltaj[8]; /* = { 0, -1,  0,  1, -1, -1,  1, 1}; */
-extern int delta[8];  /* = { NS, -1, -NS, 1, NS-1, -NS-1, -NS+1, NS+1}; */
+extern const int deltai[8]; /* = { 1,  0, -1,  0,  1, -1, -1, 1}; */
+extern const int deltaj[8]; /* = { 0, -1,  0,  1, -1, -1,  1, 1}; */
+extern const int delta[8];  /* = { NS, -WE, -NS, WE, NS-WE, -NS-WE, -NS+WE, NS+WE}; */
 
 
 
Index: gnugo/engine/boardlib.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/boardlib.c,v
retrieving revision 1.12
diff -u -r1.12 boardlib.c
--- gnugo/engine/boardlib.c	18 May 2006 04:09:28 -0000	1.12
+++ gnugo/engine/boardlib.c	30 Dec 2006 20:55:26 -0000
@@ -29,7 +29,7 @@
 /* The board state itself. */
 int          board_size = DEFAULT_BOARD_SIZE; /* board size */
 Intersection board[BOARDSIZE];
-int          board_ko_pos;
+int          board_ko_pos;	/* Position of a ko (captured stone). */
 int          white_captured;    /* number of black and white stones captured */
 int          black_captured;
 
@@ -54,7 +54,7 @@
 /* Hashing of positions. */
 Hash_data board_hash;
 
-int stackp;             /* stack pointer */
+int stackp;             /* moves stack depth */
 int position_number;    /* position number */
 
 /* Some statistics gathered partly in board.c and hash.c */
Index: gnugo/engine/cache.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/cache.c,v
retrieving revision 1.50
diff -u -r1.50 cache.c
--- gnugo/engine/cache.c	23 Jan 2006 18:15:50 -0000	1.50
+++ gnugo/engine/cache.c	30 Dec 2006 20:55:27 -0000
@@ -72,7 +72,7 @@
 calculate_hashval_for_tt(Hash_data *hashdata, int routine, int target1,
 			 int target2, Hash_data *extra_hash)
 { 
-  *hashdata = board_hash;                /* from globals.c */
+  *hashdata = board_hash;                /* from boardlib.c */
   hashdata_xor(*hashdata, routine_hash[routine]);
   hashdata_xor(*hashdata, target1_hash[target1]);
   if (target2 != NO_MOVE)
@@ -97,19 +97,18 @@
   keyhash_init();
 
   if (memsize > 0)
-    num_entries = memsize / sizeof(table->entries[0]);
+    num_entries = memsize / sizeof(Hashentry);
   else
     num_entries = DEFAULT_NUMBER_OF_CACHE_ENTRIES;
 
   table->num_entries = num_entries;
-  table->entries     = malloc(num_entries * sizeof(table->entries[0]));
+  table->entries     = malloc(num_entries * sizeof(Hashentry));
 
   if (table->entries == NULL) {
     perror("Couldn't allocate memory for transposition table. \n");
     exit(1);
   }
 
-  table->is_clean = 0;
   tt_clear(table);
 }
 
@@ -119,13 +118,10 @@
 static void
 tt_clear(Transposition_table *table)
 {
-  if (!table->is_clean) {
-    memset(table->entries, 0, table->num_entries * sizeof(table->entries[0]));
-    table->is_clean = 1;
-  }
+  memset(table->entries, 0, table->num_entries * sizeof(Hashentry));
 }
- 
- 
+
+
 /* Free the transposition table. */
 
 void
@@ -135,11 +131,12 @@
 }
 
 
-/* Get result and move. Return value:
+/* Get result and move (the bigger remaining depth the lower depth).
+ * Return value:
  *   0 if not found
- *   1 if found, but depth too small to be trusted.  In this case the move
+ *   1 if found, but depth too big to be trusted.  In this case the move
  *     can be used for move ordering.
- *   2 if found and depth is enough so that the result can be trusted.
+ *   2 if found and depth is small enough so that the result can be trusted.
  */
  
 int
@@ -162,14 +159,17 @@
 
   /* Get the correct entry and node. */
   entry = &table->entries[hashdata_remainder(hashval, table->num_entries)];
-  if (hashdata_is_equal(hashval, entry->deepest.key))
-    node = &entry->deepest;
+
+  if (hashdata_is_equal(hashval, entry->most_reliable.key))
+    node = &entry->most_reliable;
   else if (hashdata_is_equal(hashval, entry->newest.key))
     node = &entry->newest;
   else
     return 0;
 
-  stats.read_result_hits++;
+#ifndef GG_TURN_OFF_STATS
+  ++stats.read_result_hits;
+#endif
 
   /* Return data.  Only set the result if remaining depth in the table
    * is big enough to be trusted.  The move can always be used for move
@@ -177,12 +177,17 @@
    */
   if (move)
     *move = hn_get_move(node->data);
+
   if (remaining_depth <= (int) hn_get_remaining_depth(node->data)) {
     if (value1)
       *value1 = hn_get_value1(node->data);
     if (value2)
       *value2 = hn_get_value2(node->data);
-    stats.trusted_read_result_hits++;
+
+#ifndef GG_TURN_OFF_STATS
+    ++stats.trusted_read_result_hits;
+#endif
+
     return 2;
   }
 
@@ -201,7 +206,7 @@
 {
   Hash_data hashval;
   Hashentry *entry;
-  Hashnode *deepest;
+  Hashnode *most_reliable;
   Hashnode *newest;
   unsigned int data;
   /* Get routine costs definitions from liberty.h. */
@@ -220,48 +225,53 @@
 
   /* Get the entry and nodes. */ 
   entry = &table->entries[hashdata_remainder(hashval, table->num_entries)];
-  deepest = &entry->deepest;
+  most_reliable = &entry->most_reliable;
   newest  = &entry->newest;
  
   /* See if we found an already existing node. */
-  if (hashdata_is_equal(hashval, deepest->key)
-      && remaining_depth >= (int) hn_get_remaining_depth(deepest->data)) {
-
-    /* Found deepest */
-    deepest->data = data;
-
+  if (hashdata_is_equal(hashval, most_reliable->key))
+  {
+    /* Found shallower node (can be trusted more likely) */
+    if (remaining_depth > (int) hn_get_remaining_depth(most_reliable->data))
+      most_reliable->data = data;
   }
-  else if (hashdata_is_equal(hashval, newest->key)
-           && remaining_depth >= (int) hn_get_remaining_depth(newest->data)) {
-
+  else if (hashdata_is_equal(hashval, newest->key))
+  {
     /* Found newest */
-    newest->data = data;
-
-    /* If newest has become deeper than deepest, then switch them. */
-    if (hn_get_remaining_depth(newest->data)
-	> hn_get_remaining_depth(deepest->data)) {
-      Hashnode temp;
-
-      temp = *deepest;
-      *deepest = *newest;
-      *newest = temp;
+    if (remaining_depth > (int) hn_get_remaining_depth(newest->data))
+    {
+      newest->data = data;
+
+      /* If newest reliability is bigger than most_reliable, switch them. */
+      if (hn_get_reliability(newest->data) >
+          hn_get_reliability(most_reliable->data))
+      {
+        Hashnode temp;
+
+        temp = *most_reliable;
+        *most_reliable = *newest;
+        *newest = temp;
+      }
     }
-
   }
-  else if (hn_get_total_cost(data) > hn_get_total_cost(deepest->data)) {
-    if (hn_get_total_cost(newest->data) < hn_get_total_cost(deepest->data))
-      *newest = *deepest;
-    deepest->key  = hashval;
-    deepest->data = data;
-  } 
-  else {
+  /* Have new node. */
+  else if (hn_get_reliability(data) >
+           hn_get_reliability(most_reliable->data))
+  {
+    /* Replace most_reliable. */
+    most_reliable->key  = hashval;
+    most_reliable->data = data;
+  }
+  else
+  {
     /* Replace newest. */
     newest->key  = hashval;
     newest->data = data;
   }
 
-  stats.read_result_entered++;
-  table->is_clean = 0;
+#ifndef GG_TURN_OFF_STATS
+  ++stats.read_result_entered;
+#endif
 }
 
 
Index: gnugo/engine/cache.h
===================================================================
RCS file: /sources/gnugo/gnugo/engine/cache.h,v
retrieving revision 1.54
diff -u -r1.54 cache.h
--- gnugo/engine/cache.h	23 Jan 2006 18:15:50 -0000	1.54
+++ gnugo/engine/cache.h	30 Dec 2006 20:55:27 -0000
@@ -32,16 +32,26 @@
  * (Reading/Hashing) for more information.  
  */
 
+#if SIZEOF_INT == 4
+  typedef unsigned int HASHNODE_DATATYPE;
+#elif SIZEOF_LONG == 4
+  typedef unsigned long HASHNODE_DATATYPE;
+#elif SIZEOF_INT > 4
+  typedef unsigned short HASHNODE_DATATYPE;
+#elif
+  #error Long type size has to be at least 4 bytes.
+#endif
 
 /* Hashnode: a node stored in the transposition table.
  *
  * In addition to the position, the hash lock encodes the following data,
  * all hashed:
- *   komaster
- *   kom_pos
+ *   ko
+ *   komaster (look in doc)
+ *   kom_pos (look in doc)
  *   routine
- *   str1
- *   str2
+ *   target1
+ *   target2
  *   extra hashvalue, optional (e.g. encoding a goal array)
  *
  * The data field packs into 32 bits the following
@@ -54,11 +64,13 @@
  *   cost           :  4 bits
  *   remaining_depth:  5 bits (depth - stackp)  NOTE: HN_MAX_REMAINING_DEPTH
  *
- *   The last 9 bits together give an index for the total costs.
+ *   The last 9 bits together give a reliability index (bigger index means
+ *   more reliable result).
+ *   Values are results of analyzed position (WIN, LOSE, etc.)
  */
 typedef struct {
   Hash_data key;
-  unsigned int data; /* Should be 32 bits, but only wastes 25% if 64 bits. */
+  HASHNODE_DATATYPE data; /* 32-bit value */
 } Hashnode;
 
 #define HN_MAX_REMAINING_DEPTH 31
@@ -67,7 +79,7 @@
 /* Hashentry: an entry, with two nodes of the hash_table
  */
 typedef struct {
-  Hashnode deepest;
+  Hashnode most_reliable;
   Hashnode newest;
 } Hashentry;
 
@@ -76,22 +88,21 @@
 #define hn_get_value2(hn)           ((hn >> 19) & 0x0f)
 #define hn_get_move(hn)             ((hn >>  9) & 0x3ff)
 #define hn_get_cost(hn)             ((hn >>  5) & 0x0f)
-#define hn_get_remaining_depth(hn)  ((hn >>  0) & 0x1f)
-#define hn_get_total_cost(hn)       ((hn >>  0) & 0x1ff)
+#define hn_get_remaining_depth(hn)  ((hn/*>>  0*/) & 0x1f)
+#define hn_get_reliability(hn)      ((hn/*>>  0*/) & 0x1ff)
 
 #define hn_create_data(remaining_depth, value1, value2, move, cost) \
     ((((value1)         & 0x0f)  << 23) \
    | (((value2)         & 0x0f)  << 19) \
    | (((move)           & 0x3ff) <<  9) \
    | (((cost)           & 0x0f)  <<  5) \
-   | (((remaining_depth & 0x1f)  <<  0)))
+   | (((remaining_depth & 0x1f)/*<<  0*/)))
 
 
 /* Transposition_table: transposition table used for caching. */
 typedef struct {
   unsigned int num_entries;
   Hashentry *entries;
-  int is_clean;
 } Transposition_table;
 
 extern Transposition_table ttable;
@@ -141,11 +152,15 @@
   int q1 = board[str1] == EMPTY ? str1 : find_origin(str1); \
   int q2 = board[str2] == EMPTY ? str2 : find_origin(str2);
 
+#define READ_FUNCTION_NAME read_function_name
+
 #else
 
 #define TRACE_CACHED_RESULT(result, move)
 #define TRACE_CACHED_RESULT2(result1, result2, move)
 
+#ifndef GG_TURN_OFF_TRACES
+
 #define SETUP_TRACE_INFO(name, str) \
   const char *read_function_name = name; \
   int q = str;
@@ -155,18 +170,6 @@
   int q1 = str1; \
   int q2 = str2;
 
-#endif
-
-/* Trace messages in decidestring/decidedragon sgf file. */
-void sgf_trace(const char *func, int str, int move, int result,
-	       const char *message);
-/* Trace messages in decideconnection sgf file. */
-void sgf_trace2(const char *func, int str1, int str2, int move, 
-	        const char *result, const char *message);
-/* Trace messages in decidesemeai sgf file. */
-void sgf_trace_semeai(const char *func, int str1, int str2, int move, 
-		      int result1, int result2, const char *message);
-
 /* Macro to hide the call to sgf_trace(). Notice that a little black
  * magic is going on here. Before using this macro, SETUP_TRACE_INFO
  * must have been called to provide the variables read_function_name
@@ -190,6 +193,31 @@
     sgf_trace_semeai(read_function_name, q1, q2, move, \
 	             result1, result2, message)
 
+#define READ_FUNCTION_NAME read_function_name
+
+#else // #ifndef GG_TURN_OFF_TRACES
+
+#define SETUP_TRACE_INFO(name, str)
+#define SETUP_TRACE_INFO2(name, str1, str2)
+#define SGFTRACE(move, result, message) (void)0
+#define SGFTRACE2(move, result, message) (void)0
+#define SGFTRACE_SEMEAI(move, result1, result2, message) (void)0
+#define READ_FUNCTION_NAME NULL
+
+#endif // #ifndef GG_TURN_OFF_TRACES
+
+#endif // #if TRACE_READ_RESULTS
+
+/* Trace messages in decidestring/decidedragon sgf file. */
+void sgf_trace(const char *func, int str, int move, int result,
+	       const char *message);
+/* Trace messages in decideconnection sgf file. */
+void sgf_trace2(const char *func, int str1, int str2, int move, 
+	        const char *result, const char *message);
+/* Trace messages in decidesemeai sgf file. */
+void sgf_trace_semeai(const char *func, int str1, int str2, int move, 
+		      int result1, int result2, const char *message);
+
 
 /* ================================================================ */
 
@@ -212,7 +240,8 @@
   do { \
     tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\
               value, 0, move);\
-    if ((value) != 0 && (point) != 0) *(point) = (move); \
+    if ((point) != NULL && (value) != 0) \
+      *(point) = (move); \
     return (value); \
   } while (0)
 
@@ -220,7 +249,8 @@
   do { \
     tt_update(&ttable, routine, str1, str2, remaining_depth, NULL, \
               value1, value2, move); \
-    if ((value1) != 0 && (point) != 0) *(point) = (move); \
+    if ((point) != NULL && (value1) != 0) \
+      *(point) = (move); \
     return; \
   } while (0)
 
@@ -228,7 +258,8 @@
   do { \
     tt_update(&ttable, routine, str1, str2, remaining_depth, NULL,\
               value, 0, move);\
-    if ((value) != 0 && (point) != 0) *(point) = (move); \
+    if ((point) != NULL && (value) != 0) \
+      *(point) = (move); \
     return (value); \
   } while (0)
 
@@ -236,7 +267,8 @@
   do { \
     tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, hash,\
               value, 0, move);\
-    if ((value) != 0 && (point) != 0) *(point) = (move); \
+    if ((point) != NULL && (value) != 0) \
+      *(point) = (move); \
     return (value); \
   } while (0)
 
@@ -244,7 +276,8 @@
   do { \
     tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\
               value1, value2, move);\
-    if ((value1) != 0 && (point) != 0) *(point) = (move); \
+    if ((point) != NULL && (value1) != 0) \
+      *(point) = (move); \
     return (value1); \
   } while (0)
 
Index: gnugo/engine/clock.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/clock.c,v
retrieving revision 1.26
diff -u -r1.26 clock.c
--- gnugo/engine/clock.c	23 Jan 2006 18:15:50 -0000	1.26
+++ gnugo/engine/clock.c	30 Dec 2006 20:55:27 -0000
@@ -38,6 +38,7 @@
 #include "clock.h"
 #include "gg_utils.h"
 #include "board.h"
+#include "gnugo.h"
 
 /* Level data */
 static int level             = DEFAULT_LEVEL; /* current level */
@@ -68,8 +69,8 @@
 };
 
 struct timer_data {
-  struct remaining_time_data official;
-  struct remaining_time_data estimated;
+  struct remaining_time_data official; // time received from external source
+  struct remaining_time_data estimated; // time counted by GnuGO
   int time_out;
 };
 
@@ -220,23 +221,28 @@
   static int last_movenum = -1;
   struct timer_data* const td
     = (color == BLACK) ? &black_time_data : &white_time_data;
-  double now = gg_gettimeofday();
+  double now;
 
   if (!have_time_settings())
     return;
 
+  now = gg_gettimeofday();
+
   if (last_movenum >= 0
-      && movenum == last_movenum + 1
-      && movenum > td->estimated.movenum) {
+      && movenum == last_movenum + 1) {
     double time_used = now - last_time;
     td->estimated.time_left -= time_used;
     td->estimated.movenum = movenum;
     td->estimated.time_for_last_move = time_used;
     if (td->estimated.time_left < 0) {
       if (td->estimated.in_byoyomi || byoyomi_stones == 0) {
+
+#ifndef GG_TURN_OFF_DEBUGS
 	DEBUG(DEBUG_TIME, "%s ran out of time.\n", color_to_string(color));
 	if (debug & DEBUG_TIME)
 	  clock_print(color);
+#endif
+
 	td->time_out = 1;
       }
       else {
@@ -251,7 +257,7 @@
     }
     else if (td->estimated.stones > 0) {
       gg_assert(td->estimated.in_byoyomi);
-      td->estimated.stones = td->estimated.stones - 1;
+      --td->estimated.stones;
       if (td->estimated.stones == 0) {
 	td->estimated.time_left = byoyomi_time;
 	td->estimated.stones = byoyomi_stones;
@@ -262,9 +268,11 @@
   last_movenum = movenum;
   last_time = now;
 
+#ifndef GG_TURN_OFF_DEBUGS
   /* Update main timer. */
   if (debug & DEBUG_TIME)
     clock_print(color);
+#endif
 }
 
 
@@ -297,9 +305,12 @@
 
   if (timer->stones == 0) {
     /* Main time running. */
-    *time_left = timer->time_left + byoyomi_time;
+    *time_left = timer->time_left;
     if (byoyomi_time > 0)
+    {
+      *time_left += byoyomi_time;
       *stones_left = byoyomi_stones;
+    }
     else {
       /* Absolute time. Here we aim to be able to play at least X more
        * moves or a total of Y moves. We choose Y as a third of the
@@ -331,7 +342,7 @@
 adjust_level_offset(int color)
 {
   double time_for_last_move;
-  double time_left;
+  double time_left, estimated_time;
   int stones_left;
 
   if (!analyze_time_data(color, &time_for_last_move, &time_left, &stones_left))
@@ -342,28 +353,39 @@
    *
    * FIXME: Use rules with at least some theoretical basis.
    */
-  if (time_left < time_for_last_move * (stones_left + 3))
-    level_offset--;
-  if (time_left < time_for_last_move * stones_left)
-    level_offset--;
-  if (3 * time_left < 2 * time_for_last_move * stones_left)
-    level_offset--;
-  if (2 * time_left < time_for_last_move * stones_left)
-    level_offset--;
-  if (3 * time_left < time_for_last_move * stones_left)
-    level_offset--;
-
-  if (time_for_last_move == 0)
-    time_for_last_move = 1;
-  if (time_left > time_for_last_move * (stones_left + 6))
-    level_offset++;
-  if (time_left > 2 * time_for_last_move * (stones_left + 6))
-    level_offset++;
+  if (time_for_last_move < 0.1)
+    time_for_last_move = 0.1;
+
+  estimated_time = time_for_last_move * stones_left;
+
+  if (time_left < estimated_time)
+  {
+    --level_offset;
+
+    if (1.33 * time_left < estimated_time)
+    {
+      --level_offset;
+
+      if (2 * time_left < estimated_time)
+      {
+        level_offset -= 2;
+
+        if (4 * time_left < estimated_time)
+          level_offset -= 2;
+      }
+    }
+  }
+  else if (0.8 * time_left > estimated_time)
+  {
+    ++level_offset;
+
+    if (0.5 * time_left > estimated_time)
+      level_offset += 2;
+  }
 
   if (level + level_offset < min_level)
     level_offset = min_level - level;
-
-  if (level + level_offset > max_level)
+  else if (level + level_offset > max_level)
     level_offset = max_level - level;
 
   DEBUG(DEBUG_TIME, "New level %d (%d %C %f %f %d)\n", level + level_offset,
Index: gnugo/engine/combination.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/combination.c,v
retrieving revision 1.57
diff -u -r1.57 combination.c
--- gnugo/engine/combination.c	4 Feb 2006 10:17:17 -0000	1.57
+++ gnugo/engine/combination.c	30 Dec 2006 20:55:28 -0000
@@ -889,7 +889,7 @@
       continue;
     
     if (board[last_friendly] == EMPTY
-	&& !liberty_of_string(last_friendly, pos))
+	&& !liberty_of_string2(last_friendly, pos))
       continue;
     
     if (debug & DEBUG_ATARI_ATARI)
Index: gnugo/engine/endgame.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/endgame.c,v
retrieving revision 1.13
diff -u -r1.13 endgame.c
--- gnugo/engine/endgame.c	23 Jan 2006 18:15:50 -0000	1.13
+++ gnugo/engine/endgame.c	30 Dec 2006 20:55:29 -0000
@@ -461,8 +461,10 @@
   int liberties;
   int libs[MAXLIBS];
   int k;
+  int color = board[str];
+  int origin = find_origin(str);
 
-  ASSERT1(IS_STONE(board[str]), str);
+  ASSERT1(IS_STONE(color), str);
 
   *essential_liberties = 0;
   *inessential_liberties = 0;
@@ -494,8 +496,8 @@
 	if (worm[pos].attack_codes[0] != 0 || dragon[pos].status != ALIVE)
 	  return 0;
 
-	if (board[pos] == board[str]) {
-	  if (find_origin(pos) != find_origin(str))
+	if (board[pos] == color) {
+	  if (find_origin(pos) != origin)
 	    essential = 1;
 	}
 	else
Index: gnugo/engine/filllib.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/filllib.c,v
retrieving revision 1.37
diff -u -r1.37 filllib.c
--- gnugo/engine/filllib.c	17 Apr 2006 07:56:14 -0000	1.37
+++ gnugo/engine/filllib.c	30 Dec 2006 20:55:30 -0000
@@ -310,13 +310,13 @@
       DEBUG(DEBUG_FILLLIB,
 	    "Filllib: Nothing found, looking for threat to back-capture.\n");
       for (k = 0; k < 4; k++) {
-	int d = delta[k];
-	if (board[pos + d] == other
-	    && worm[pos + d].attack_codes[0] != 0) {
+	int checked_pos = pos + delta[k];
+	if (board[checked_pos] == other
+	    && worm[checked_pos].attack_codes[0] != 0) {
 	  /* Just pick some other liberty. */
 	  /* FIXME: Something is odd about this code. */
 	  int libs[2];
-	  if (findlib(pos + d, 2, libs) > 1) {
+	  if (findlib(checked_pos, 2, libs) > 1) {
 	    if (is_legal(libs[0], color))
 	      *move = libs[0];
 	    else if (is_legal(libs[1], color))
@@ -435,7 +435,7 @@
       if (attack(adjs[k], &bpos) == WIN) {
 	if (forbidden_moves[bpos])
 	  continue;
-	if (liberty_of_string(bpos, adjs[k])) {
+	if (liberty_of_string2(bpos, adjs[k])) {
 	  *backfill_move = bpos;
 	  return 1;
 	}
@@ -464,7 +464,7 @@
 	if (attack(adjs[k], &bpos) == WIN) {
 	  if (forbidden_moves[bpos])
 	    continue;
-	  if (liberty_of_string(bpos, adjs[k])) {
+	  if (liberty_of_string2(bpos, adjs[k])) {
 	    *backfill_move = bpos;
 	    return 1;
 	  }
@@ -496,7 +496,7 @@
     popgo();
     for (k = 0; k < neighbors; k++) {
       if (attack(adjs[k], &bpos) == WIN) {
-	if (!forbidden_moves[bpos] && liberty_of_string(bpos, adjs[k])) {
+	if (!forbidden_moves[bpos] && liberty_of_string2(bpos, adjs[k])) {
 	  *backfill_move = bpos;
 	  return 1;
 	}
Index: gnugo/engine/genmove.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/genmove.c,v
retrieving revision 1.116
diff -u -r1.116 genmove.c
--- gnugo/engine/genmove.c	17 Sep 2006 23:29:22 -0000	1.116
+++ gnugo/engine/genmove.c	30 Dec 2006 20:55:30 -0000
@@ -73,6 +73,9 @@
 void
 reset_engine()
 {
+  static int last_level = -1;
+  int act_level;
+
   /* To improve the reproducability of games, we restart the random
    * number generator with the same seed for each move. Thus we don't
    * have to know how many previous moves have been played, nor
@@ -98,7 +101,12 @@
   clear_break_in_list();
 
   /* Set up depth values (see comments there for details). */
-  set_depth_values(get_level(), 0);
+  act_level = get_level();
+  if (last_level != act_level)
+  {
+    set_depth_values(act_level, 0);
+    last_level = act_level;
+  }
 }
 
 /*
@@ -117,24 +125,39 @@
 void
 examine_position(int how_much, int aftermath_play)
 {
+#ifndef GG_TURN_OFF_TRACES
   int save_verbose = verbose;
+#endif
 
   purge_persistent_caches();
   
+#ifndef GG_TURN_OFF_TRACES
   /* Don't print reading traces during make_worms and make_dragons unless 
    * the user really wants it (verbose == 3). 
    */
   if (verbose == 1 || verbose == 2)
     --verbose;
+#endif
 
   if (NEEDS_UPDATE(worms_examined)) {
+
+#ifndef GG_TURN_OFF_TRACES
     start_timer(0);
+#endif
+
     make_worms();
+
+#ifndef GG_TURN_OFF_TRACES
     time_report(0, "  make worms", NO_MOVE, 1.0);
+#endif
   }
 
   if (how_much == EXAMINE_WORMS) {
+
+#ifndef GG_TURN_OFF_TRACES
     verbose = save_verbose;
+#endif
+
     gg_assert(test_gray_border() < 0);
     return;
   }
@@ -142,8 +165,13 @@
   if (stones_on_board(BLACK | WHITE) != 0) {
     if (NEEDS_UPDATE(initial_influence_examined))
       compute_worm_influence();
+
     if (how_much == EXAMINE_INITIAL_INFLUENCE) {
+
+#ifndef GG_TURN_OFF_TRACES
       verbose = save_verbose;
+#endif
+
       gg_assert(test_gray_border() < 0);
       return;
     }
@@ -151,7 +179,11 @@
     if (how_much == EXAMINE_DRAGONS_WITHOUT_OWL) {
       if (NEEDS_UPDATE(dragons_examined_without_owl))
 	make_dragons(1);
+
+#ifndef GG_TURN_OFF_TRACES
       verbose = save_verbose;
+#endif
+
       gg_assert(test_gray_border() < 0);
       return;
     }
@@ -163,7 +195,11 @@
       dragons_examined_without_owl = position_number;
     }
     if (how_much == EXAMINE_DRAGONS) {
+
+#ifndef GG_TURN_OFF_TRACES
       verbose = save_verbose;
+#endif
+
       gg_assert(test_gray_border() < 0);
       return;
     }
@@ -173,12 +209,18 @@
 	   || how_much == EXAMINE_ALL) {
     initialize_dragon_data();
     compute_scores(chinese_rules || aftermath_play);
+
+#ifndef GG_TURN_OFF_TRACES
     verbose = save_verbose;
+#endif
+
     gg_assert(test_gray_border() < 0);
     return;
   }
   
+#ifndef GG_TURN_OFF_TRACES
   verbose = save_verbose;
+#endif
 
   if (NEEDS_UPDATE(initial_influence2_examined)) {
     compute_dragon_influence();
@@ -197,8 +239,10 @@
     return;
   }
 
+#ifndef GG_TURN_OFF_TRACES
   if (printworms)
     show_dragons();
+#endif
 }
 
 
@@ -306,17 +350,28 @@
 	   int allowed_moves[BOARDMAX], float *value, int *resign)
 {
   float average_score, pessimistic_score, optimistic_score;
-  int save_verbose;
-  int save_depth;
   int move;
   float dummy_value;
   int use_thrashing_dragon_heuristics = 0;
 
+#ifndef GG_TURN_OFF_TRACES
+  int save_verbose;
+#endif
+
+#ifndef GG_TURN_OFF_ASSERTS
+  int save_depth;
+#endif
+
   if (!value)
     value = &dummy_value;
 
+#ifndef GG_TURN_OFF_TRACES
   start_timer(0);
+#endif
+
+#ifndef GG_TURN_OFF_STATS
   clearstats();
+#endif
 
   /* Usually we would not recommend resignation. */
   if (resign)
@@ -332,10 +387,12 @@
   /* Prepare pattern matcher and reading code. */
   reset_engine();
 
+#ifndef GG_TURN_OFF_ASSERTS
   /* Store the depth value so we can check that it hasn't changed when
    * we leave this function.
    */
   save_depth = depth;
+#endif
 
   /* If in mirror mode, try to find a mirror move. */
   if (play_mirror_go
@@ -348,9 +405,15 @@
   }
 
   /* Find out information about the worms and dragons. */
+#ifndef GG_TURN_OFF_TRACES
   start_timer(1);
+#endif
+
   examine_position(EXAMINE_ALL, 0);
+
+#ifndef GG_TURN_OFF_TRACES
   time_report(1, "examine position", NO_MOVE, 1.0);
+#endif
 
 
   /* The score will be used to determine when we are safely
@@ -374,6 +437,7 @@
     average_score = -(white_score + black_score)/2.0;
   choose_strategy(color, average_score, game_status(color));
 
+#ifndef GG_TURN_OFF_TRACES
   if (printboard) {
     if (printboard == 1)
       fprintf(stderr, "\n          dragon_status display:\n\n");
@@ -387,6 +451,7 @@
       showboard(4);
     }
   }
+#endif
   
   gg_assert(stackp == 0);
   
@@ -396,12 +461,18 @@
 
   
   /* Pick up moves that we know of already. */
+#ifndef GG_TURN_OFF_TRACES
   save_verbose = verbose;
   if (verbose > 0)
     verbose--;
+#endif
+
   collect_move_reasons(color);
+
+#ifndef GG_TURN_OFF_TRACES
   verbose = save_verbose;
   time_report(1, "generate move reasons", NO_MOVE, 1.0);
+#endif
   
   /* Try to find empty corner moves. */
   fuseki(color);
@@ -420,12 +491,20 @@
   
   /* The general pattern database. */
   shapes(color);
+
+#ifndef GG_TURN_OFF_TRACES
   time_report(1, "shapes", NO_MOVE, 1.0);
+#endif
+
   gg_assert(stackp == 0);
 
   /* Look for combination attacks and defenses against them. */
   combinations(color);
+
+#ifndef GG_TURN_OFF_TRACES
   time_report(1, "combinations", NO_MOVE, 1.0);
+#endif
+
   gg_assert(stackp == 0);
 
   /* Review the move reasons and estimate move values. */
@@ -433,8 +512,12 @@
 			  pure_threat_value, pessimistic_score, allowed_moves,
 			  use_thrashing_dragon_heuristics))
     TRACE("Move generation likes %1m with value %f\n", move, *value);
+
   gg_assert(stackp == 0);
+
+#ifndef GG_TURN_OFF_TRACES
   time_report(1, "review move reasons", NO_MOVE, 1.0);
+#endif
 
 
   /* If the move value is 6 or lower, we look for endgame patterns too. */
@@ -447,7 +530,10 @@
 			    use_thrashing_dragon_heuristics))
       TRACE("Move generation likes %1m with value %f\n", move, *value);
     gg_assert(stackp == 0);
+
+#ifndef GG_TURN_OFF_TRACES
     time_report(1, "endgame", NO_MOVE, 1.0);
+#endif
   }
   
   /* If no move found yet, revisit any semeai and change the
@@ -465,8 +551,10 @@
 	      move, *value); 
       }
     }
-    time_report(1, "move reasons with revised semeai status",
-		NO_MOVE, 1.0);
+
+#ifndef GG_TURN_OFF_TRACES
+    time_report(1, "move reasons with revised semeai status", NO_MOVE, 1.0);
+#endif
   }
 
   /* If still no move, fill a remaining liberty. This should pick up
@@ -478,8 +566,11 @@
       *value = 1.0;
       TRACE("Filling a liberty at %1m\n", move);
       record_top_move(move, *value);
-      move_considered(move, *value);
+
+#ifndef GG_TURN_OFF_TRACES
+	  move_considered(move, *value);
       time_report(1, "fill liberty", NO_MOVE, 1.0);
+#endif
     }
     else
       move = PASS_MOVE;
@@ -492,7 +583,7 @@
   if (move == PASS_MOVE) {
     if (play_out_aftermath 
 	|| capture_all_dead 
-	|| (!doing_scoring && thrashing_dragon && pessimistic_score > 15.0))
+	|| (!doing_scoring && thrashing_dragon && pessimistic_score > 1.0))
       move = aftermath_genmove(color, 0, allowed_moves);
       
     /* If we're instructed to capture all dead opponent stones, generate
@@ -506,8 +597,11 @@
       *value = 1.0;
       TRACE("Aftermath move at %1m\n", move);
       record_top_move(move, *value);
+
+#ifndef GG_TURN_OFF_TRACES
       move_considered(move, *value);
       time_report(1, "aftermath_genmove", NO_MOVE, 1.0);
+#endif
     }
   }
 
@@ -534,10 +628,13 @@
     *resign = 1;
   }
   
+#ifndef GG_TURN_OFF_STATS
   /* If statistics is turned on, this is the place to show it. */
   if (showstatistics)
     showstats();
+#endif
 
+#ifndef GG_TURN_OFF_TRACES
   if (showtime) {
     double spent = time_report(0, "TIME to generate move at ", move, 1.0);
     total_time += spent;
@@ -547,13 +644,17 @@
       slowest_movenum = movenum + 1;
     }
   }
+#endif
 
   /* Some consistency checks to verify that things are properly
    * restored and/or have not been corrupted.
    */
   gg_assert(stackp == 0);
   gg_assert(test_gray_border() < 0);
+
+#ifndef GG_TURN_OFF_ASSERTS
   gg_assert(depth == save_depth);
+#endif
 
   return move;
 }
@@ -682,7 +783,7 @@
   return 0;
 }
 
-/* Computer two territory estimates: for *upper, the status of all
+/* Compute two territory estimates: for *upper, the status of all
  * cricital stones gets resolved in White's favor; vice verso for
  * black.
  */
@@ -701,6 +802,7 @@
       		    NO_MOVE, "White territory estimate");
   black_score = influence_score(&move_influence, use_chinese_rules);
 
+#ifndef GG_TURN_OFF_TRACES
   if (verbose || showscore) {
     if (white_score == black_score)
       gprintf("Score estimate: %s %f\n",
@@ -711,6 +813,7 @@
 	      white_score > 0 ? "W " : "B ", gg_abs(white_score));
     fflush(stderr);
   }
+#endif
 }
 
 
Index: gnugo/engine/globals.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/globals.c,v
retrieving revision 1.81
diff -u -r1.81 globals.c
--- gnugo/engine/globals.c	11 Feb 2006 13:46:20 -0000	1.81
+++ gnugo/engine/globals.c	30 Dec 2006 20:55:30 -0000
@@ -132,11 +132,12 @@
 float white_score;
 float black_score;
 
-int close_worms[BOARDMAX][4];
+/* Close worms data. See liberty.h */
+int close_worms[BOARDMAX][MAX_CLOSE_WORMS];
 int number_close_worms[BOARDMAX];
-int close_black_worms[BOARDMAX][4];
+int close_black_worms[BOARDMAX][MAX_CLOSE_WORMS];
 int number_close_black_worms[BOARDMAX];
-int close_white_worms[BOARDMAX][4];
+int close_white_worms[BOARDMAX][MAX_CLOSE_WORMS];
 int number_close_white_worms[BOARDMAX];
 
 int false_eye_territory[BOARDMAX];
Index: gnugo/engine/gnugo.h
===================================================================
RCS file: /sources/gnugo/gnugo/engine/gnugo.h,v
retrieving revision 1.133
diff -u -r1.133 gnugo.h
--- gnugo/engine/gnugo.h	11 Feb 2006 13:46:20 -0000	1.133
+++ gnugo/engine/gnugo.h	30 Dec 2006 20:55:30 -0000
@@ -114,6 +114,16 @@
 /*                           global variables                       */
 /* ================================================================ */
 
+// final release option
+
+#if FINAL_RELEASE == 1
+
+#define GG_TURN_OFF_ASSERTS
+#define GG_TURN_OFF_TRACES
+#define GG_TURN_OFF_STATS
+#define GG_TURN_OFF_DEBUGS
+
+#endif
 
 /* Miscellaneous debug options. */
 extern int quiet;		/* Minimal output. */
@@ -269,8 +279,16 @@
 /* influence.c */
 void debug_influence_move(int move);
 
-
+#ifdef GG_TURN_OFF_TRACES
+#define TRACE (1) ? (void)0 : (void)gprintf
+#else
 #define TRACE  (!(verbose)) ? (void)0 : (void)gprintf
+#endif
+
+#ifdef GG_TURN_OFF_DEBUGS
+#define DEBUG (1) ? (void)0 : (void)DEBUG_func
+int DEBUG_func(int level, const char *fmt, ...);
+#else
 
 #ifdef HAVE_VARIADIC_DEFINE
 
@@ -286,6 +304,8 @@
 
 #endif  /*HAVE_VARIADIC_DEFINE*/
 
+#endif /*GG_TURN_OFF_DEBUGS*/
+
 
 /* genmove.c */
 #define EXAMINE_WORMS               1
Index: gnugo/engine/hash.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/hash.c,v
retrieving revision 1.38
diff -u -r1.38 hash.c
--- gnugo/engine/hash.c	23 Jan 2006 18:15:50 -0000	1.38
+++ gnugo/engine/hash.c	30 Dec 2006 20:55:31 -0000
@@ -24,10 +24,12 @@
 #include "board.h"
 #include "hash.h"
 #include "random.h"
+#include "gnugo.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <string.h>
 
 
 
@@ -58,9 +60,10 @@
 {
   int i;
   Hashvalue h = 0;
+  const int limit = CHAR_BIT * sizeof(Hashvalue);
 
-  for (i = 0; 32*i < (int) (CHAR_BIT*sizeof(Hashvalue)); i++)
-    h |= (Hashvalue) gg_urand() << 32*i;
+  for (i = 0; i < limit; i += 32)
+    h |= ((Hashvalue) gg_urand()) << i;
 
   return h;
 }
@@ -118,7 +121,7 @@
       hashdata_xor(*target, black_hash[pos]);
   }
 
-  if (ko_pos != 0)
+  if (ko_pos != NO_MOVE)
     hashdata_xor(*target, ko_hash[ko_pos]);
 }
 
@@ -126,9 +129,7 @@
 void
 hashdata_clear(Hash_data *hd)
 {
-  int i;
-  for (i = 0; i < NUM_HASHVALUES; i++)
-    hd->hashval[i] = 0;
+  memset(hd->hashval, 0, NUM_HASHVALUES * sizeof(Hashvalue));
 }
 
 /* Set or remove ko in the hash value and hash position.  */
Index: gnugo/engine/hash.h
===================================================================
RCS file: /sources/gnugo/gnugo/engine/hash.h,v
retrieving revision 1.37
diff -u -r1.37 hash.h
--- gnugo/engine/hash.h	23 Jan 2006 18:15:50 -0000	1.37
+++ gnugo/engine/hash.h	30 Dec 2006 20:55:31 -0000
@@ -100,14 +100,13 @@
 
 /* ---------------------------------------------------------------- */
 
-/* There is no need to involve all bits in the remainder computation
- * as long as we only use it to compute a key into a hash table. 32
- * random bits are sufficient to get an even distribution within any
- * hashtable of reasonable size. By never using more than 32 bits we
- * also reduce the platform dependency of the GNU Go engine.
-*/
+/* Calculates a place in the transposition table where to look up for
+   a hash value. If sizeof(long) > sizeof(int) we truncate long to int
+   because size of the transposition table wouldn't be greater than
+   int. */
 #define hashdata_remainder(hd, num) \
-  (((hd).hashval[0] & 0xffffffffU) % (num))
+  (*((unsigned int*)((hd).hashval)) % (num))
+
 
 #if NUM_HASHVALUES == 1
 
Index: gnugo/engine/liberty.h
===================================================================
RCS file: /sources/gnugo/gnugo/engine/liberty.h,v
retrieving revision 1.258
diff -u -r1.258 liberty.h
--- gnugo/engine/liberty.h	19 Feb 2006 19:39:17 -0000	1.258
+++ gnugo/engine/liberty.h	30 Dec 2006 20:55:32 -0000
@@ -97,7 +97,8 @@
   "analyze_semeai"
 
 /* To prioritize between different types of reading, we give a cost
- * ranking to each of the routines above:
+ * ranking to each of the routines above (bigger index means bigger
+ * cost):
  *
  * 4 semeai
  * 3 owl
@@ -119,10 +120,10 @@
  * final status computed by the aftermath code.
  */
 enum dragon_status {
+  UNKNOWN,
   DEAD,
   ALIVE,
   CRITICAL,
-  UNKNOWN,
   UNCHECKED,
   CAN_THREATEN_ATTACK,
   CAN_THREATEN_DEFENSE, 
@@ -139,10 +140,10 @@
 };
 
 #define DRAGON_STATUS_NAMES \
+  "unknown", \
   "dead", \
   "alive", \
   "critical", \
-  "unknown", \
   "unchecked", \
   "can threaten attack", \
   "can threaten defense", \
Index: gnugo/engine/move_reasons.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/move_reasons.c,v
retrieving revision 1.135
diff -u -r1.135 move_reasons.c
--- gnugo/engine/move_reasons.c	11 Feb 2006 13:46:20 -0000	1.135
+++ gnugo/engine/move_reasons.c	30 Dec 2006 20:55:33 -0000
@@ -1553,8 +1553,9 @@
 {
   float new_strength;
   int ii;
+  int aff_stone = board[affected];
 
-  ASSERT1(IS_STONE(board[affected]), affected);
+  ASSERT1(IS_STONE(aff_stone), affected);
 
   if (new_status == 0)
     new_strength = 0.0;
@@ -1563,7 +1564,7 @@
     new_strength = DEFAULT_STRENGTH;
   }
   for (ii = BOARDMIN; ii < BOARDMAX; ii++)
-    if (board[ii] == board[affected]
+    if (board[ii] == aff_stone
 	&& same_string(ii, affected)) {
       strength[ii] = new_strength;
       safe_stones[ii] = new_status;
Index: gnugo/engine/optics.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/optics.c,v
retrieving revision 1.105
diff -u -r1.105 optics.c
--- gnugo/engine/optics.c	5 Feb 2006 11:29:45 -0000	1.105
+++ gnugo/engine/optics.c	30 Dec 2006 20:55:35 -0000
@@ -1748,6 +1748,7 @@
   int defense_point;
   int attack_value;
   int defense_value;
+  int other = OTHER_COLOR(color);
 
   memset(attack_values, 0, sizeof(attack_values));
   memset(defense_values, 0, sizeof(defense_values));
@@ -1846,7 +1847,7 @@
      *           string neighbors more than one empty vertex in the
      *           same eyespace.
      */
-    if (val < 2.0 && board[pos] == EMPTY && board[diag] == OTHER_COLOR(color)
+    if (val < 2.0 && board[pos] == EMPTY && board[diag] == other
 	&& !is_edge_vertex(pos) && neighbor_of_string(pos, diag)
 	&& countstones(diag) >= 3) {
       int strings[3];
@@ -1880,7 +1881,7 @@
 	    continue;
 
 	  for (r = 0; r < lib_count && adj_eye_count < 2; r++)
-	    if (my_eye[libs[r]].color == OTHER_COLOR(color)
+	    if (my_eye[libs[r]].color == other
 		&& !my_eye[libs[r]].marginal)
 	      adj_eye_count++;
 	  if (adj_eye_count < 2) {
@@ -2402,11 +2403,12 @@
    * liberties empty.
    */
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (mx[pos] == 1 || board[pos] != EMPTY || liberty_of_string(pos, str))
+    if (mx[pos] == 1 || board[pos] != EMPTY || liberty_of_string2(pos, str))
       continue;
     for (k = 0; k < 8; k++) {
-      if (ON_BOARD(pos + delta[k])
-	  && liberty_of_string(pos + delta[k], str)) {
+      int checked_pos = pos + delta[k];
+      if (ON_BOARD(checked_pos)
+	  && liberty_of_string(checked_pos, str)) {
 	play_move(pos, BLACK);
 	break;
       }
@@ -2695,9 +2697,10 @@
   int eyes;
   
   for (k = 0; k < 4; k++) {
-    if (board[vertex + delta[k]] == BLACK) {
+    int checked_pos = vertex + delta[k];
+    if (board[checked_pos] == BLACK) {
       eyes = 0;
-      num_libs = findlib(vertex + delta[k], MAXLIBS, libs);
+      num_libs = findlib(checked_pos, MAXLIBS, libs);
       
       for (r = 0; r < num_libs; r++)
 	if (is_suicide(libs[r], WHITE))
@@ -3646,14 +3649,17 @@
   /* If there are any isolated O stones, those should also be added to
    * the playable vertices.
    */
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
-    if (board[pos] == WHITE && !same_string(pos, POS(1, 0))) {
-      vertices[num_vertices] = vertices[num_vertices - 1];
-      vertices[num_vertices - 1] = vertices[num_vertices - 2];
-      vertices[num_vertices - 2] = vertices[num_vertices - 3];
-      vertices[num_vertices - 3] = pos;
-      num_vertices++;
-    }
+  {
+    int pos_1_0 = POS(1, 0);
+    for (pos = BOARDMIN; pos < BOARDMAX; pos++)
+      if (board[pos] == WHITE && !same_string(pos, pos_1_0)) {
+        vertices[num_vertices] = vertices[num_vertices - 1];
+        vertices[num_vertices - 1] = vertices[num_vertices - 2];
+        vertices[num_vertices - 2] = vertices[num_vertices - 3];
+        vertices[num_vertices - 3] = pos;
+        num_vertices++;
+      }
+  }
 
   if (verbose) {
     int k;
Index: gnugo/engine/owl.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.251
diff -u -r1.251 owl.c
--- gnugo/engine/owl.c	15 Sep 2006 01:05:48 -0000	1.251
+++ gnugo/engine/owl.c	30 Dec 2006 20:55:38 -0000
@@ -1576,10 +1576,16 @@
     for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
       if (IS_STONE(board[pos])
 	  && pos == find_origin(pos)) {
-	if (owla->goal[pos])
-	  net -= 75*countlib(pos);
-	if (owlb->goal[pos])
-	  net += 100*countlib(pos);	  
+	int count_lib = -1;
+	if (owla->goal[pos]) {
+	  count_lib = countlib(pos);
+	  net -= 75 * count_lib;
+	}
+	if (owlb->goal[pos]) {
+	  if (count_lib < 0)
+	    count_lib = countlib(pos);
+	  net += 100 * count_lib;
+	}
       }
     }
     if (!trymove(move, color, NULL, 0)) {
@@ -1589,11 +1595,17 @@
     for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
       if (IS_STONE(board[pos])
 	  && pos == find_origin(pos)) {
+	int count_lib = -1;
 	if (owla->goal[pos]
-	    || (pos == move && liberty_of_goal(move, owla)))
-	  net += 75*countlib(pos);
-	if (owlb->goal[pos])
-	  net -= 100*countlib(pos);
+	    || (pos == move && liberty_of_goal(move, owla))) {
+	  count_lib = countlib(pos);
+	  net += 75 * count_lib;
+	}
+	if (owlb->goal[pos]) {
+	  if (count_lib < 0)
+	    count_lib = countlib(pos);
+	  net -= 100 * count_lib;
+	}
       }
     }
 
@@ -1929,14 +1941,15 @@
       int size = 0;
       saveworm = MAX_GOAL_WORMS;
       for (k = 0; k < MAX_GOAL_WORMS; k++) {
-	if (owl_goal_worm[k] == NO_MOVE)
+	int worm_goal = owl_goal_worm[k];
+	if (worm_goal == NO_MOVE)
 	  break;
-	if (board[owl_goal_worm[k]] == EMPTY
-	    || countlib(owl_goal_worm[k]) > 1)
+	if (board[worm_goal] == EMPTY
+	    || countlib(worm_goal) > 1)
 	  continue;
-	if (worm[owl_goal_worm[k]].size > size) {
+	if (worm[worm_goal].size > size) {
 	  saveworm = k;
-	  size = worm[owl_goal_worm[k]].size;
+	  size = worm[worm_goal].size;
 	}
       }
       if (saveworm != MAX_GOAL_WORMS && size >= 3) {
@@ -3554,24 +3567,28 @@
     if (ON_BOARD(*move + delta[k]) && board[*move + delta[k]] != color)
       return 0;
 
-  for (r = 4; r < 8; r++)
-    if (board[*move + delta[r]] == other
-	&& countlib(*move + delta[r]) == 1) {
-      for (k = 0; k < 4; k++)
-	if (board[*move + delta[k]] == color
-	    && countlib(*move + delta[k]) == 1
-	    && !adjacent_strings(*move + delta[r], *move + delta[k]))
+  for (r = 4; r < 8; r++) {
+    int checked_pos_r = *move + delta[r];
+    if (board[checked_pos_r] == other
+	&& countlib(checked_pos_r) == 1) {
+      for (k = 0; k < 4; k++) {
+	int checked_pos_k = *move + delta[k];
+	if (board[checked_pos_k] == color
+	    && countlib(checked_pos_k) == 1
+	    && !adjacent_strings(checked_pos_r, checked_pos_k))
 	  break;
+      }
 
       if (k == 4) {
 	int new_move;
-	findlib(*move + delta[r], 1, &new_move);
+	findlib(checked_pos_r, 1, &new_move);
 	TRACE("Changing eyefilling move at %1m to capture at %1m.\n",
 	      *move, new_move);
 	*move = new_move;
 	return 1;
       }
     }
+  }
   
   return 0;    
 }
Index: gnugo/engine/persistent.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/persistent.c,v
retrieving revision 1.40
diff -u -r1.40 persistent.c
--- gnugo/engine/persistent.c	15 Sep 2006 00:55:14 -0000	1.40
+++ gnugo/engine/persistent.c	30 Dec 2006 20:55:39 -0000
@@ -233,9 +233,12 @@
       return 0;
     else if (!(p[pos] & (HIGH_LIBERTY_BIT | HIGH_LIBERTY_BIT2)))
       continue;
-    else if (((p[pos] & HIGH_LIBERTY_BIT) && countlib(pos) <= 4)
-             || (p[pos] & HIGH_LIBERTY_BIT2 && countlib(pos) <= 3))
-      return 0;
+    else {
+      int count_lib = countlib(pos);
+      if (((p[pos] & HIGH_LIBERTY_BIT) && count_lib <= 4)
+          || ((p[pos] & HIGH_LIBERTY_BIT2) && count_lib <= 3))
+        return 0;
+    }
   }
   
   return 1;
@@ -336,9 +339,10 @@
     else {
       for (r = 0; r < MAX_CACHE_DEPTH; r++) {
 	int apos = entry->stack[r];
-	int color = entry->move_color[r];
-	if (apos == 0)
+	int color;
+	if (apos == NO_MOVE)
 	  break;
+	color = entry->move_color[r];
 	if (board[apos] == EMPTY
 	    && trymove(apos, color, "purge_persistent_cache", 0))
 	  played_moves++;
@@ -354,8 +358,9 @@
       /* Move the last entry in the cache here and back up the loop
        * counter to redo the test at this position in the cache.
        */
-      if (0)
+#if 0
 	gprintf("Purging entry %d from cache.\n", k);
+#endif
       if (k < cache->current_size - 1)
 	*entry = cache->table[cache->current_size - 1];
       k--;
@@ -718,6 +723,7 @@
 			   int m, int n, float contribution)
 {
   int i, j, k;
+  int pos_mn;
   
   /* If p[m][n] is EMPTY, we just give the contribution to close empty
    * vertices. This is a rough simplification.
@@ -733,22 +739,23 @@
   /* Otherwise we give contribution to liberties and diagonal
    * neighbors of the string at (m, n).
    */
+  pos_mn = POS(m, n);
   for (i = 0; i < board_size; i++)
     for (j = 0; j < board_size; j++) {
       if (BOARD(i, j) != EMPTY)
 	continue;
       for (k = 0; k < 8; k++) {
-	int di = deltai[k];
-	int dj = deltaj[k];
-	if (IS_STONE(BOARD(i+di, j+dj))
-	    && same_string(POS(i+di, j+dj), POS(m, n))) {
+	int di = i + deltai[k];
+	int dj = j + deltaj[k];
+	if (IS_STONE(BOARD(di, dj))
+	    && same_string(POS(di, dj), pos_mn)) {
 	  if (k < 4) {
 	    values[POS(i, j)] += contribution;
 	    break;
 	  }
 	  else {
-	    if (BOARD(i+di, j) == EMPTY || countlib(POS(i+di, j)) <= 2
-		|| BOARD(i, j+dj) == EMPTY || countlib(POS(i, j+dj)) <= 2)
+	    if (BOARD(di, j) == EMPTY || countlib(POS(di, j)) <= 2
+	        || BOARD(i, dj) == EMPTY || countlib(POS(i, dj)) <= 2)
 	      values[POS(i, j)] += contribution;
 	    break;
 	  }
@@ -1345,15 +1352,16 @@
     if (board[pos] != EMPTY)
       continue;
     for (k = 0; k < 8; k++) {
+      int same_dragon;
       int pos2 = pos + delta[k];
       if (IS_STONE(board[pos2])
-	  && (is_same_dragon(pos2, dr)
+	  && ((same_dragon = is_same_dragon(pos2, dr))
 	      || (are_neighbor_dragons(pos2, dr)
 		  && board[pos2] == board[dr]))
 	  && (countlib(pos2) <= 4
 	      || is_edge_vertex(pos))) {
 	if (k < 4) {
-	  if (is_same_dragon(pos2, dr))
+	  if (same_dragon)
 	    values[pos] += contribution;
 	  else
 	    values[pos] += 0.5 * contribution;
Index: gnugo/engine/printutils.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/printutils.c,v
retrieving revision 1.56
diff -u -r1.56 printutils.c
--- gnugo/engine/printutils.c	29 Jan 2006 18:36:59 -0000	1.56
+++ gnugo/engine/printutils.c	30 Dec 2006 20:55:39 -0000
@@ -24,6 +24,7 @@
 #include "hash.h"
 #include "gg_utils.h"
 #include "sgftree.h"
+#include "gnugo.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -35,6 +36,8 @@
  * This function underpins all the TRACE and DEBUG stuff.
  * It accepts %c, %d, %f, %s, and %x as usual. But it
  * also accepts %m, which takes TWO integers and writes a move.
+ * It is possible to specify %1m, which takes one integer and
+ * prints a move (integer means the board array index).
  * Other accepted formats are
  * %H: Print a hashvalue.
  * %C: Print a color as a string.
Index: gnugo/engine/readconnect.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/readconnect.c,v
retrieving revision 1.99
diff -u -r1.99 readconnect.c
--- gnugo/engine/readconnect.c	23 Jan 2006 18:15:50 -0000	1.99
+++ gnugo/engine/readconnect.c	30 Dec 2006 20:55:41 -0000
@@ -246,9 +246,7 @@
   
   /* if only one liberty after capture */
   if (trymove(lib, OTHER_COLOR(board[str]), "snapback", str)) {
-    liberties = 0;
-    if (IS_STONE(board[lib]))
-      liberties = countlib(lib);
+    liberties = countlib(lib);
     popgo();
     sgf_dumptree = save_sgf_dumptree;
     if (liberties > 1)
@@ -271,6 +269,8 @@
   int liberties, libs[MAXLIBS];
   int adj, adjs[MAXCHAIN];
   int neighb, neighbs[MAXCHAIN];
+  int color = board[str1];
+  int other = OTHER_COLOR(color);
 
   /* finds connection through two forbidden liberties for
    * the opponent
@@ -288,17 +288,17 @@
    */
   liberties = findlib(str1, MAXLIBS, libs);
   for (r = 0; r < liberties; r++)
-    if (is_self_atari(libs[r], OTHER_COLOR(board[str1]))) 
+    if (is_self_atari(libs[r], other)) 
       for (k = 0; k < 4; k++) {
 	int pos = libs[r] + delta[k];
-	if (board[pos] == board[str1]
+	if (board[pos] == color
 	    && !same_string(pos, str1)
 	    && !same_string(pos, str2)) {
 	  /* try to connect pos to str2 in one move */
 	  /* play a common liberty */
 	  neighb = findlib(pos, MAXLIBS, neighbs);
 	  for (s = 0; s < neighb; s++)
-	    if (liberty_of_string(neighbs[s], str2)) {
+	    if (liberty_of_string2(neighbs[s], str2)) {
 	      res = 1;
 	      add_zone(zn, libs[r]);
 	      add_zone(zn, neighbs[s]);
@@ -492,7 +492,7 @@
     liberties = findlib(adjs[r], MAXLIBS, libs);
     common_adj_liberty = 0;
     for (s = 0; s < liberties; s++)
-      if (liberty_of_string(libs[s], str2))
+      if (liberty_of_string2(libs[s], str2))
 	common_adj_liberty = 1;
     if (common_adj_liberty || adjacent_strings(adjs[r], str2)) {
       for (s = 0; s < liberties; s++)
@@ -511,7 +511,7 @@
     liberties = findlib(adjs[r], MAXLIBS, libs);
     common_adj_liberty = 0;
     for (s = 0; s < liberties; s++)
-      if (liberty_of_string(libs[s], str1))
+      if (liberty_of_string2(libs[s], str1))
 	common_adj_liberty = 1;
     if (common_adj_liberty || adjacent_strings(adjs[r], str1)) {
       for (s = 0; s < liberties; s++)
@@ -530,28 +530,28 @@
   liberties = findlib(str1, MAXLIBS, libs);
   for (r = 0; r < liberties; r++) {
     if (board[SOUTH(libs[r])] == EMPTY) {
-      if (liberty_of_string(SOUTH(libs[r]), str2)) {
+      if (liberty_of_string2(SOUTH(libs[r]), str2)) {
 	add_array(moves, libs[r]);
 	add_array(moves, SOUTH(libs[r]));
       }
     }
     
     if (board[WEST(libs[r])] == EMPTY) {
-      if (liberty_of_string(WEST(libs[r]), str2)) {
+      if (liberty_of_string2(WEST(libs[r]), str2)) {
 	add_array(moves, libs[r]);
 	add_array(moves, WEST(libs[r]));
       }
     }
 
     if (board[NORTH(libs[r])] == EMPTY) {
-      if (liberty_of_string(NORTH(libs[r]), str2)) {
+      if (liberty_of_string2(NORTH(libs[r]), str2)) {
 	add_array(moves, libs[r]);
 	add_array(moves, NORTH(libs[r]));
       }
     }
 
     if (board[EAST(libs[r])] == EMPTY) {
-      if (liberty_of_string(EAST(libs[r]), str2)) {
+      if (liberty_of_string2(EAST(libs[r]), str2)) {
 	add_array(moves, libs[r]);
 	add_array(moves, EAST(libs[r]));
       }
@@ -561,7 +561,18 @@
   /* Liberties of str1 which are adjacent to a friendly string with
    * common liberty with str2.
    */
-  liberties = findlib(str1, MAXLIBS, libs);
+
+#ifndef GG_TURN_OFF_ASSERTS
+/* We got liberties from previous call to findlib. */
+  {
+    int test_libs[MAXLIBS];
+    int t;
+    gg_assert(liberties == findlib(str1, MAXLIBS, test_libs));
+    for (t = 0; t < liberties; ++t)
+      gg_assert(libs[t] == test_libs[t]);
+  }
+#endif
+
   for (r = 0; r < liberties; r++) {
     for (k = 0; k < 4; k++) {
       int pos = libs[r] + delta[k];
@@ -1495,6 +1506,7 @@
   SGFTree *save_sgf_dumptree = sgf_dumptree;
   int save_count_variations = count_variations;
   int result = 0;
+  int count_lib = countlib(str);
 
   /* We turn off the sgf traces here to avoid cluttering them up with
    * naive_ladder moves.
@@ -1502,11 +1514,11 @@
   sgf_dumptree = NULL;
   count_variations = 0;
 
-  if (countlib(str) == 1) {
+  if (count_lib == 1) {
     findlib(str, 1, move);
     result = WIN;
   }
-  else if (countlib(str) == 2)
+  else if (count_lib == 2)
     result = simple_ladder(str, move);
 
   /* Turn the sgf traces back on. */
@@ -2317,6 +2329,7 @@
   SGFTree *save_sgf_dumptree = sgf_dumptree;
   int save_count_variations = count_variations;
   int distance_limit;
+  int str2_onboard;
 
   /* We turn off the sgf traces here to avoid cluttering them up with
    * tactical reading moves.
@@ -2447,6 +2460,11 @@
   }
 
   /* Modify the distance values for the moves with various bonuses. */
+  if (ON_BOARD(str2))
+    str2_onboard = 1;
+  else
+    str2_onboard = 0;
+
   for (r = 0; r < num_moves; r++) {
     int move = moves[r];
     int adjacent_to_attacker = 0;
@@ -2478,7 +2496,8 @@
 	}
       }
       else if (board[pos] == color) {
-	if (countlib(pos) <= 2) {
+	int count_lib = countlib(pos);
+	if (count_lib <= 2) {
 	  distances[r] -= FP(0.2);
 	  if (verbose > 0)
 	    gprintf("%o%1M -0.2, adjacent to defender string with at most two liberties\n", move);
@@ -2491,7 +2510,7 @@
 	 * The following code compensates in such kind of situations.
 	 * See connection:111 and gunnar:53 for example.
 	 */
-	if (!connect_move && countlib(pos) == 1
+	if (!connect_move && count_lib == 1
 	    /* let's avoid ko and snapbacks */
 	    && accuratelib(move, other, 2, NULL) > 1) {
 	  int adjs[MAXCHAIN];
@@ -2523,9 +2542,9 @@
      * Neighbor strings with less than 3 liberties have already
      * generated a bonus above.
      */
-    if ((liberty_of_string(move, str1)
+    if ((liberty_of_string2(move, str1)
 	 && countlib(str1) == 3)
-	|| (ON_BOARD(str2) && liberty_of_string(move, str2)
+	|| (str2_onboard && liberty_of_string2(move, str2)
 	    && countlib(str2) == 3)) {
       distances[r] -= FP(0.1);
       if (verbose > 0)
@@ -4235,6 +4254,7 @@
   int save_count_variations = count_variations;
   int adj[MAXCHAIN];
   int libs[2];
+  int count_lib = countlib(str);
   
   /* We turn off the sgf traces here to avoid cluttering them up with
    * tactical reading moves.
@@ -4242,10 +4262,10 @@
   sgf_dumptree = NULL;
   count_variations = 0;
   
-  if (countlib(str) == 1 && find_defense(str, NULL) == 0)
+  if (count_lib == 1 && find_defense(str, NULL) == 0)
     result = 1;
 
-  if (countlib(str) == 2
+  if (count_lib == 2
       && chainlinks2(str, adj, 1) == 0
       && findlib(str, 2, libs) == 2
       && approxlib(libs[0], board[str], 2, NULL) == 1
@@ -4332,11 +4352,13 @@
   if (apos == bpos)
     return 1;
 
-  for (k = 0; k < 4; k++)
-    if (board[apos + delta[k]] == color
-	&& countlib(apos + delta[k]) <= 3
-	&& liberty_of_string(bpos, apos + delta[k]))
+  for (k = 0; k < 4; k++) {
+    int checked_pos = apos + delta[k];
+    if (board[checked_pos] == color
+	&& countlib(checked_pos) <= 3
+	&& liberty_of_string(bpos, checked_pos))
       return 1;
+  }
 
   return 0;
 }
Index: gnugo/engine/reading.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/reading.c,v
retrieving revision 1.168
diff -u -r1.168 reading.c
--- gnugo/engine/reading.c	4 Feb 2006 18:46:04 -0000	1.168
+++ gnugo/engine/reading.c	30 Dec 2006 20:55:44 -0000
@@ -1032,7 +1032,6 @@
   int r;
 
   ASSERT1(IS_STONE(board[str]), str);
-  other = OTHER_COLOR(board[str]);
 
   /* Only handle strings with no way to capture immediately.
    * For now, we treat ko the same as unconditionally. */
@@ -1046,6 +1045,7 @@
    *
    * The test against 6 liberties is just an optimization.
    */
+  other = OTHER_COLOR(board[str]);
   liberties = findlib(str, MAXLIBS, libs);
   if (liberties > 1 && liberties < 6) {
     for (k = 0; k < liberties; k++) {
@@ -1065,7 +1065,7 @@
 
        if (!ON_BOARD(bb)
            || IS_STONE(board[bb])
-           || liberty_of_string(bb, str))
+           || liberty_of_string2(bb, str))
          continue;
 
        if (trymove(bb, other, "attack_threats-B", str)) {
@@ -1322,7 +1322,7 @@
      * it has already been done in the first loop of this function.
      */
     num_adjacent_stones = count_adjacent_stones(adjs[j], str, missing);
-    if (!liberty_of_string(lib, str)
+    if (!liberty_of_string2(lib, str)
 	&& num_adjacent_stones >= missing) {
       *move = lib;
       return 1;
@@ -1444,7 +1444,7 @@
   break_chain_moves(str, &moves);
   set_up_snapback_moves(str, lib, &moves);
 
-  order_moves(str, &moves, color, read_function_name, *move);
+  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,
@@ -1552,7 +1552,7 @@
   if (stackp <= backfill_depth)
     special_rescue2_moves(str, libs, &moves);
 
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(0, &suggest_move);
 
   /* Look for backfilling moves. */
@@ -1586,7 +1586,7 @@
   special_rescue4_moves(str, libs, &moves);
   
   /* Only order and test the new set of moves. */
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(0, &suggest_move);
 
   /* If we haven't found any useful moves in first batches, be more
@@ -1618,7 +1618,7 @@
     break_chain4_moves(str, &moves, be_aggressive);
 
   /* Only order and test the new set of moves. */
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(0, &suggest_move);
 
   RETURN_RESULT(savecode, savemove, move, "saved move");
@@ -1680,7 +1680,7 @@
   if (stackp <= backfill2_depth)
     hane_rescue_moves(str, libs, &moves);
 
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(1, &suggest_move);
 
   /* This looks a little too expensive. */
@@ -1768,7 +1768,7 @@
   }
 
   /* Only order and test the new set of moves. */
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(1, &suggest_move);
 
   /* If nothing else works, we try playing a liberty of the
@@ -1783,7 +1783,7 @@
     break_chain3_moves(str, &moves, 0);
 
   /* Only order and test the new set of moves. */
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(1, &suggest_move);
 
   RETURN_RESULT(savecode, savemove, move, "saved move");
@@ -1850,7 +1850,7 @@
     squeeze_moves(str, &moves);
   }
 
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(1, &suggest_move);
 
   if (stackp <= depth) {
@@ -1859,7 +1859,7 @@
     bamboo_rescue_moves(str, liberties, libs, &moves);
   }
 
-  order_moves(str, &moves, color, read_function_name, *move);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, *move);
   DEFEND_TRY_MOVES(1, &suggest_move);
 
   RETURN_RESULT(savecode, savemove, move, "saved move");
@@ -2005,7 +2005,7 @@
   int other = OTHER_COLOR(color);
   int newlibs[4];
   int liberties;
-  int newstr;
+  int astr_pos;
   int k, r, s;
   
   for (r = 0; r < 2; r++) {
@@ -2017,18 +2017,18 @@
       continue;
 
     for (k = 0; k < 4; k++) {
-      if (board[alib + delta[k]] == color
-	  && !same_string(alib + delta[k], str)) {
-	newstr = alib + delta[k];
-	liberties = findlib(newstr, 4, newlibs);
+      astr_pos = alib + delta[k];
+      if (board[astr_pos] == color
+	  && !same_string(astr_pos, str)) {
+	liberties = findlib(astr_pos, 4, newlibs);
 	
 	for (s = 0; s < liberties && s < 4; s++) {
 	  if (!is_self_atari(newlibs[s], color))
 	    ADD_CANDIDATE_MOVE(newlibs[s], 0, *moves, "special_rescue2");
 	}
-	break_chain_moves(newstr, moves);
-	break_chain2_efficient_moves(newstr, moves);
-	edge_clamp_moves(newstr, moves);
+	break_chain_moves(astr_pos, moves);
+	break_chain2_efficient_moves(astr_pos, moves);
+	edge_clamp_moves(astr_pos, moves);
       }
     }
   }
@@ -2284,7 +2284,7 @@
 
       liberties2 = findlib(bpos, 4, libs2);
       for (s = 0; s < liberties2; s++)
-	if (!liberty_of_string(libs2[s], str)
+	if (!liberty_of_string2(libs2[s], str)
 	    && !is_self_atari(libs2[s], color))
 	  ADD_CANDIDATE_MOVE(libs2[s], 0, *moves, "special_rescue5-A");
 
@@ -2469,7 +2469,7 @@
       int alibs[2];
       int alib = accuratelib(apos, other, 2, alibs);
 
-      if (liberty_of_string(apos, str))
+      if (liberty_of_string2(apos, str))
 	continue;
 
       if (alib >= 2)
@@ -2521,7 +2521,7 @@
       continue;
 
     for (r = 0; r < num_libs2; r++)
-      if (!liberty_of_string(libs2[r], str)) {
+      if (!liberty_of_string2(libs2[r], str)) {
 	potential_move = libs2[r];
 	break;
       }
@@ -2542,7 +2542,7 @@
 	previous_liberty = potential_move;
 	potential_move = libs2[0];
       }
-      if (liberty_of_string(potential_move, str)) {
+      if (liberty_of_string2(potential_move, str)) {
 	potential_move = NO_MOVE;
 	break;
       }
@@ -2642,12 +2642,12 @@
 	if (board[cpos] != color || !same_string(cpos, str))
 	  continue;
 
-	if (board[dpos] != EMPTY || !liberty_of_string(dpos, apos))
+	if (board[dpos] != EMPTY || !liberty_of_string2(dpos, apos))
 	  continue;
 
 	epos = dpos + up;
 
-	if (board[epos] != EMPTY || !liberty_of_string(epos, apos))
+	if (board[epos] != EMPTY || !liberty_of_string2(epos, apos))
 	  continue;
 
 	if (approxlib(dpos, color, 3, NULL) < 3)
@@ -3112,9 +3112,9 @@
         /* If stackp > depth and any boundary chain is in atari, assume safe.
          * However, if the captured chain is only of size 1, there can still
          * be a working ladder, so continue if that is the case.
-	 * Also if the string in atari shares its liberty with the
-	 * attacked string, drawing it out may enable the ladder to
-	 * continue.
+         * Also if the string in atari shares its liberty with the
+         * attacked string, drawing it out may enable the ladder to
+         * continue.
          */
         if (stackp > depth
 	    && countstones(adjs[r]) > 1
@@ -3190,8 +3190,8 @@
       adj = chainlinks2(str, adjs, 2);
       for (r = 0; r < adj; r++) {
         int apos = adjs[r];
-        if (liberty_of_string(libs[0], apos)
-	    && liberty_of_string(libs[1], apos))
+        if (liberty_of_string2(libs[0], apos)
+	    && liberty_of_string2(libs[1], apos))
           break_chain_moves(apos, &moves);
       }
 
@@ -3230,7 +3230,7 @@
       abort();
     } /* switch (pass) */
 
-    order_moves(str, &moves, other, read_function_name, *move);
+    order_moves(str, &moves, other, READ_FUNCTION_NAME, *move);
     ATTACK_TRY_MOVES(0, &suggest_move);
   }
 
@@ -3373,7 +3373,7 @@
       abort();
     }
 
-    order_moves(str, &moves, other, read_function_name, *move);
+    order_moves(str, &moves, other, READ_FUNCTION_NAME, *move);
     ATTACK_TRY_MOVES(1, &suggest_move);
   } /* for (pass... */
 
@@ -3467,7 +3467,7 @@
       abort();
     }
 
-    order_moves(str, &moves, other, read_function_name, *move);
+    order_moves(str, &moves, other, READ_FUNCTION_NAME, *move);
     ATTACK_TRY_MOVES(1, &suggest_move);
   } /* for (pass = ... */
 
@@ -3681,7 +3681,7 @@
      * chain links.
      */
     for (s = 0; s < adj; s++)
-      if (liberty_of_string(apos, adjs[s])) {
+      if (liberty_of_string2(apos, adjs[s])) {
 	bpos = adjs[s];
 	break;
       }
@@ -3773,7 +3773,7 @@
   for (r = 0; r < adj; r++) {
     findlib(adjs[r], 2, libs);
     for (k = 0; k < 2; k++) {
-      if (!liberty_of_string(libs[k], str)
+      if (!liberty_of_string2(libs[k], str)
 	     && ((ON_BOARD1(SOUTH(libs[k]))
 		     && liberty_of_string(SOUTH(libs[k]), str))
 	      || (ON_BOARD1(WEST(libs[k]))
@@ -4019,10 +4019,12 @@
   for (k = 0; k < 4; k++) {
     int l;
     int up = delta[k];
+    int up_apos;
 
     if (ON_BOARD(apos - up))
       continue;
-    if (board[apos + up] != color || !same_string(apos + up, str))
+    up_apos = apos + up;
+    if (board[up_apos] != color || !same_string(up_apos, str))
       return;
     
     for (l = 0; l < 2; l++) {
@@ -4036,7 +4038,7 @@
 	right = -right;
 
       cpos = apos + right;
-      dpos = apos + right + up;
+      dpos = up_apos + right;
       epos = cpos + right;
       fpos = dpos + right;
 
@@ -4159,7 +4161,8 @@
     int min_liberties)
 {
   int r, s, t;
-  int color = OTHER_COLOR(board[str]);
+  int color = board[str];
+  int other = OTHER_COLOR(color);
   int xpos;
   int adj;
   int adj2;
@@ -4178,7 +4181,7 @@
     findlib(adjs[r], 2, libs);
     for (t = 0; t < 2; t++) {
       xpos = libs[t];
-      if (approxlib(xpos, color, min_liberties, NULL)
+      if (approxlib(xpos, other, min_liberties, NULL)
 	  + neighbor_of_string(xpos, str) >= min_liberties)
 	ADD_CANDIDATE_MOVE(xpos, 0, *moves, "defend_secondary_chain2-A");
     }
@@ -4187,7 +4190,7 @@
     adj2 = chainlinks2(adjs[r], adjs2, 1);
     for (s = 0; s < adj2; s++) {
       findlib(adjs2[s], 1, &xpos);
-      if (!is_self_atari(xpos, color))
+      if (!is_self_atari(xpos, other))
 	ADD_CANDIDATE_MOVE(xpos, 0, *moves, "defend_secondary_chain2-B");
     }
 
@@ -4197,8 +4200,8 @@
       findlib(adjs2[s], 2, libs);
       for (t = 0; t < 2; t++) {
 	/* Only atari if target has no easy escape with his other liberty. */
-	if (approxlib(libs[1-t], OTHER_COLOR(color), 3, NULL) < 3 
-	    &&  !is_self_atari(libs[t], color)) {
+	if (approxlib(libs[1-t], color, 3, NULL) < 3 
+	    &&  !is_self_atari(libs[t], other)) {
 	  ADD_CANDIDATE_MOVE(libs[t], 0, *moves, "defend_secondary_chain2-C");
 	}
       }
@@ -4823,7 +4826,7 @@
 
   break_chain_moves(str, &moves);
   set_up_snapback_moves(str, lib, &moves);
-  order_moves(str, &moves, color, read_function_name, NO_MOVE);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, NO_MOVE);
 
   for (k = 0; k < moves.num; k++) {
     int ko_capture;
@@ -5626,7 +5629,7 @@
   if (approxlib(libs[1], color, 4, NULL) <= 3)
     ADD_CANDIDATE_MOVE(libs[0], 0, moves, "simple_ladder");
 
-  order_moves(str, &moves, other, read_function_name, NO_MOVE);
+  order_moves(str, &moves, other, READ_FUNCTION_NAME, NO_MOVE);
 
   for (k = 0; k < moves.num; k++) {
     int ko_move;
@@ -5688,7 +5691,7 @@
   moves.num_tried = 0;
 
   break_chain_moves(str, &moves);
-  order_moves(str, &moves, color, read_function_name, NO_MOVE);
+  order_moves(str, &moves, color, READ_FUNCTION_NAME, NO_MOVE);
 
   for (k = 0; k < moves.num; k++) {
     int ko_move;
Index: gnugo/engine/showbord.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/showbord.c,v
retrieving revision 1.29
diff -u -r1.29 showbord.c
--- gnugo/engine/showbord.c	23 Jan 2006 18:15:50 -0000	1.29
+++ gnugo/engine/showbord.c	30 Dec 2006 20:55:45 -0000
@@ -343,7 +343,7 @@
 }
 
 
-#ifndef HAVE_VARIADIC_DEFINE
+#if !defined(HAVE_VARIADIC_DEFINE) || defined(GG_TURN_OFF_DEBUGS)
 
 /* See gnugo.h for related TRACE family macro definitions */
 
Index: gnugo/engine/unconditional.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/unconditional.c,v
retrieving revision 1.5
diff -u -r1.5 unconditional.c
--- gnugo/engine/unconditional.c	23 Jan 2006 18:15:50 -0000	1.5
+++ gnugo/engine/unconditional.c	30 Dec 2006 20:55:45 -0000
@@ -343,12 +343,15 @@
     
     findstones(pos, 2, stones);
     for (k = 0; k < 2 && isolated; k++) {
-      for (r = 0; r < 8 && isolated; r++) {
+      for (r = 0; r < 8; r++) {
 	pos2 = stones[k] + delta[r];
 	if (!ON_BOARD(pos2)
 	    || (board[pos2] == color
 		&& !same_string(pos, pos2)))
+	{
 	  isolated = 0;
+	  break;
+	}
       }
     }
 
Index: gnugo/engine/utils.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/utils.c,v
retrieving revision 1.115
diff -u -r1.115 utils.c
--- gnugo/engine/utils.c	17 Apr 2006 07:42:58 -0000	1.115
+++ gnugo/engine/utils.c	30 Dec 2006 20:55:46 -0000
@@ -731,8 +731,8 @@
 void
 set_depth_values(int level, int report_levels)
 {
-  static int node_limits[] = {500, 500, 450, 400, 400, 325, 275,
-			      200, 150, 100, 75, 50};
+  const int node_limits[] = {500, 500, 450, 400, 400, 325, 275,
+                             200, 150, 100, 75, 50};
   int depth_level;
 
   /*
@@ -858,6 +858,7 @@
 
   depth_offset = 0;
   
+#ifndef GG_TURN_OFF_TRACES
   if (report_levels) {
     fprintf(stderr, "at level %d:\n\n\
 depth: %d\n\
@@ -889,6 +890,9 @@
             connect_depth2, connection_node_limit, breakin_depth, 
 	    breakin_node_limit);
   }
+#else
+  UNUSED(report_levels);
+#endif
 }
 
 
Index: gnugo/engine/value_moves.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/value_moves.c,v
retrieving revision 1.170
diff -u -r1.170 value_moves.c
--- gnugo/engine/value_moves.c	18 May 2006 04:09:28 -0000	1.170
+++ gnugo/engine/value_moves.c	30 Dec 2006 20:55:48 -0000
@@ -69,22 +69,24 @@
   }
 
   for (k = 0; k < strings; k++) {
+    int count_lib;
     if (worm[ss[k]].invincible)
       continue;
+    count_lib = countlib(ss[k]);
     if (board[ss[k]] == color) {
       int newlibs = approxlib(pos, color, MAXLIBS, NULL);
       own_strings++;
-      if (newlibs >= countlib(ss[k])) {
-	if (countlib(ss[k]) <= 4)
+      if (newlibs >= count_lib) {
+	if (count_lib <= 4)
 	  fewlibs++;
-	if (countlib(ss[k]) <= 2)
+	if (count_lib <= 2)
 	  fewlibs++;
       }
     }
     else {
-      if (countlib(ss[k]) <= 2)
+      if (count_lib <= 2)
 	fewlibs++;
-      if (countlib(ss[k]) <= 1 && to_move) {
+      if (count_lib <= 1 && to_move) {
 	int dummy[MAXCHAIN];
 	fewlibs++;
 	fewlibs += chainlinks2(ss[k], dummy, 1);
@@ -765,7 +767,7 @@
     int potential_semeai_move_found = 0;
     int other_move_reason_found = 0;
 
-    if (!ON_BOARD1(pos))
+    if (!ON_BOARD(pos))
       continue;
     for (k = 0; k < MAX_REASONS; k++) {
       r = move[pos].reason[k];
@@ -2267,7 +2269,7 @@
        */
       if (dragon[aa].size == 1
 	  && is_ko_point(aa)
-	  && liberty_of_string(pos, aa)) {
+	  && liberty_of_string2(pos, aa)) {
 	TRACE("  %1m: -0.5 - penalty for ko stone %1m (workaround)\n",
 	      pos, aa);
 	tot_value -= 0.5;
Index: gnugo/engine/worm.c
===================================================================
RCS file: /sources/gnugo/gnugo/engine/worm.c,v
retrieving revision 1.72
diff -u -r1.72 worm.c
--- gnugo/engine/worm.c	18 May 2006 03:54:42 -0000	1.72
+++ gnugo/engine/worm.c	30 Dec 2006 20:55:49 -0000
@@ -76,7 +76,7 @@
  * though its location is irrelevant for applications. To see if two
  * stones lie in the same worm, compare their origins.
  *
- * We will use the field dragon[ii].genus to keep track of
+ * We will use the field dragon[pos].genus to keep track of
  * black- or white-bordered cavities (essentially eyes) which are found.  
  * so this field must be zero'd now.
  */
@@ -521,27 +521,24 @@
 build_worms()
 {
   int pos;
+  int stone;
 
   /* Set all worm data fields to 0. */
   memset(worm, 0 , sizeof(worm));
 
-  /* Initialize the worm data for each worm. */
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
-    if (ON_BOARD(pos))
-      worm[pos].origin = NO_MOVE;
+  /* Worm statuses must be set to UNKNOWN. Now memset does it. */
+  gg_assert(UNKNOWN == 0);
   
+  /* Initialize the worm data for each worm. */
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
     if (!ON_BOARD(pos) || worm[pos].origin != NO_MOVE)
       continue;
-    worm[pos].color = board[pos];
-    worm[pos].origin = pos;
-    worm[pos].inessential = 0;
-    worm[pos].invincible = 0;
-    worm[pos].unconditional_status = UNKNOWN;
-    worm[pos].effective_size = 0.0;
-    if (IS_STONE(board[pos])) {
-      worm[pos].liberties = countlib(pos);
+    stone = board[pos];
+    worm[pos].color = stone;
+    if (IS_STONE(stone)) {
+      worm[pos].origin = pos;
       worm[pos].size = countstones(pos);
+      worm[pos].liberties = countlib(pos);
       propagate_worm(pos);
     }
   }
@@ -584,6 +581,7 @@
    * a stone at the location, 1 a liberty of a stone, and so on.
    */
   int distance[BOARDMAX];
+
   /* Pointer to the origin of the closest worms. A very large number of
    * worms may potentially be equally close, but no more than
    * 2*(board_size-1).
@@ -596,22 +594,19 @@
   int r;
     
   /* Initialize arrays. */
+  memset(worms, NO_MOVE, sizeof(worms));
+  memset(nworms, 0, sizeof(nworms));
+  memset(distance, -1, sizeof(distance));
+
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
     if (!ON_BOARD(pos))
       continue;
 
-    for (k = 0; k < 2*(board_size-1); k++)
-      worms[pos][k] = NO_MOVE;
-    
-    nworms[pos] = 0;
-    
     if (board[pos] & color) {
       distance[pos] = 0;
       worms[pos][0] = worm[pos].origin;
-      nworms[pos]++;
+      nworms[pos] = 1;
     }
-    else
-      distance[pos] = -1;
   }
   
   dist = 0;
@@ -620,7 +615,7 @@
     found_one = 0;
     dist++;
     for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-      if (!ON_BOARD(pos) || distance[pos] != -1)
+      if (distance[pos] != -1 || !ON_BOARD(pos))
 	continue; /* already claimed */
 
       for (r = 0; r < 4; r++) {
@@ -638,8 +633,7 @@
 	      }
 	    if (!already_counted) {
 	      ASSERT1(nworms[pos] < 2*(board_size-1), pos);
-	      worms[pos][nworms[pos]] = worms[pos2][k];
-	      nworms[pos]++;
+	      worms[pos][nworms[pos]++] = worms[pos2][k];
 	    }
 	  }
 	}
@@ -789,7 +783,7 @@
 	 * defense, so we try and see if it defends.
 	 */
 	attack_point = worm[str].attack_points[0];
-	if (!liberty_of_string(attack_point, str))
+	if (!liberty_of_string2(attack_point, str))
 	  if (trymove(attack_point, worm[str].color, "make_worms", NO_MOVE)) {
 	    int acode = attack(str, NULL);
 	    if (acode != WIN) {
@@ -924,7 +918,7 @@
     /* Only try those worms that have an attack. */
     if (worm[str].attack_codes[0] != 0
 	&& worm[str].defense_codes[0] == 0) {
-      
+
       liberties = findlib(str, MAXLIBS, libs);
       
       for (k = 0; k < liberties; k++) {
@@ -946,7 +940,7 @@
 	  
 	  if (!ON_BOARD(bb)
 	      || IS_STONE(board[bb])
-	      || liberty_of_string(bb, str))
+	      || liberty_of_string2(bb, str))
 	    continue;
 	  
 	  if (trymove(bb, color, "threaten defense", str)) {
@@ -1204,7 +1198,7 @@
   num_stones = findstones(pos, MAX_BOARD * MAX_BOARD, stones);
   for (k = 0; k < num_stones; k++)
     if (stones[k] != pos)
-      worm[stones[k]] = worm[pos];
+      memcpy(worm + stones[k], worm + pos, sizeof(struct worm_data));
 }
 
 
@@ -1707,9 +1701,8 @@
 get_lively_stones(int color, signed char safe_stones[BOARDMAX])
 {
   int ii;
-  memset(safe_stones, 0, BOARDMAX * sizeof(*safe_stones));
-  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
-    ASSERT1(safe_stones[ii] == 0, ii);
+  gg_assert(sizeof(*safe_stones) == sizeof(signed char));
+  memset(safe_stones, 0, BOARDMAX * sizeof(signed char));
   for (ii = BOARDMIN; ii < BOARDMAX; ii++)
     if (IS_STONE(board[ii])
 	&& worm[ii].origin == ii) {
Index: gnugo/interface/main.c
===================================================================
RCS file: /sources/gnugo/gnugo/interface/main.c,v
retrieving revision 1.136
diff -u -r1.136 main.c
--- gnugo/interface/main.c	18 May 2006 21:29:45 -0000	1.136
+++ gnugo/interface/main.c	30 Dec 2006 20:55:50 -0000
@@ -97,7 +97,6 @@
       OPT_DECIDE_SEMEAI,
       OPT_DECIDE_SURROUNDED,
       OPT_DECIDE_TACTICAL_SEMEAI,
-      OPT_DECIDE_ORACLE,
       OPT_EXPERIMENTAL_SEMEAI,
       OPT_EXPERIMENTAL_OWL_EXT,
       OPT_SEMEAI_NODE_LIMIT,
@@ -140,8 +139,6 @@
       OPT_PRINTSGF,
       OPT_PROFILE_PATTERNS,
       OPT_CHINESE_RULES,
-      OPT_OWL_THREATS,
-      OPT_NO_OWL_THREATS,
       OPT_JAPANESE_RULES,
       OPT_FORBID_SUICIDE,
       OPT_ALLOW_SUICIDE,
@@ -289,7 +286,6 @@
   {"decide-surrounded",  required_argument, 0, OPT_DECIDE_SURROUNDED},
   {"decide-eye",     required_argument, 0, OPT_DECIDE_EYE},
   {"decide-combination", no_argument,   0, OPT_DECIDE_COMBINATION},
-  {"decide-oracle",  no_argument,       0, OPT_DECIDE_ORACLE},
   {"nofusekidb",     no_argument,       0, OPT_NOFUSEKIDB},
   {"nofuseki",       no_argument,       0, OPT_NOFUSEKI},
   {"nojosekidb",     no_argument,       0, OPT_NOJOSEKIDB},
@@ -353,12 +349,28 @@
   
   /* Weed through all of the command line options. */
   while ((i = gg_getopt_long(argc, argv, 
-                            "-ab:B:d:D:EF:gh::K:l:L:M:m:o:O:p:r:fsStTvw",
+                            "-ab:B:d:D:EF:h::K:l:L:M:m:o:O:r:StTvw",
 			     long_options, NULL)) != EOF)
     {
       switch (i) {
-      case 'T': printboard++; break;
-      case 't': ++verbose; break;
+
+      case 'T':
+#ifdef GG_TURN_OFF_TRACES
+        fprintf(stdout, "board printing not supported in final release\n");
+#else
+        printboard++;
+#endif
+        break;
+
+      case 't':
+#ifdef GG_TURN_OFF_TRACES
+        fprintf(stdout, "tracing not supported in final release\n");
+#else
+        ++verbose;
+#endif
+        break;
+
+
       case 'a': allpats = 1; break;
 
       case  1 :
@@ -367,11 +379,35 @@
 	
       case 'b': benchmark = atoi(gg_optarg); playmode = MODE_SOLO; break;
       case 'r': seed = atoi(gg_optarg); seed_specified = 1; break;
-      case 'S': showstatistics = 1; break;
-      case 'w': printworms = 1; break;
+
+      case 'S':
+#ifdef GG_TURN_OFF_STATS
+        fprintf(stdout, "statistics not supported in final release\n");
+#else
+        showstatistics = 1;
+#endif
+        break;
+
+      case 'w':
+#ifdef GG_TURN_OFF_TRACES
+        fprintf(stdout, "worm printing not supported in final release\n");
+#else
+        printworms = 1;
+#endif
+        break;
+
       case 'm': printmoyo = strtol(gg_optarg, NULL, 0);  /* allows 0x... */ 
 	break;
-      case 'd': debug ^= strtol(gg_optarg, NULL, 0);  /* allows 0x... */ break;
+
+      case 'd':
+#ifdef GG_TURN_OFF_DEBUGS
+        fprintf(stdout, "debugging not supported in final release\n");
+        debug = 0;
+#else
+        debug ^= strtol(gg_optarg, NULL, 0);  /* allows 0x... */
+#endif
+        break;
+
       case 'D': mandated_depth = atoi(gg_optarg); break;
       case 'M': memory = atof(gg_optarg); break; /* floating point number */
       case 'E': printboard = 2; break;
@@ -445,6 +481,7 @@
 	break;
 	
       case OPT_OPTIONS:
+	fprintf(stdout, "Default level: %d\n", DEFAULT_LEVEL);
 	if (USE_BREAK_IN)
 	  fprintf(stdout,
 		  "configure option enabled: experimental break-ins\n");
@@ -468,7 +505,7 @@
 		  "configure option enabled: owl threats\n");
 	if (RESIGNATION_ALLOWED)
 	  fprintf(stdout,
-		  "configure option enabled: resination allowed\n");
+		  "configure option enabled: resignation allowed\n");
 	if (ORACLE)
 	  fprintf(stdout,
 		  "configure option enabled: oracle\n");
@@ -486,12 +523,20 @@
 	break;
 
       case OPT_SHOWTIME:
-	showtime = 1;
-	break;
+#ifdef GG_TURN_OFF_TRACES
+        fprintf(stdout, "time showing not supported in final release\n");
+#else
+        showtime = 1;
+#endif
+        break;
 	
       case OPT_SHOWSCORE:
-	showscore = 1;
-	break;
+#ifdef GG_TURN_OFF_TRACES
+        fprintf(stdout, "score showing not supported in final release\n");
+#else
+        showscore = 1;
+#endif
+        break;
 	
       case OPT_HANDICAPSTONES:
 	{
@@ -535,14 +580,6 @@
 	chinese_rules = 1;
 	break;
 
-      case OPT_OWL_THREATS: 
-	owl_threats = 1;
-	break;
-
-      case OPT_NO_OWL_THREATS: 
-	owl_threats = 0;
-	break;
-
       case OPT_METAMACHINE:
         metamachine = 1;
 	break;
@@ -762,10 +799,6 @@
 	playmode = MODE_DECIDE_SURROUNDED;
 	break;
 	
-      case OPT_DECIDE_ORACLE:
-	playmode = MODE_DECIDE_ORACLE;
-	break;
-	
       case OPT_BRANCH_DEPTH:
 	mandated_branch_depth = atoi(gg_optarg);
 	break;
@@ -951,11 +984,15 @@
 	break;
 
       case OPT_PRINT_LEVELS:
+#ifdef GG_TURN_OFF_TRACES
+	fprintf(stdout, "levels printing not supported in final release\n");
+#else
 	{
 	  int lev;
 	  for (lev = 12; lev >= 0; lev--)
 	    set_depth_values(lev, 1);
 	}
+#endif
 	return EXIT_SUCCESS;
 	break;
 
Index: gnugo/patterns/dfa-mkpat.h
===================================================================
RCS file: /sources/gnugo/gnugo/patterns/dfa-mkpat.h,v
retrieving revision 1.6
diff -u -r1.6 dfa-mkpat.h
--- gnugo/patterns/dfa-mkpat.h	23 Jan 2006 18:15:51 -0000	1.6
+++ gnugo/patterns/dfa-mkpat.h	30 Dec 2006 20:55:52 -0000
@@ -41,9 +41,6 @@
  *    Data types definition     *
  ********************************/
 
-/* Intersections. */
-typedef unsigned short Intersection_t;
-
 /* Attribute list. */
 typedef struct attrib
 {
Index: gnugo/patterns/helpers.c
===================================================================
RCS file: /sources/gnugo/gnugo/patterns/helpers.c,v
retrieving revision 1.72
diff -u -r1.72 helpers.c
--- gnugo/patterns/helpers.c	23 Jan 2006 18:15:51 -0000	1.72
+++ gnugo/patterns/helpers.c	30 Dec 2006 20:55:54 -0000
@@ -617,12 +617,14 @@
 
 
   if (TRYMOVE(Apos, color)) {
-    for (k = 0; k < 4; k++)
-      if (board[cpos + delta[k]] == other
-	  && neighbor_of_string(cpos + delta[k], Apos)) {
-	epos = cpos + delta[k];
+    for (k = 0; k < 4; k++) {
+      int checked_pos = cpos + delta[k];
+      if (board[checked_pos] == other
+	  && neighbor_of_string(checked_pos, Apos)) {
+	epos = checked_pos;
 	break;
       }
+    }
 
     gg_assert(epos != NO_MOVE);
     

