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	28 Nov 2006 22:07:46 -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	28 Nov 2006 22:08:01 -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	28 Nov 2006 22:08:04 -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	28 Nov 2006 22:08:06 -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) {
@@ -681,7 +694,7 @@
 	  break;
 	}
       }
-    }
+	}
     if (target == NO_MOVE)
       continue;
     
@@ -723,7 +736,7 @@
 	cc = pos + delta[k];
 	break;
       }
-    }
+	}
     
     /* Copy the potential move to (move). */
     move = pos;
@@ -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	28 Nov 2006 22:08:23 -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;
@@ -1026,7 +1246,7 @@
 /* Return the last move done by anyone. Both if no move was found or
  * if the last move was a pass, PASS_MOVE is returned.
  */
-int
+inline int
 get_last_move()
 {
   if (move_history_pointer == 0)
@@ -1038,7 +1258,7 @@
 /* Return the color of the player doing the last move. If no move was
  * found, EMPTY is returned.
  */
-int
+inline int
 get_last_player()
 {
   if (move_history_pointer == 0)
@@ -1057,10 +1277,10 @@
  * Test if the move is a pass or not.  Return 1 if it is.
  */
 
-int
+inline 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;
@@ -1165,13 +1394,19 @@
  * is_illegal_ko_capture(pos, color) determines whether the move
  * (color) at (pos) would be an illegal ko capture.
  */
-int 
+inline int 
 is_illegal_ko_capture(int pos, int color)
 {
   ASSERT_ON_BOARD1(pos);
   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);
@@ -1402,13 +1664,13 @@
   return 1;
 }
 
-int
+inline int
 get_komaster()
 {
   return komaster;
 }
 
-int
+inline int
 get_kom_pos()
 {
   return kom_pos;
@@ -1416,7 +1678,7 @@
 
 
 /* Determine whether vertex is on the edge. */
-int
+inline int
 is_edge_vertex(int pos)
 {
   ASSERT_ON_BOARD1(pos);
@@ -1428,7 +1690,7 @@
 }
 
 /* Distance to the edge. */
-int
+inline int
 edge_distance(int pos)
 {
   int i = I(pos);
@@ -1439,7 +1701,7 @@
 
 
 /* Determine whether vertex is a corner. */
-int
+inline int
 is_corner_vertex(int pos)
 {
   ASSERT_ON_BOARD1(pos);
@@ -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)
+inline int
+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,33 +2004,19 @@
   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];
 
 
 /* Clears approxlib() cache. This function should be called only once
  * during engine initialization. Sets thresholds to zero.
  */
-void
+inline 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,29 +2309,23 @@
    * 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];
 
 
 /* Clears accuratelib() cache. This function should be called only once
  * during engine initialization. Sets thresholds to zero.
  */
-void
+inline 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;
@@ -2477,38 +2797,40 @@
  * Report the number of stones in a string.
  */
 
-int
-countstones(int str)
+inline int
+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;
+
+  ASSERT_ON_BOARD1(str_pos);
+  ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
-  s = string_number[str];
-  size = string[s].size;
+  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;
       }
     }
   }
@@ -2697,12 +3061,13 @@
  * reference point for a string.
  */
 
-int
-find_origin(int str)
+inline int
+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,60 +3196,97 @@
 
 
 /*
- * 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]);
 }
 
 /*
  * Returns true if (pos) has a neighbor of color (color).
  */
 
-int
+inline int
 has_neighbor(int pos, int color)
 {
   ASSERT_ON_BOARD1(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)
+inline int
+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;
@@ -3120,7 +3563,7 @@
 
 
 /* Retrieve a move from the move stack. */
-void
+inline void
 get_move_from_stack(int k, int *move, int *color)
 {
   gg_assert(k < stackp);
@@ -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)
@@ -3168,7 +3609,7 @@
 
 
 /* Clear statistics. */
-void
+inline void
 reset_trymove_counter()
 {
   trymove_counter = 0;
@@ -3176,7 +3617,7 @@
 
 
 /* Retrieve statistics. */
-int
+inline int
 get_trymove_counter()
 {
   return trymove_counter;
@@ -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[neig