Index: patterns/patterns.h
===================================================================
--- patterns/patterns.h	(revision 2413)
+++ patterns/patterns.h	(working copy)
@@ -293,6 +293,11 @@
 };
 
 
+/* Monte Carlo local patterns. */
+struct mc_pattern_database {
+  const char *name;
+  const unsigned int *values;
+};
 
 
 /* helper functions */
@@ -352,6 +357,8 @@
 extern struct fullboard_pattern fuseki13[];
 extern struct fullboard_pattern fuseki9[];
 
+extern struct mc_pattern_database mc_pattern_databases[];
+
 struct corner_db;
 struct corner_variation;
 struct corner_pattern;
Index: patterns/Makefile.am
===================================================================
--- patterns/Makefile.am	(revision 2413)
+++ patterns/Makefile.am	(working copy)
@@ -1,4 +1,4 @@
-noinst_PROGRAMS = mkpat joseki mkeyes uncompress_fuseki
+noinst_PROGRAMS = mkpat joseki mkeyes uncompress_fuseki mkmcpat
 EXTRA_PROGRAMS = extract_fuseki compress_fuseki
 
 DSP = dfa.dsp patterns.dsp joseki.dsp mkeyes.dsp mkpat.dsp fuseki.dsp
@@ -51,6 +51,9 @@
 joseki_AM_CPPFLAGS = $(GNU_GO_WARNINGS) -I$(top_srcdir)/sgf
 mkeyes_SOURCES = mkeyes.c
 mkeyes_LDADD = ../utils/libutils.a
+mkmcpat_SOURCES  = mkmcpat.c
+mkmcpat_LDADD = ../engine/libengine.a ../sgf/libsgf.a ../utils/libutils.a
+mkmcpat_AM_CPPFLAGS = $(GNU_GO_WARNINGS)
 extract_fuseki_SOURCES  = extract_fuseki.c
 # Yes, we currently need duplicate libengine.a and libpatterns.a.
 extract_fuseki_LDADD = ../engine/libengine.a libpatterns.a\
@@ -69,7 +72,7 @@
                  owl_attackpat.c\
 		 owl_vital_apat.c owl_defendpat.c fusekipat.c\
                  fuseki9.c fuseki13.c fuseki19.c josekidb.c\
-		 handipat.c oraclepat.c
+		 handipat.c oraclepat.c mcpat.c
 
 DBBUILT = gogo.db hoshi_keima.db hoshi_other.db komoku.db sansan.db \
 	  mokuhazushi.db takamoku.db
@@ -77,6 +80,9 @@
 DBBUILT_INPUT = -i gogo.db -i hoshi_keima.db -i hoshi_other.db -i komoku.db \
                -i sansan.db -i mokuhazushi.db -i takamoku.db
 
+MC_DB = $(srcdir)/mc_montegnu_classic.db $(srcdir)/mc_mogo_classic.db \
+        $(srcdir)/mc_uniform.db
+
 DB_TO_TAG = aa_attackpats.db attack.db barriers.db conn.db defense.db\
 	    endgame.db eyes.db fuseki.db fuseki9.dbz fuseki13.dbz fuseki19.dbz\
 	    handicap.db influence.db oracle.db owl_attackpats.db\
@@ -183,7 +189,10 @@
 handipat.c : $(srcdir)/handicap.db mkpat$(EXEEXT)
 	./mkpat -b handipat -i $(srcdir)/handicap.db -o handipat.c
 
+mcpat.c : $(MC_DB) mkmcpat$(EXEEXT)
+	./mkmcpat $(MC_DB) > mcpat.c
 
+
 ETAGS_ARGS = --language none --regex '/^Pattern[ \t]+[a-zA-Z0-9]+/' $(DB_TO_TAG)\
 	     --language auto --no-regex
 TAGS_DEPENDENCIES = $(DB_TO_TAG)
Index: patterns/Makefile.in
===================================================================
--- patterns/Makefile.in	(revision 2413)
+++ patterns/Makefile.in	(working copy)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.9.5 from Makefile.am.
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -16,8 +16,6 @@
 
 
 
-SOURCES = $(libpatterns_a_SOURCES) $(compress_fuseki_SOURCES) $(extract_fuseki_SOURCES) $(joseki_SOURCES) $(mkeyes_SOURCES) $(mkpat_SOURCES) $(uncompress_fuseki_SOURCES)
-
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
@@ -39,7 +37,7 @@
 PRE_UNINSTALL = :
 POST_UNINSTALL = :
 noinst_PROGRAMS = mkpat$(EXEEXT) joseki$(EXEEXT) mkeyes$(EXEEXT) \
-	uncompress_fuseki$(EXEEXT)
+	uncompress_fuseki$(EXEEXT) mkmcpat$(EXEEXT)
 EXTRA_PROGRAMS = extract_fuseki$(EXEEXT) compress_fuseki$(EXEEXT)
 subdir = patterns
 DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.am \
@@ -62,7 +60,7 @@
 	owl_attackpat.$(OBJEXT) owl_vital_apat.$(OBJEXT) \
 	owl_defendpat.$(OBJEXT) fusekipat.$(OBJEXT) fuseki9.$(OBJEXT) \
 	fuseki13.$(OBJEXT) fuseki19.$(OBJEXT) josekidb.$(OBJEXT) \
-	handipat.$(OBJEXT) oraclepat.$(OBJEXT)
+	handipat.$(OBJEXT) oraclepat.$(OBJEXT) mcpat.$(OBJEXT)
 am_libpatterns_a_OBJECTS = connections.$(OBJEXT) helpers.$(OBJEXT) \
 	transform.$(OBJEXT) $(am__objects_1)
 libpatterns_a_OBJECTS = $(am_libpatterns_a_OBJECTS)
@@ -82,6 +80,10 @@
 am_mkeyes_OBJECTS = mkeyes.$(OBJEXT)
 mkeyes_OBJECTS = $(am_mkeyes_OBJECTS)
 mkeyes_DEPENDENCIES = ../utils/libutils.a
+am_mkmcpat_OBJECTS = mkmcpat.$(OBJEXT)
+mkmcpat_OBJECTS = $(am_mkmcpat_OBJECTS)
+mkmcpat_DEPENDENCIES = ../engine/libengine.a ../sgf/libsgf.a \
+	../utils/libutils.a
 am_mkpat_OBJECTS = mkpat.$(OBJEXT) transform.$(OBJEXT) dfa.$(OBJEXT)
 mkpat_OBJECTS = $(am_mkpat_OBJECTS)
 mkpat_DEPENDENCIES = ../utils/libutils.a
@@ -98,10 +100,12 @@
 LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
 SOURCES = $(libpatterns_a_SOURCES) $(compress_fuseki_SOURCES) \
 	$(extract_fuseki_SOURCES) $(joseki_SOURCES) $(mkeyes_SOURCES) \
-	$(mkpat_SOURCES) $(uncompress_fuseki_SOURCES)
+	$(mkmcpat_SOURCES) $(mkpat_SOURCES) \
+	$(uncompress_fuseki_SOURCES)
 DIST_SOURCES = $(libpatterns_a_SOURCES) $(compress_fuseki_SOURCES) \
 	$(extract_fuseki_SOURCES) $(joseki_SOURCES) $(mkeyes_SOURCES) \
-	$(mkpat_SOURCES) $(uncompress_fuseki_SOURCES)
+	$(mkmcpat_SOURCES) $(mkpat_SOURCES) \
+	$(uncompress_fuseki_SOURCES)
 HEADERS = $(noinst_HEADERS)
 ETAGS = etags
 CTAGS = ctags
@@ -134,6 +138,7 @@
 GCC_ONLY_FALSE = @GCC_ONLY_FALSE@
 GCC_ONLY_TRUE = @GCC_ONLY_TRUE@
 GNU_GO_WARNINGS = @GNU_GO_WARNINGS@
+GREP = @GREP@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
@@ -160,8 +165,6 @@
 STRIP = @STRIP@
 VERSION = @VERSION@
 ac_ct_CC = @ac_ct_CC@
-ac_ct_RANLIB = @ac_ct_RANLIB@
-ac_ct_STRIP = @ac_ct_STRIP@
 am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
 am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
 am__include = @am__include@
@@ -172,20 +175,27 @@
 bindir = @bindir@
 build_alias = @build_alias@
 datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 glibconfig = @glibconfig@
 host_alias = @host_alias@
+htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
+localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
+psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 sysconfdir = @sysconfdir@
@@ -234,6 +244,9 @@
 joseki_AM_CPPFLAGS = $(GNU_GO_WARNINGS) -I$(top_srcdir)/sgf
 mkeyes_SOURCES = mkeyes.c
 mkeyes_LDADD = ../utils/libutils.a
+mkmcpat_SOURCES = mkmcpat.c
+mkmcpat_LDADD = ../engine/libengine.a ../sgf/libsgf.a ../utils/libutils.a
+mkmcpat_AM_CPPFLAGS = $(GNU_GO_WARNINGS)
 extract_fuseki_SOURCES = extract_fuseki.c
 # Yes, we currently need duplicate libengine.a and libpatterns.a.
 extract_fuseki_LDADD = ../engine/libengine.a libpatterns.a\
@@ -250,7 +263,7 @@
                  owl_attackpat.c\
 		 owl_vital_apat.c owl_defendpat.c fusekipat.c\
                  fuseki9.c fuseki13.c fuseki19.c josekidb.c\
-		 handipat.c oraclepat.c
+		 handipat.c oraclepat.c mcpat.c
 
 DBBUILT = gogo.db hoshi_keima.db hoshi_other.db komoku.db sansan.db \
 	  mokuhazushi.db takamoku.db
@@ -258,6 +271,9 @@
 DBBUILT_INPUT = -i gogo.db -i hoshi_keima.db -i hoshi_other.db -i komoku.db \
                -i sansan.db -i mokuhazushi.db -i takamoku.db
 
+MC_DB = $(srcdir)/mc_montegnu_classic.db $(srcdir)/mc_mogo_classic.db \
+        $(srcdir)/mc_uniform.db
+
 DB_TO_TAG = aa_attackpats.db attack.db barriers.db conn.db defense.db\
 	    endgame.db eyes.db fuseki.db fuseki9.dbz fuseki13.dbz fuseki19.dbz\
 	    handicap.db influence.db oracle.db owl_attackpats.db\
@@ -336,6 +352,9 @@
 mkeyes$(EXEEXT): $(mkeyes_OBJECTS) $(mkeyes_DEPENDENCIES) 
 	@rm -f mkeyes$(EXEEXT)
 	$(LINK) $(mkeyes_LDFLAGS) $(mkeyes_OBJECTS) $(mkeyes_LDADD) $(LIBS)
+mkmcpat$(EXEEXT): $(mkmcpat_OBJECTS) $(mkmcpat_DEPENDENCIES) 
+	@rm -f mkmcpat$(EXEEXT)
+	$(LINK) $(mkmcpat_LDFLAGS) $(mkmcpat_OBJECTS) $(mkmcpat_LDADD) $(LIBS)
 mkpat$(EXEEXT): $(mkpat_OBJECTS) $(mkpat_DEPENDENCIES) 
 	@rm -f mkpat$(EXEEXT)
 	$(LINK) $(mkpat_LDFLAGS) $(mkpat_OBJECTS) $(mkpat_LDADD) $(LIBS)
@@ -369,7 +388,9 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/influence.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joseki.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/josekidb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcpat.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkeyes.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkmcpat.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkpat.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oraclepat.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/owl_attackpat.Po@am__quote@
@@ -648,6 +669,9 @@
 
 handipat.c : $(srcdir)/handicap.db mkpat$(EXEEXT)
 	./mkpat -b handipat -i $(srcdir)/handicap.db -o handipat.c
+
+mcpat.c : $(MC_DB) mkmcpat$(EXEEXT)
+	./mkmcpat $(MC_DB) > mcpat.c
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
Index: interface/main.c
===================================================================
--- interface/main.c	(revision 2413)
+++ interface/main.c	(working copy)
@@ -159,7 +159,10 @@
       OPT_RESIGN_ALLOWED,
       OPT_NEVER_RESIGN,
       OPT_MONTE_CARLO,
-      OPT_MC_GAMES_PER_LEVEL
+      OPT_MC_GAMES_PER_LEVEL,
+      OPT_MC_PATTERNS,
+      OPT_MC_LIST_PATTERNS,
+      OPT_MC_LOAD_PATTERNS
 };
 
 /* names of playing modes */
@@ -309,6 +312,9 @@
   {"never-resign",   no_argument,       0, OPT_NEVER_RESIGN},
   {"monte-carlo",    no_argument,       0, OPT_MONTE_CARLO},
   {"mc-games-per-level", required_argument, 0, OPT_MC_GAMES_PER_LEVEL},
+  {"mc-patterns",    required_argument, 0, OPT_MC_PATTERNS},
+  {"mc-list-patterns", no_argument,     0, OPT_MC_LIST_PATTERNS},
+  {"mc-load-patterns", required_argument, 0, OPT_MC_LOAD_PATTERNS},
   {NULL, 0, NULL, 0}
 };
 
@@ -344,6 +350,9 @@
   FILE *output_check;
   int orientation = 0;
 
+  char mc_pattern_name[40] = "";
+  char mc_pattern_filename[320] = "";
+
   float memory = (float) DEFAULT_MEMORY; /* Megabytes used for hash table. */
 
   /* If seed is zero, GNU Go will play a different game each time. If
@@ -645,6 +654,27 @@
 	mc_games_per_level = atoi(gg_optarg);
 	break;
 
+      case OPT_MC_PATTERNS:
+	if (strlen(gg_optarg) >= sizeof(mc_pattern_name)) {
+	  fprintf(stderr, "Too long name given as value to --mc-patterns option.\n");
+	  exit(EXIT_FAILURE);
+	}
+	strcpy(mc_pattern_name, gg_optarg);
+	break;
+
+      case OPT_MC_LIST_PATTERNS:
+	list_mc_patterns();
+	return EXIT_SUCCESS;
+	break;
+
+      case OPT_MC_LOAD_PATTERNS:
+	if (strlen(gg_optarg) >= sizeof(mc_pattern_filename)) {
+	  fprintf(stderr, "Too long name given as value to --mc-load-patterns option.\n");
+	  exit(EXIT_FAILURE);
+	}
+	strcpy(mc_pattern_filename, gg_optarg);
+	break;
+
       case OPT_MODE: 
 	if (strcmp(gg_optarg, "ascii") == 0)
 	  playmode = MODE_ASCII;
@@ -987,6 +1017,23 @@
   /* Initialize the GNU Go engine. */
   init_gnugo(memory, seed);
 
+  /* Load Monte Carlo patterns if one has been specified. Either
+   * choose one of the compiled in ones or load directly from a
+   * database file.
+   */
+  if (strlen(mc_pattern_filename) > 0) {
+    if (!mc_load_patterns_from_db(mc_pattern_filename, NULL))
+      return EXIT_FAILURE;
+  }
+  else if (strlen(mc_pattern_name) > 0) {
+    if (!choose_mc_patterns(mc_pattern_name)) {
+      fprintf(stderr, "Unknown Monte Carlo pattern database name %s.\n",
+	      mc_pattern_name);
+      fprintf(stderr, "Use \"--mc-list-patterns\" to list the available databases.\n");
+      return EXIT_FAILURE;
+    }
+  }
+
   /* Read the infile if there is one. Also play up the position. */
   if (infilename) {
     if (!sgftree_readfile(&sgftree, infilename)) {
@@ -1536,6 +1583,9 @@
    --mirror-limit <n>      stop mirroring when n stones on board\n\n\
    --monte-carlo           enable Monte Carlo move generation (9x9 or smaller)\n\
    --mc-games-per-level <n> number of Monte Carlo simulations per level\n\
+   --mc-list-patterns      list names of builtin Monte Carlo patterns\n\
+   --mc-patterns <name>    choose a built in Monte Carlo pattern database\n\
+   --mc-load-patterns <filename> read Monte Carlo patterns from file\n\
    --alternate-connections\n\
    --experimental-connections\n\
    --experimental-owl-ext\n\
Index: engine/interface.c
===================================================================
--- engine/interface.c	(revision 2413)
+++ engine/interface.c	(working copy)
@@ -52,6 +52,7 @@
 
   transformation_init();
   dfa_match_init();
+  choose_mc_patterns(NULL);
 
   clear_approxlib_cache();
   clear_accuratelib_cache();
Index: engine/utils.c
===================================================================
--- engine/utils.c	(revision 2413)
+++ engine/utils.c	(working copy)
@@ -33,8 +33,8 @@
 #include "sgftree.h"
 #include "random.h"
 #include "gg_utils.h"
+#include "patterns.h"
 
-
 /*
  * Change the status of all the stones in the dragon at (dr).
  */
@@ -1959,6 +1959,43 @@
 }
 
 
+/* Set up a compiled in pattern database for use by the Monte Carlo
+ * code. If name is NULL, the first pattern database is used.
+ *
+ * The reason why this function and the next are placed here rather
+ * than in montecarlo.c is to keep that file free from dependency on
+ * patterns.h.
+ */
+int
+choose_mc_patterns(char *name)
+{
+  int k;
+  for (k = 0; mc_pattern_databases[k].name; k++) {
+    if (!name || strcmp(name, mc_pattern_databases[k].name) == 0) {
+      mc_init_patterns(mc_pattern_databases[k].values);
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+/* List compiled in Monte Carlo pattern databases. */
+void
+list_mc_patterns(void)
+{
+  int k;
+  printf("Available builtin Monte Carlo local patterns:\n\n");
+  for (k = 0; mc_pattern_databases[k].name; k++) {
+    if (k == 0)
+      printf("* %s (default)\n", mc_pattern_databases[k].name);
+    else
+      printf("* %s\n", mc_pattern_databases[k].name);
+  }
+  printf("\nUse \"--mc-patterns name\" to choose one of these.\n");
+  printf("Use \"--mc-load-patterns filename\" to directly load a pattern database.\n");
+}
+
 /*
  * Local Variables:
  * tab-width: 8
Index: engine/liberty.h
===================================================================
--- engine/liberty.h	(revision 2413)
+++ engine/liberty.h	(working copy)
@@ -497,6 +497,12 @@
 		      int allowed_moves[BOARDMAX]);
 enum dragon_status aftermath_final_status(int color, int pos);
 
+int mc_get_size_of_pattern_values_table(void);
+int mc_load_patterns_from_db(const char *filename, unsigned int *values);
+void mc_init_patterns(const unsigned int *values);
+int choose_mc_patterns(char *name);
+void list_mc_patterns(void);
+
 void uct_genmove(int color, int *move, int *forbidden_moves,
 		 int *allowed_moves, int nodes, float *move_values,
 		 int *move_frequencies);
Index: engine/montecarlo.c
===================================================================
--- engine/montecarlo.c	(revision 2413)
+++ engine/montecarlo.c	(working copy)
@@ -37,8 +37,9 @@
 /* FIXME: Replace with a DEBUG_MC symbol for use with -d. */
 static int mc_debug = 0;
 
-#define CACHE_CAPTURE_MOVES 1
+#define TURN_OFF_ASSERTIONS 1
 
+
 /* Special board code for Monte Carlo simulations.
  *
  * A liberty edge is the combination of the position of the liberty
@@ -58,11 +59,85 @@
  * origin in the global board. The reference stone is the only one
  * which is guaranteed to have a valid pointer to the "first" liberty
  * edge (just an arbitrary element in the circular list).
+ *
+ * The local_context field contains information about the surrounding
+ * 8 points. The bit layout is
+ *
+ * 23   : Black suicide.
+ * 22   : White suicide.
+ * 21   : Black self-atari.
+ * 20   : White self-atari.
+ * 19,18: Number of stones captured by black move.
+ * 17,16: Number of stones captured by white move.
+ * 15,14: Color to the southeast.
+ * 13,12: Color to the northeast.
+ * 11,10: Color to the northwest.
+ *  9, 8: Color to the southwest.
+ *  7, 6: Color to the east.
+ *  5, 4: Color to the north.
+ *  3, 2: Color to the west.
+ *  1, 0: Color to the south.
+ *
+ * The number of stones in atari is 0 if empty or not atari, 1 if one
+ * stone in atari, 2 if two stones in atari, and 3 if three or more stones
+ * in atari.
+ *
+ * The queue array is used to form a linked single list data structure
+ * with O(1) add, O(1) lookup, and O(n) delete operations. The
+ * assumption is that v1 = queue[0] points to the first board vertex
+ * in the list, v2 = queue[v1] points to the second vertex and so on.
+ * The list ends when the next vertex is the off-board point 1. Board
+ * vertices not included in the list have queue[v1] = 0. Thus an empty
+ * list is characterized by queue[0] = 1 and queue[v] = 0 for all
+ * vertices on the board. Generally queue[v] can be used to test for
+ * membership in the list. The list is used to keep track of points
+ * needing updated local context or value information.
+ *
+ * The move_values_*, partitioned_move_value_sums_*,
+ * move_partition_lists_*, and move_value_sum_* fields are together
+ * used to track move values and quickly sample according the
+ * distribution determined by the move values.
+ *
+ * The move_values_* arrays naturally hold the values of each move.
+ *
+ * The move_partition_lists_* arrays form a two-level access to the
+ * legal moves of respective color. Depending on the MAX_BOARD size,
+ * the vertices are split into 2, 4, 8, or 16 partitions (see below)
+ * where the partition number of each vertex is given by the 1, 2, 3,
+ * or 4 least significant bits of the vertex index respectively. The
+ * legal moves in each partition are linked together just like the
+ * queue array described above. The only difference is that multiple
+ * partition linked lists are represented in the same array by
+ * starting from out of board indices 0..1, 0..3, 0..7, and 0..15
+ * respectively.
+ *
+ * The partitioned_move_value_sums_* arrays are simply the sums of
+ * move values in each partition and the move_value_sum_white_* fields
+ * are the sum of the values of all legal moves.
  */
 
+#if MAX_BOARD < 4
+#define NUM_MOVE_PARTITIONS 2
+#elif MAX_BOARD < 8
+#define NUM_MOVE_PARTITIONS 4
+#elif MAX_BOARD < 16
+#define NUM_MOVE_PARTITIONS 8
+#else
+#define NUM_MOVE_PARTITIONS 16
+#endif
 
 struct mc_board {
   Intersection board[BOARDSIZE];
+  int local_context[BOARDSIZE];
+  int queue[BOARDMAX];
+  unsigned int move_values_white[BOARDMAX];
+  unsigned int move_values_black[BOARDMAX];
+  unsigned int partitioned_move_value_sums_white[NUM_MOVE_PARTITIONS];
+  unsigned int partitioned_move_value_sums_black[NUM_MOVE_PARTITIONS];
+  int move_partition_lists_white[BOARDMAX];
+  int move_partition_lists_black[BOARDMAX];
+  unsigned int move_value_sum_white;
+  unsigned int move_value_sum_black;
   int board_ko_pos;
   int reference_stone[BOARDMAX];
   int next_stone[BOARDMAX];
@@ -72,13 +147,16 @@
   Hash_data hash;
 };
 
+#define MC_ADD_TO_UPDATE_QUEUE(mc, pos) \
+  do {					\
+    if (!mc->queue[pos]) {		\
+      mc->queue[pos] = mc->queue[0];	\
+      mc->queue[0] = pos;		\
+    }					\
+  } while (0)
+
 #define MC_ON_BOARD(pos) (mc->board[pos] != GRAY)
 
-/* FIXME: In principle same a MAXCHAIN but we don't need to care about
- * such high numbers.
- */
-#define MAX_NEIGHBORS 20
-
 /* Add a liberty edge for a string at pos with liberty at lib and
  * direction dir.
  */
@@ -89,7 +167,9 @@
   int reference = mc->reference_stone[pos];
   int first_liberty_edge = mc->first_liberty_edge[reference];
 
+#if !TURN_OFF_ASSERTIONS
   gg_assert(lib + delta[dir] == pos);
+#endif
   
   if (first_liberty_edge) {
     int second_liberty_edge = mc->next_liberty_edge[first_liberty_edge];
@@ -117,7 +197,9 @@
   int next = mc->next_liberty_edge[this_liberty_edge];
   int previous = mc->previous_liberty_edge[this_liberty_edge];
   
+#if !TURN_OFF_ASSERTIONS
   gg_assert(lib + delta[dir] == pos);
+#endif
   
   if (next == this_liberty_edge) {
     mc->first_liberty_edge[reference] = 0;
@@ -174,6 +256,42 @@
 }
 
 
+/* Does the string at str have at most two liberties? In that case,
+ * add them to the update queue.
+ */
+static void
+mc_queue_max_two_liberties(struct mc_board *mc, int str)
+{
+  int reference = mc->reference_stone[str];
+  int first_liberty_edge = mc->first_liberty_edge[reference];
+  int first_liberty = first_liberty_edge >> 2;
+  int liberty_edge = mc->next_liberty_edge[first_liberty_edge];
+  int second_liberty;
+#if !TURN_OFF_ASSERTIONS
+  ASSERT1(IS_STONE(mc->board[str]), str);
+#endif
+  if (first_liberty == NO_MOVE)
+    return;
+  while (liberty_edge != first_liberty_edge) {
+    if ((liberty_edge >> 2) != first_liberty) {
+      second_liberty = liberty_edge >> 2;
+      while (liberty_edge != first_liberty_edge) {
+	if ((liberty_edge >> 2) != first_liberty
+	    && (liberty_edge >> 2) != second_liberty)
+	  return;
+	liberty_edge = mc->next_liberty_edge[liberty_edge];
+      }
+      MC_ADD_TO_UPDATE_QUEUE(mc, first_liberty);
+      MC_ADD_TO_UPDATE_QUEUE(mc, second_liberty);
+      return;
+    }
+    liberty_edge = mc->next_liberty_edge[liberty_edge];
+  }
+
+  MC_ADD_TO_UPDATE_QUEUE(mc, first_liberty);
+}
+
+
 /* Remove the string at str from the board. */
 static int
 mc_remove_string(struct mc_board *mc, int str)
@@ -185,11 +303,25 @@
   int k;
   
   do {
-    for (k = 0; k < 4; k++)
-      if (mc->board[pos + delta[k]] == other)
+    for (k = 0; k < 8; k++) {
+      if (k < 4 && mc->board[pos + delta[k]] == other) {
+	mc_queue_max_two_liberties(mc, pos + delta[k]);
 	mc_add_liberty_edge(mc, pos + delta[k], pos, k);
+      }
+      if (mc->board[pos + delta[k]] == EMPTY)
+	MC_ADD_TO_UPDATE_QUEUE(mc, pos + delta[k]);
+    }
     mc->board[pos] = EMPTY;
+    mc->local_context[NW(pos)] ^= color << 14;
+    mc->local_context[SW(pos)] ^= color << 12;
+    mc->local_context[SE(pos)] ^= color << 10;
+    mc->local_context[NE(pos)] ^= color << 8;
+    mc->local_context[WEST(pos)] ^= color << 6;
+    mc->local_context[SOUTH(pos)] ^= color << 4;
+    mc->local_context[EAST(pos)] ^= color << 2;
+    mc->local_context[NORTH(pos)] ^= color;
     hashdata_invert_stone(&(mc->hash), pos, color);
+    MC_ADD_TO_UPDATE_QUEUE(mc, pos);
     num_removed_stones++;
     pos = mc->next_stone[pos];
   } while (pos != str);
@@ -211,9 +343,48 @@
   memcpy(mc->board, board, sizeof(mc->board));
   mc->board_ko_pos = board_ko_pos;
   mc->hash = board_hash;
+  memset(mc->queue, 0, sizeof(mc->queue));
+  mc->queue[0] = 1;
 
   memset(mc->next_stone, 0, sizeof(mc->next_stone));
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    int geometry = ((mc->board[SE(pos)] << 14)
+		    | (mc->board[NE(pos)] << 12)
+		    | (mc->board[NW(pos)] << 10)
+		    | (mc->board[SW(pos)] << 8)
+		    | (mc->board[EAST(pos)] << 6)
+		    | (mc->board[NORTH(pos)] << 4)
+		    | (mc->board[WEST(pos)] << 2)
+		    | mc->board[SOUTH(pos)]);
+    mc->local_context[pos] = geometry;
+    if (board[pos] == EMPTY) {
+      int s;
+      int captured_black_stones = 0;
+      int captured_white_stones = 0;
+      if (is_self_atari(pos, WHITE))
+	mc->local_context[pos] |= 1 << 20;
+      if (is_self_atari(pos, BLACK))
+	mc->local_context[pos] |= 1 << 21;
+      if (is_suicide(pos, WHITE))
+	mc->local_context[pos] |= 1 << 22;
+      if (is_suicide(pos, BLACK))
+	mc->local_context[pos] |= 1 << 23;
+      for (s = 0; s < 4; s++) {
+	if (board[pos + delta[s]] == BLACK
+	    && countlib(pos + delta[s]) == 1)
+	  captured_black_stones += countstones(pos + delta[s]);
+	else if (board[pos + delta[s]] == WHITE
+		 && countlib(pos + delta[s]) == 1)
+	  captured_white_stones += countstones(pos + delta[s]);
+      }
+      if (captured_black_stones > 3)
+	captured_black_stones = 3;
+      if (captured_white_stones > 3)
+	captured_white_stones = 3;
+      mc->local_context[pos] |= captured_black_stones << 16;
+      mc->local_context[pos] |= captured_white_stones << 18;
+    }
+    
     if (IS_STONE(board[pos]) && mc->next_stone[pos] == 0) {
       num_stones = findstones(pos, BOARDMAX, stones);
       mc->first_liberty_edge[pos] = 0;
@@ -288,8 +459,7 @@
 #endif
 
 
-/* Write the Monte Carlo board to outfile.
- */
+/* Write the Monte Carlo board to outfile. */
 static void
 mc_showboard(struct mc_board *mc, FILE *outfile)
 {
@@ -329,43 +499,13 @@
   return num_stones;
 }
 
-/* Is a move at pos by color suicide? */
-static int
-mc_is_suicide(struct mc_board *mc, int pos, int color)
-{
-  int k;
-  
-  if (mc->board[SOUTH(pos)] == EMPTY
-      || mc->board[WEST(pos)] == EMPTY
-      || mc->board[NORTH(pos)] == EMPTY
-      || mc->board[EAST(pos)] == EMPTY)
-    return 0;
 
-  for (k = 0; k < 4; k++) {
-    int first_liberty_edge;
-    int liberty_edge;
-    int additional_liberty = 0;
-    if (!ON_BOARD(pos + delta[k]))
-      continue;
+/* Suicide is incrementally tracked by the local context information. */
+#define mc_is_suicide(mc, pos, color) \
+  ((mc->local_context[pos] >> (21 + color)) & 1)
 
-    first_liberty_edge = (pos << 2) | k;
-    liberty_edge = mc->next_liberty_edge[first_liberty_edge];
-    while (liberty_edge != first_liberty_edge) {
-      if ((liberty_edge >> 2) != pos) {
-	additional_liberty = 1;
-	break;
-      }
-      liberty_edge = mc->next_liberty_edge[liberty_edge];
-    }
 
-    if ((mc->board[pos + delta[k]] != color) ^ additional_liberty)
-      return 0;
-  }
-
-  return 1;
-}
-
-
+#if !TURN_OFF_ASSERTIONS
 /* Is a move at pos by color legal? */
 static int
 mc_is_legal(struct mc_board *mc, int pos, int color)
@@ -385,6 +525,7 @@
 
   return !mc_is_suicide(mc, pos, color);
 }
+#endif
 
 
 /* Is the string at str in atari? Always place one liberty of the
@@ -397,7 +538,9 @@
   int first_liberty_edge = mc->first_liberty_edge[reference];
   int liberty = first_liberty_edge >> 2;
   int liberty_edge = mc->next_liberty_edge[first_liberty_edge];
+#if !TURN_OFF_ASSERTIONS
   ASSERT1(IS_STONE(mc->board[str]), str);
+#endif
   if (lib)
     *lib = liberty;
   while (liberty_edge != first_liberty_edge) {
@@ -410,40 +553,69 @@
 }
 
 
-/* Does the string at str have exactly two liberties? Place those in
- * lib[0] and lib[1] unless lib is a NULL pointer. 
+/* Does the liberty edge chain at first_liberty_edge contain more than
+ * one distinct liberty?
  */
 static int
-mc_has_two_liberties(struct mc_board *mc, int str, int *lib)
+mc_is_in_atari2(struct mc_board *mc, int first_liberty, int first_liberty_edge)
 {
-  int reference = mc->reference_stone[str];
-  int first_liberty_edge = mc->first_liberty_edge[reference];
-  int first_liberty = first_liberty_edge >> 2;
   int liberty_edge = mc->next_liberty_edge[first_liberty_edge];
-  int second_liberty;
-  ASSERT1(IS_STONE(mc->board[str]), str);
-  if (lib)
-    lib[0] = first_liberty;
   while (liberty_edge != first_liberty_edge) {
-    if ((liberty_edge >> 2) != first_liberty) {
-      second_liberty = liberty_edge >> 2;
-      if (lib)
-	lib[1] = second_liberty;
-      while (liberty_edge != first_liberty_edge) {
-	if ((liberty_edge >> 2) != first_liberty
-	    && (liberty_edge >> 2) != second_liberty)
-	  return 0;
-	liberty_edge = mc->next_liberty_edge[liberty_edge];
-      }
-      return 1;
-    }
+    if ((liberty_edge >> 2) != first_liberty)
+      return 0;
     liberty_edge = mc->next_liberty_edge[liberty_edge];
   }
 
-  return 0;
+  return 1;
 }
 
 
+/* Count the number of stones that would be captured if color played at move.
+ * Return at most the number given by maxstones.
+ */
+static int
+mc_stones_in_atari(struct mc_board *mc, int move, int color, int maxstones)
+{
+  int k;
+  int stones_in_atari = 0;
+  for (k = 0; k < 4 && stones_in_atari < maxstones; k++) {
+    int pos = move + delta[k];
+    if (mc->board[pos] == OTHER_COLOR(color)
+	&& mc_is_in_atari(mc, pos, NULL))
+      stones_in_atari += mc_countstones(mc, pos, maxstones - stones_in_atari);
+  }
+  
+  return stones_in_atari;
+}
+
+
+/* Does the string at str have exactly two liberties? One liberty is
+ * assumed to be known and passed in first_liberty, whereas the second
+ * is placed in second_liberty.
+ */
+static int
+mc_has_two_liberties_one_given(struct mc_board *mc, int str,
+			       int first_liberty, int *second_liberty)
+{
+  int reference = mc->reference_stone[str];
+  int first_liberty_edge = mc->first_liberty_edge[reference];
+  int liberty_edge = first_liberty_edge;
+  *second_liberty = NO_MOVE;
+  do {
+    int liberty = liberty_edge >> 2;
+    if (liberty != first_liberty) {
+      if (*second_liberty == NO_MOVE)
+	*second_liberty = liberty;
+      else if (liberty != *second_liberty)
+	return 0;
+    }
+    liberty_edge = mc->next_liberty_edge[liberty_edge];
+  } while (liberty_edge != first_liberty_edge);
+
+  return (*second_liberty != NO_MOVE);
+}
+
+
 /* Is a move at pos by color a self atari? */
 static int
 mc_is_self_atari(struct mc_board *mc, int pos, int color)
@@ -539,43 +711,88 @@
 }
 
 
-/* Does the string at str have one or more neighbors in atari? If so,
- * return moves to capture a neighbor.
- * FIXME: Does it pay off the keep a string mark array in the mc_board
- *        struct?
+/* Update the local context information at pos, except the geometric
+ * information, by recomputing it. Most of the information is obtained
+ * by analyzing the presence of empty vertices or stones in atari
+ * adjacent to pos.
+ *
+ * FIXME: There's some computations wasted by calling the full
+ * mc_is_self_atari() and mc_stones_in_atari() functions when parts of
+ * the relevant information is already available.
  */
-static int
-mc_break_chain(struct mc_board *mc, int str, int *moves, int max_moves,
-	       int include_ko_recapture)
+static void
+mc_update_local_context(struct mc_board *mc, int pos)
 {
-  unsigned char found_neighbors[BOARDMAX];
-  int pos = str;
-  int other = OTHER_COLOR(mc->board[str]);
-  int num_moves = 0;
-  int move;
-  ASSERT1(IS_STONE(mc->board[str]), str);
-  memset(found_neighbors, 0, sizeof(found_neighbors));
-  do {
-    int k;
-    for (k = 0; k < 4; k++) {
-      if (mc->board[pos + delta[k]] == other) {
-	int reference = mc->reference_stone[pos + delta[k]];
-	if (!found_neighbors[reference]) {
-	  found_neighbors[reference] = 1;
-	  if (mc_is_in_atari(mc, pos + delta[k], &move)
-	      && (include_ko_recapture
-		  || move != mc->board_ko_pos)) {
-	    moves[num_moves++] = move;
-	    if (num_moves == max_moves)
-	      return num_moves;
-	  }
+  int min_white_liberties = 0;
+  int min_black_liberties = 0;
+  int white_liberty_through_stones = 0;
+  int black_liberty_through_stones = 0;
+  int min_white_captured_stones = 0;
+  int min_black_captured_stones = 0;
+  int white_suicide = 0;
+  int black_suicide = 0;
+  int white_self_atari = 0;
+  int black_self_atari = 0;
+  int white_captured_stones = 0;
+  int black_captured_stones = 0;
+  int k;
+  for (k = 0; k < 4; k++) {
+    int pos2 = pos + delta[k];
+    switch (mc->board[pos2]) {
+      case EMPTY:
+	min_white_liberties++;
+	min_black_liberties++;
+	break;
+      case WHITE:
+	if (mc_is_in_atari2(mc, pos, (pos << 2) | k)) {
+	  min_black_liberties++;
+	  min_white_captured_stones++;
 	}
-      }
+	else
+	  white_liberty_through_stones = 1;
+	break;
+      case BLACK:
+	if (mc_is_in_atari2(mc, pos, (pos << 2) | k)) {
+	  min_white_liberties++;
+	  min_black_captured_stones++;
+	}
+	else
+	  black_liberty_through_stones = 1;
+	break;
     }
-    pos = mc->next_stone[pos];
-  } while (pos != str);
+  }
 
-  return num_moves;
+  if (min_white_liberties + white_liberty_through_stones == 0) {
+    white_suicide = 1;
+    white_self_atari = 1;
+  }
+  else if (min_white_liberties <= 1)
+    white_self_atari = mc_is_self_atari(mc, pos, WHITE);
+
+  if (min_black_liberties + black_liberty_through_stones == 0) {
+    black_suicide = 1;
+    black_self_atari = 1;
+  }
+  else if (min_black_liberties <= 1)
+    black_self_atari = mc_is_self_atari(mc, pos, BLACK);
+
+  if (min_white_captured_stones >= 3)
+    white_captured_stones = 3;
+  else if (min_white_captured_stones > 0)
+    white_captured_stones = mc_stones_in_atari(mc, pos, BLACK, 3);
+
+  if (min_black_captured_stones >= 3)
+    black_captured_stones = 3;
+  else if (min_black_captured_stones > 0)
+    black_captured_stones = mc_stones_in_atari(mc, pos, WHITE, 3);
+
+  mc->local_context[pos] &= 0xffff;
+  mc->local_context[pos] |= black_captured_stones << 16;
+  mc->local_context[pos] |= white_captured_stones << 18;
+  mc->local_context[pos] |= white_self_atari << 20;
+  mc->local_context[pos] |= black_self_atari << 21;
+  mc->local_context[pos] |= white_suicide << 22;
+  mc->local_context[pos] |= black_suicide << 23;
 }
 
 
@@ -586,7 +803,15 @@
   int k;
   int captured_stones = 0;
   int num_direct_liberties = 0;
-  
+  int pos2;
+
+  /* Clear the update queue. */
+  while (mc->queue[0] != 1) {
+    pos2 = mc->queue[0];
+    mc->queue[0] = mc->queue[pos2];
+    mc->queue[pos2] = 0;
+  }
+
   if (pos == PASS_MOVE) {
     if (mc->board_ko_pos != NO_MOVE)
       hashdata_invert_ko(&mc->hash, mc->board_ko_pos);
@@ -610,32 +835,56 @@
     hashdata_invert_ko(&mc->hash, mc->board_ko_pos);
   mc->board_ko_pos = NO_MOVE;
 
+#if !TURN_OFF_ASSERTIONS
   ASSERT1(mc->board[pos] == EMPTY, pos);
+#endif
   mc->board[pos] = color;
   hashdata_invert_stone(&mc->hash, pos, color);
   mc->next_stone[pos] = pos;
+  
+  /* Update the geometry part of the local context. */
+  mc->local_context[NW(pos)] |= color << 14;
+  mc->local_context[SW(pos)] |= color << 12;
+  mc->local_context[SE(pos)] |= color << 10;
+  mc->local_context[NE(pos)] |= color << 8;
+  mc->local_context[WEST(pos)] |= color << 6;
+  mc->local_context[SOUTH(pos)] |= color << 4;
+  mc->local_context[EAST(pos)] |= color << 2;
+  mc->local_context[NORTH(pos)] |= color;
+  
   mc->reference_stone[pos] = pos;
   mc->first_liberty_edge[pos] = 0;
 
   for (k = 0; k < 4; k++) {
-    int pos2 = pos + delta[k];
+    pos2 = pos + delta[k];
     if (mc->board[pos2] == EMPTY) {
       mc_add_liberty_edge(mc, pos, pos2, (k + 2) % 4);
       num_direct_liberties++;
+      MC_ADD_TO_UPDATE_QUEUE(mc, pos2);
     }
   }
   
   for (k = 0; k < 4; k++) {
-    int pos2 = pos + delta[k];
+    int liberty;
+    pos2 = pos + delta[k];
+    if (mc->board[pos2] == color) {
+      if (mc->reference_stone[pos] != mc->reference_stone[pos2]) {
+	if (mc_has_two_liberties_one_given(mc, pos2, pos, &liberty))
+	  MC_ADD_TO_UPDATE_QUEUE(mc, liberty);
+	mc_join_strings(mc, pos, pos2);
+      }
+      mc_remove_liberty_edge(mc, pos2, pos, k);
+    }
+  }
+
+  for (k = 0; k < 4; k++) {
+    pos2 = pos + delta[k];
     if (mc->board[pos2] == OTHER_COLOR(color)) {
       if (mc_remove_liberty_edge(mc, pos2, pos, k) == 0)
 	captured_stones += mc_remove_string(mc, pos2);
+      else
+	mc_queue_max_two_liberties(mc, pos2);
     }
-    else if (mc->board[pos2] == color) {
-      if (mc->reference_stone[pos] != mc->reference_stone[pos2])
-	mc_join_strings(mc, pos, pos2);
-      mc_remove_liberty_edge(mc, pos2, pos, k);
-    }
   }
 
   if (captured_stones == 1
@@ -644,6 +893,23 @@
     mc->board_ko_pos = mc->first_liberty_edge[pos] >> 2;
     hashdata_invert_ko(&mc->hash, mc->board_ko_pos);
   }
+
+  mc_queue_max_two_liberties(mc, pos);
+
+  /* Traverse the update queue and update the local context for queued
+   * points.
+   */
+  for (pos2 = mc->queue[0]; pos2 != 1; pos2 = mc->queue[pos2])
+    if (pos2 != pos)
+      mc_update_local_context(mc, pos2);
+
+  /* Add the immediate neighborhood of the move to the update queue
+   * for recomputation of move values later on.
+   */
+  MC_ADD_TO_UPDATE_QUEUE(mc, pos);
+  for (k = 0; k < 8; k++)
+    if (mc->board[pos + delta[k]] == EMPTY)
+      MC_ADD_TO_UPDATE_QUEUE(mc, pos + delta[k]);
   
   return 1;
 }
@@ -651,10 +917,609 @@
 
 /***************************************************/
 
+#define NUM_GEOMETRIES 1107
+#define NUM_PROPERTIES 256
+
+struct mc_pattern_table
+{
+  unsigned short geometry_table[65536];
+  unsigned int values[(NUM_GEOMETRIES + 1) * NUM_PROPERTIES];
+};
+
+static struct mc_pattern_table mc_patterns;
+
+/* The pattern number is determined by the following bit layout:
+ * 18-8: Geometry number (range 1..1107)
+ * 7   : Opponent suicide
+ * 6   : Our self-atari
+ * 5   : Opponent self-atari
+ * 4,3 : Our captures
+ * 2,1 : Opponent captures
+ * 0   : Near
+ */
+static int
+mc_find_pattern_number(struct mc_board *mc, int move, int color,
+		       int near_previous_move)
+{
+  int local_context = mc->local_context[move];
+  int properties;
+  int geometry;
+
+  if (color == WHITE) {
+    properties = (((local_context >> 16) & 0xa0)
+		  | ((local_context >> 14) & 0x40)
+		  | ((local_context >> 17) & 0x06)
+		  | ((local_context >> 13) & 0x18));
+    geometry = local_context & 0xffff;
+  }
+  else {
+    properties = (local_context >> 15) & 0xfe;
+    geometry = (((local_context & 0x5555) << 1)
+		| ((local_context & 0xaaaa) >> 1));
+  }
+
+  return ((mc_patterns.geometry_table[geometry] << 8)
+	  | properties
+	  | near_previous_move);
+}
+
+
+/* Geometry patterns have the neighborhood defined by the order
+ *
+ * 637
+ * 2*4
+ * 518
+ *
+ * where * is the point to play. The reason for this seemingly
+ * arbitrary order is to be consistent with the delta[] array
+ * of point offsets.
+ *
+ * The 8 rotation/mirror transformations are given by reordering the
+ * points like this:
+ * 12345678 no transform
+ * 41238567 rotation 90
+ * 34127856 rotation 180
+ * 23416785 rotation 270
+ * 14328765 mirror
+ * 21435876 mirror + rotation 90
+ * 32146587 mirror + rotation 180
+ * 43217658 mirror + rotation 270
+ *
+ * The geometry is encoded by a 16-bit integer where point 1 goes into
+ * the 2 least significant bits and point 8 into the 2 most
+ * significant bits. Each pair of bits contain the corresponding
+ * EMPTY, WHITE, BLACK, GRAY (off board) values.
+ */
+static unsigned short
+mc_register_geometry_pattern(unsigned int pattern, unsigned short n)
+{
+  int k;
+  int j;
+  unsigned int transformed_pattern;
+  
+  if (mc_patterns.geometry_table[pattern] != 0)
+    return 0;
+
+  for (k = 0; k < 8; k++) {
+    transformed_pattern = pattern;
+    if (k >= 4) {
+      /* Mirror pattern. */
+      transformed_pattern = (((pattern & 0x0300) << 6)
+			     | ((pattern & 0x000c) << 4)
+			     | ((pattern & 0x0c00) << 2)
+			     | (pattern & 0x0033)
+			     | ((pattern & 0x3000) >> 2)
+			     | ((pattern & 0x00c0) >> 4)
+			     | ((pattern & 0xc000) >> 6));
+    }
+
+    /* Rotate pattern. */
+    for (j = 0; j < k % 4; j++) {
+      transformed_pattern = (((transformed_pattern & 0xc0c0) >> 6)
+			     | ((transformed_pattern & 0x3f3f) << 2));
+    }
+    mc_patterns.geometry_table[transformed_pattern] = n;
+  }
+
+  return 1;
+}
+
+
+/* Compute the mapping from 8-point local neighborhoods to rotation
+ * invariant geometry numbers.
+ */
+static void
+mc_init_pattern_geometries(void)
+{
+  unsigned int pattern;
+  unsigned short n = 1;
+
+  static int initialized = 0;
+  if (initialized)
+    return;
+  initialized = 1;
+
+  memset(mc_patterns.geometry_table, 0, sizeof(mc_patterns.geometry_table));
+  
+  for (pattern = 0; pattern < 65536; pattern++) {
+    unsigned int off_board = (pattern & (pattern >> 1)) & 0x5555;
+    if (off_board == 0x0 || off_board == 0x1410 || off_board == 0x5450)
+      n += mc_register_geometry_pattern(pattern, n);
+  }
+
+  gg_assert(n == NUM_GEOMETRIES + 1);
+}
+
+
+/* Determine which geometry numbers are matched by a pattern with
+ * possible wildcards, for use when loading pattern databases.
+ *
+ * This function is recursive with the argument n determining which
+ * point in the neighborhood is expanded for wildcards.
+ */
+static void
+mc_match_geometries(int pattern[8], int *matching_geometries, int n)
+{
+  int k;
+  int geometry = 0;
+  if (n == 8) {
+    /* The pattern has been fully expanded. Find the geometry number. */
+    for (k = 0; k < 8; k++) {
+      if (pattern[k] == 'O')
+	geometry |= WHITE << (2 * k);
+      else if (pattern[k] == 'X')
+	geometry |= BLACK << (2 * k);
+      else if (pattern[k] == '+' || pattern[k] == '|' || pattern[k] == '-')
+	geometry |= (WHITE | BLACK) << (2 * k);
+    }
+    if (mc_patterns.geometry_table[geometry] != 0) {
+      matching_geometries[mc_patterns.geometry_table[geometry]] = 1;
+    }
+  }
+  else {
+    /* Recurse with all possible expansions of the current
+     * neighborhood point.
+     */
+    int new_pattern[8];
+    memcpy(new_pattern, pattern, sizeof(new_pattern));
+    switch (pattern[n]) {
+      case '.':
+      case 'O':
+      case 'X':
+      case '|':
+      case '-':
+      case '+':
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	break;
+      case 'o':
+	new_pattern[n] = '.';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	new_pattern[n] = 'O';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	break;
+      case 'x':
+	new_pattern[n] = '.';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	new_pattern[n] = 'X';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	break;
+      case '?':
+	new_pattern[n] = '.';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	new_pattern[n] = 'O';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	new_pattern[n] = 'X';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	break;
+      case '%':
+	new_pattern[n] = '.';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	new_pattern[n] = 'O';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	new_pattern[n] = 'X';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	new_pattern[n] = '+';
+	mc_match_geometries(new_pattern, matching_geometries, n + 1);
+	break;
+    }
+  }
+}
+
+
+/* Clear a subset of the property combinations determined by shift,
+ * mask, and value.
+ */
+static void
+mc_clear_properties(int *properties, int shift, int mask, int value)
+{
+  int k;
+  for (k = 0; k < NUM_PROPERTIES; k++)
+    if (((k >> shift) & mask) == value)
+      properties[k] = 0;
+}
+
+
+/* Find which property combinations are consistent with the rules
+ * given in buf.
+ */
+static void
+mc_analyze_properties(char *buf, int *properties)
+{
+  int k;
+
+  /* First set all properties. */
+  for (k = 0; k < NUM_PROPERTIES; k++)
+    properties[k] = 1;
+
+  /* Then reset the ones which are inconsistent. */
+  if (strstr(buf, "near"))
+    mc_clear_properties(properties, 0, 1, 0);
+  if (strstr(buf, "far"))
+    mc_clear_properties(properties, 0, 1, 1);
+  if (strstr(buf, "xcap0")) {
+    mc_clear_properties(properties, 1, 3, 1);
+    mc_clear_properties(properties, 1, 3, 2);
+    mc_clear_properties(properties, 1, 3, 3);
+  }
+  if (strstr(buf, "xcap1+"))
+    mc_clear_properties(properties, 1, 3, 0);
+  else if (strstr(buf, "xcap1-")) {
+    mc_clear_properties(properties, 1, 3, 2);
+    mc_clear_properties(properties, 1, 3, 3);
+  }
+  else if (strstr(buf, "xcap1")) {
+    mc_clear_properties(properties, 1, 3, 0);
+    mc_clear_properties(properties, 1, 3, 2);
+    mc_clear_properties(properties, 1, 3, 3);
+  }
+  if (strstr(buf, "xcap2+")) {
+    mc_clear_properties(properties, 1, 3, 0);
+    mc_clear_properties(properties, 1, 3, 1);
+  }
+  else if (strstr(buf, "xcap2-"))
+    mc_clear_properties(properties, 1, 3, 3);
+  else if (strstr(buf, "xcap2")) {
+    mc_clear_properties(properties, 1, 3, 0);
+    mc_clear_properties(properties, 1, 3, 1);
+    mc_clear_properties(properties, 1, 3, 3);
+  }
+  if (strstr(buf, "xcap3")) {
+    mc_clear_properties(properties, 1, 3, 0);
+    mc_clear_properties(properties, 1, 3, 1);
+    mc_clear_properties(properties, 1, 3, 2);
+  }
+  if (strstr(buf, "ocap0")) {
+    mc_clear_properties(properties, 3, 3, 1);
+    mc_clear_properties(properties, 3, 3, 2);
+    mc_clear_properties(properties, 3, 3, 3);
+  }
+  if (strstr(buf, "ocap1+"))
+    mc_clear_properties(properties, 3, 3, 0);
+  else if (strstr(buf, "ocap1-")) {
+    mc_clear_properties(properties, 3, 3, 2);
+    mc_clear_properties(properties, 3, 3, 3);
+  }
+  else if (strstr(buf, "ocap1")) {
+    mc_clear_properties(properties, 3, 3, 0);
+    mc_clear_properties(properties, 3, 3, 2);
+    mc_clear_properties(properties, 3, 3, 3);
+  }
+  if (strstr(buf, "ocap2+")) {
+    mc_clear_properties(properties, 3, 3, 0);
+    mc_clear_properties(properties, 3, 3, 1);
+  }
+  else if (strstr(buf, "ocap2-"))
+    mc_clear_properties(properties, 3, 3, 3);
+  else if (strstr(buf, "ocap2")) {
+    mc_clear_properties(properties, 3, 3, 0);
+    mc_clear_properties(properties, 3, 3, 1);
+    mc_clear_properties(properties, 3, 3, 3);
+  }
+  if (strstr(buf, "ocap3")) {
+    mc_clear_properties(properties, 3, 3, 0);
+    mc_clear_properties(properties, 3, 3, 1);
+    mc_clear_properties(properties, 3, 3, 2);
+  }
+  if (strstr(buf, "xsafe"))
+    mc_clear_properties(properties, 5, 1, 1);
+  if (strstr(buf, "xunsafe"))
+    mc_clear_properties(properties, 5, 1, 0);
+  if (strstr(buf, "osafe"))
+    mc_clear_properties(properties, 6, 1, 1);
+  if (strstr(buf, "ounsafe"))
+    mc_clear_properties(properties, 6, 1, 0);
+  if (strstr(buf, "xsuicide"))
+    mc_clear_properties(properties, 7, 1, 0);
+  if (strstr(buf, "xnosuicide"))
+    mc_clear_properties(properties, 7, 1, 1);
+}
+
+
+/* Export the size of the array mc_patterns.values so that external
+ * callers of mc_load_patterns_from_db() know how big arrays to
+ * allocate.
+ */
+int
+mc_get_size_of_pattern_values_table(void)
+{
+  return (NUM_GEOMETRIES + 1) * NUM_PROPERTIES;
+}
+
+
+/* Load Monte Carlo patterns from file in .db format. If values is
+ * NULL, load directly into mc_patterns.values.
+ */
+int
+mc_load_patterns_from_db(const char *filename, unsigned int *values)
+{
+  FILE *pattern_file;
+  char buf[80];
+  unsigned int value;
+  int pattern_line = 0;
+  int current_pattern[8];
+  int patterns_expanded = 0;
+  int *matching_geometries;
+  int properties[NUM_PROPERTIES];
+  int k;
+  int m;
+
+  if (!values)
+    values = mc_patterns.values;
+
+  mc_init_pattern_geometries();
+  
+  pattern_file = fopen(filename, "r");
+  if (!pattern_file) {
+    gprintf("Failed to open %s file.\n", filename);
+    return 0;
+  }
+
+  matching_geometries = malloc((NUM_GEOMETRIES + 1)
+			       * sizeof(*matching_geometries));
+
+  /* Set unloaded patterns to a "-1" value. */
+  for (k = 1; k <= NUM_GEOMETRIES; k++)
+    for (m = 0; m < NUM_PROPERTIES; m++)
+      values[k * NUM_PROPERTIES + m] = 0xffffffffU;
+
+  /* Loop over the rows of the pattern database. */
+  while (fgets(buf, 80, pattern_file)) {
+    if (strchr(".xXoO|+-?%", buf[0])) {
+      /* Pattern line found */
+      patterns_expanded = 0;
+      if (pattern_line == 0) {
+	current_pattern[5] = buf[0];
+	current_pattern[2] = buf[1];
+	current_pattern[6] = buf[2];
+      }
+      else if (pattern_line == 1) {
+	current_pattern[1] = buf[0];
+	current_pattern[3] = buf[2];
+      }
+      else if (pattern_line == 2) {
+	current_pattern[4] = buf[0];
+	current_pattern[0] = buf[1];
+	current_pattern[7] = buf[2];
+      }
+      pattern_line++;
+    }
+    else if (sscanf(buf, ":%u", &value) == 1) {
+      /* Colon line found. */
+      if (value > 10000000)
+	fprintf(stderr, "Warning: pattern values should be at most 10000000.");
+
+      if (!patterns_expanded) {
+	/* Find the set of rotation invariant geometries matching the
+	 * pattern.
+	 */
+	memset(matching_geometries, 0,
+	       (NUM_GEOMETRIES + 1) * sizeof(*matching_geometries));
+	mc_match_geometries(current_pattern, matching_geometries, 0);
+	patterns_expanded = 1;
+      }
+
+      /* Find the set of matching property values. */
+      mc_analyze_properties(buf, properties);
+
+      /* Set the value for the combinations of matched geometries and
+       * properties, except those which have already been matched by a
+       * previous pattern.
+       */
+      for (k = 1; k <= NUM_GEOMETRIES; k++)
+	if (matching_geometries[k])
+	  for (m = 0; m < NUM_PROPERTIES; m++)
+	    if (properties[m] && values[k * NUM_PROPERTIES + m] == 0xffffffffU)
+	      values[k * NUM_PROPERTIES + m] = value;
+
+      pattern_line = 0;
+    }
+  }
+
+  fclose(pattern_file);
+
+  /* Set unmatched patterns/properties to a value of 1. */
+  for (k = 1; k <= NUM_GEOMETRIES; k++)
+    for (m = 0; m < NUM_PROPERTIES; m++)
+      if (values[k * NUM_PROPERTIES + m] == 0xffffffffU)
+	values[k * NUM_PROPERTIES + m] = 1;
+
+  free(matching_geometries);
+  return 1;
+}
+
+
+/* Set up local pattern values. */
+void
+mc_init_patterns(const unsigned int *values)
+{
+  mc_init_pattern_geometries();
+  memcpy(mc_patterns.values, values, sizeof(mc_patterns.values));
+}
+
+
+/* Initialize the data structures used to keep track of the local
+ * pattern values.
+ */
+static void
+mc_init_move_values(struct mc_board *mc)
+{
+  int pos;
+  int k;
+
+  memset(mc->move_values_white, 0, sizeof(mc->move_values_white));
+  memset(mc->move_values_black, 0, sizeof(mc->move_values_black));
+  memset(mc->partitioned_move_value_sums_white, 0,
+	 sizeof(mc->partitioned_move_value_sums_white));
+  memset(mc->partitioned_move_value_sums_black, 0,
+	 sizeof(mc->partitioned_move_value_sums_black));
+  memset(mc->move_partition_lists_white, 0,
+	 sizeof(mc->move_partition_lists_white));
+  memset(mc->move_partition_lists_black, 0,
+	 sizeof(mc->move_partition_lists_black));
+
+  mc->move_value_sum_white = 0.0;
+  mc->move_value_sum_black = 0.0;
+
+  for (k = 0; k < NUM_MOVE_PARTITIONS; k++) {
+    mc->move_partition_lists_white[k] = 1;
+    mc->move_partition_lists_black[k] = 1;
+  }
+  
+  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+    if (mc->board[pos] == EMPTY) {
+      int partition = pos & (NUM_MOVE_PARTITIONS - 1);
+      if (!mc_is_suicide(mc, pos, WHITE)) {
+	int pattern = mc_find_pattern_number(mc, pos, WHITE, 0);
+	unsigned int value = mc_patterns.values[pattern];
+	mc->move_values_white[pos] = value;
+	mc->partitioned_move_value_sums_white[partition] += value;
+	mc->move_value_sum_white += value;
+	mc->move_partition_lists_white[pos] = mc->move_partition_lists_white[partition];
+	mc->move_partition_lists_white[partition] = pos;
+      }
+      if (!mc_is_suicide(mc, pos, BLACK)) {
+	int pattern = mc_find_pattern_number(mc, pos, BLACK, 0);
+	unsigned int value = mc_patterns.values[pattern];
+	mc->move_values_black[pos] = value;
+	mc->partitioned_move_value_sums_black[partition] += value;
+	mc->move_value_sum_black += value;
+	mc->move_partition_lists_black[pos] = mc->move_partition_lists_black[partition];
+	mc->move_partition_lists_black[partition] = pos;
+      }
+    }
+  }
+}
+
+
+/* Add a move at a vertex which was previously not a legal move. */
+static void
+mc_add_move(struct mc_board *mc, int pos, int color, int partition,
+	    unsigned int *move_values, int *partition_lists,
+	    unsigned int *partition_sums, unsigned int *move_value_sum)
+{
+  int pattern = mc_find_pattern_number(mc, pos, color, 0);
+  unsigned int value = mc_patterns.values[pattern];
+  partition_lists[pos] = partition_lists[partition];
+  partition_lists[partition] = pos;
+  move_values[pos] = value;
+  partition_sums[partition] += value;
+  *move_value_sum += value;
+}
+
+
+/* Update a move value. */
+static void
+mc_update_move(struct mc_board *mc, int pos, int color, int partition,
+	       unsigned int *move_values, unsigned int *partition_sums,
+	       unsigned int *move_value_sum)
+{
+  int pattern = mc_find_pattern_number(mc, pos, color, 0);
+  unsigned int value = mc_patterns.values[pattern];
+  partition_sums[partition] += value - move_values[pos];
+  *move_value_sum += value - move_values[pos];
+  move_values[pos] = value;
+}
+
+
+/* Remove a move because it has been played or has become suicide. */
+static void
+mc_remove_move(int pos, int partition, unsigned int *move_values,
+	       int *partition_lists, unsigned int *partition_sums,
+	       unsigned int *move_value_sum)
+{
+  int pos2;
+  int pos3;
+  for (pos2 = partition; partition_lists[pos2] != 1; pos2 = partition_lists[pos2]) {
+    if (partition_lists[pos2] == pos)
+      break;
+  }
+  pos3 = partition_lists[pos2];
+  partition_lists[pos2] = partition_lists[pos3];
+  partition_lists[pos3] = 0;
+  partition_sums[partition] -= move_values[pos];
+  *move_value_sum -= move_values[pos];
+  move_values[pos] = 0.0;
+}
+
+
+/* Update move values for the moves listed in the update queue. */
+static void
+mc_update_move_values(struct mc_board *mc)
+{
+  int pos;
+  int partition;
+  for (pos = mc->queue[0]; pos != 1; pos = mc->queue[pos]) {
+    partition = pos & (NUM_MOVE_PARTITIONS - 1);
+    if ((mc->board[pos] != EMPTY || mc_is_suicide(mc, pos, WHITE))) {
+      if (mc->move_partition_lists_white[pos] != 0) {
+	mc_remove_move(pos, partition, mc->move_values_white,
+		       mc->move_partition_lists_white,
+		       mc->partitioned_move_value_sums_white,
+		       &mc->move_value_sum_white);
+      }
+    }
+    else {
+      if (mc->move_partition_lists_white[pos] == 0)
+	mc_add_move(mc, pos, WHITE, partition, mc->move_values_white,
+		    mc->move_partition_lists_white,
+		    mc->partitioned_move_value_sums_white,
+		    &mc->move_value_sum_white);
+      else
+	mc_update_move(mc, pos, WHITE, partition, mc->move_values_white,
+		       mc->partitioned_move_value_sums_white,
+		       &mc->move_value_sum_white);
+    }
+
+    if ((mc->board[pos] != EMPTY || mc_is_suicide(mc, pos, BLACK))) {
+      if (mc->move_partition_lists_black[pos] != 0) {
+	mc_remove_move(pos, partition, mc->move_values_black,
+		       mc->move_partition_lists_black,
+		       mc->partitioned_move_value_sums_black,
+		       &mc->move_value_sum_black);
+      }
+    }
+    else {
+      if (mc->move_partition_lists_black[pos] == 0)
+	mc_add_move(mc, pos, BLACK, partition, mc->move_values_black,
+		    mc->move_partition_lists_black,
+		    mc->partitioned_move_value_sums_black,
+		    &mc->move_value_sum_black);
+      else
+	mc_update_move(mc, pos, BLACK, partition, mc->move_values_black,
+		       mc->partitioned_move_value_sums_black,
+		       &mc->move_value_sum_black);
+    }
+  }
+}
+
+
+/***************************************************/
+
 #define ASSERT_LEGAL 1
 
 struct mc_game {
   struct mc_board mc;
+  int move_history[600];
   unsigned char settled[BOARDMAX];
   int color_to_move;
   int last_move;
@@ -666,20 +1531,27 @@
 
 /* Generate a random move. */
 static int
-mc_generate_random_move(struct mc_game *game, int only_reactive_moves)
+mc_generate_random_move(struct mc_game *game)
 {
   struct mc_board *mc = &game->mc;
   int last_move = game->last_move;
   int color = game->color_to_move;
   int depth = game->depth;
   
-  int moves[MAX_BOARD * MAX_BOARD];
-  int num_moves = 0;
   int pos;
+
+  int near_moves[BOARDMAX];
+  unsigned int saved_near_move_values[BOARDMAX];
+  int num_near_moves;
+  unsigned int *move_values;
+  unsigned int *partition_sums;
+  int *partition_lists;
+  unsigned int *move_value_sum;
+  unsigned int saved_ko_value = 0;
+  int partition;
+  int move;
   int k;
-  int offset;
-  int move;
-  int liberties[2];
+  int x;
 
   /* If we get this deep we are almost certainly playing triple ko
    * without alternative options, so just give up and score as is.
@@ -688,431 +1560,123 @@
    */
   if (depth > 600) {
     if (mc_debug) {
+      int pos;
       fprintf(stderr, "Reached 600 iterations.\n");
       mc_showboard(mc, stderr);
+      for (k = 0; k < game->depth; k++)
+	gprintf("%1m ", game->move_history[k]);
+      gprintf("\n");
+      for (pos = BOARDMIN; pos < BOARDMAX; pos++)
+	if (mc->board[pos] == EMPTY) {
+	  gprintf("%1m ", pos);
+	  fprintf(stderr, "white %7d black %7d white near %7d black near %7d\n",
+		  (int) mc->move_values_white[pos],
+		  (int) mc->move_values_black[pos],
+		  mc_patterns.values[mc_find_pattern_number(mc, pos, WHITE, 1)],
+		  mc_patterns.values[mc_find_pattern_number(mc, pos, BLACK, 1)]);
+	}
     }
     return PASS_MOVE;
   }
 
-  /* Play reactive moves, aiming to reduce the Monte-Carlo tendency to
-   * fear cuts.
+  if (color == WHITE) {
+    move_values = mc->move_values_white;
+    partition_sums = mc->partitioned_move_value_sums_white;
+    partition_lists = mc->move_partition_lists_white;
+    move_value_sum = &mc->move_value_sum_white;
+  }
+  else {
+    move_values = mc->move_values_black;
+    partition_sums = mc->partitioned_move_value_sums_black;
+    partition_lists = mc->move_partition_lists_black;
+    move_value_sum = &mc->move_value_sum_black;
+  }
+  
+  /* Temporarily update pattern values for NEAR moves. We define
+   * NEAR moves as those which had their values updated during the
+   * previous mc_play_move() call and can be found by traversing the
+   * update queue.
    */
-  if (last_move != PASS_MOVE && game->settled[last_move] == EMPTY) {
-    /* If the opponent played self-atari, with high probability capture. */
-    if (mc_is_in_atari(mc, last_move, &move)
-	&& move != mc->board_ko_pos
-	&& gg_drand() < 0.75 + 0.1 * mc_countstones(mc, last_move, 4)) {
-#if ASSERT_LEGAL
-      ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-      return move;
-    }
-    
-    /* If the opponent played an atari, try to run away or capture out
-     * of atari.
-     */
-    offset = gg_urand() % 4;
-    for (k = 0; k < 4; k++) {
-      int neighbor = last_move + delta[(k + offset) % 4];
-      if (mc->board[neighbor] == color
-	  && mc_is_in_atari(mc, neighbor, &move) == 1
-	  && gg_drand() < (0.7 + 0.1 * (mc_countstones(mc, neighbor, 4) - 1))) {
-	if (!mc_is_self_atari(mc, move, color)) {
-#if ASSERT_LEGAL
-	  ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-	  return move;
-	}
-	else if (mc_break_chain(mc, neighbor, &move, 1, 0)) {
-#if ASSERT_LEGAL
-	  ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-	  return move;
-	}
+  num_near_moves = 0;
+  if (last_move != PASS_MOVE) {
+    for (pos = mc->queue[0]; pos != 1; pos = mc->queue[pos]) {
+      if (mc->board[pos] == EMPTY && partition_lists[pos] != 0) {
+	unsigned int old_value = move_values[pos];
+	int pattern = mc_find_pattern_number(mc, pos, color, 1);
+	unsigned int new_value = mc_patterns.values[pattern];
+	partition = pos & (NUM_MOVE_PARTITIONS - 1);
+	saved_near_move_values[num_near_moves] = old_value;
+	near_moves[num_near_moves++] = pos;
+	move_values[pos] = new_value;
+	partition_sums[partition] += new_value - old_value;
+	  *move_value_sum += new_value - old_value;
       }
     }
-
-    /* If the opponent played a string with two liberties, try to
-     * capture with a ladder. (Don't actually check this, just play as
-     * if it works.)
-     */
-    if (mc_has_two_liberties(mc, last_move, liberties)
-      	&& gg_drand() < 0.77 + 0.1 * mc_countstones(mc, last_move, 4)) {
-      int first_liberty_score = 0;
-      int second_liberty_score = 0;
-      
-      for (k = 0; k < 4; k++) {
-	int neighbor = mc->board[liberties[0] + delta[k]];
-	if (neighbor == EMPTY)
-	  first_liberty_score += 2;
-	else if (neighbor == OTHER_COLOR(color))
-	  first_liberty_score += 2;
-	else if (neighbor != color)
-	  first_liberty_score -= 1;
-      }
-      
-      for (k = 0; k < 4; k++) {
-	int neighbor = mc->board[liberties[1] + delta[k]];
-	if (neighbor == EMPTY)
-	  second_liberty_score += 2;
-	else if (neighbor == OTHER_COLOR(color))
-	  second_liberty_score += 2;
-	else if (neighbor != color)
-	  second_liberty_score -= 1;
-      }
-
-      if (first_liberty_score < 3
-	  && liberties[1] != mc->board_ko_pos
-	  && ((first_liberty_score < second_liberty_score)
-	      || (first_liberty_score == second_liberty_score
-		  && gg_drand() < 0.5))
-	  && !mc_is_self_atari(mc, liberties[1], color)) {
-#if ASSERT_LEGAL
-	ASSERT1(mc_is_legal(mc, liberties[1], color), liberties[1]);
-#endif
-	return liberties[1];
-      }
-
-      if (second_liberty_score < 3
-	  && liberties[0] != mc->board_ko_pos
-	  && second_liberty_score <= first_liberty_score
-	  && !mc_is_self_atari(mc, liberties[0], color)) {
-#if ASSERT_LEGAL
-	ASSERT1(mc_is_legal(mc, liberties[0], color), liberties[0]);
-#endif
-	return liberties[0];
-      }
-    }
-
-#if 0
-    /* Connect and cut.
-     *
-     *  ?Y?
-     *  O*O
-     *  ?X?
-     */
-    for (k = 0; k < 4; k++) {
-      int down = delta[(k + offset) % 4];
-      int right = delta[(k + 1 + offset) % 4];
-      if (mc->board[last_move + down] == EMPTY
-	  && (mc->board[last_move + down + right] == color
-	      || !MC_ON_BOARD(last_move + down + right))
-	  && (mc->board[last_move + down - right] == color
-	      || !MC_ON_BOARD(last_move + down - right))) {
-	if ((mc->board[last_move + down + down] == OTHER_COLOR(color)
-	     || !MC_ON_BOARD(last_move + down + down)
-	     || (mc->board[last_move + down + down] == color
-		 && mc_has_two_liberties(mc, last_move + down + down, NULL)))
-	    && gg_drand() < 0.9
-	    && !mc_is_self_atari(mc, last_move + down, color)) {
-#if ASSERT_LEGAL
-	  if (!mc_is_legal(mc, last_move + down, color))
-	    mc_showboard(mc, stderr);
-	  ASSERT1(mc_is_legal(mc, last_move + down, color), last_move + down);
-#endif
-	  return last_move + down;
-	}
-      }
-    }
-#endif
-
-    /* If the opponent might cut, connect or at least try to connect.
-     *
-     *  oYo
-     *  o*o
-     */
-    for (k = 0; k < 4; k++) {
-      int down = delta[(k + offset) % 4];
-      int right = delta[(k + 1 + offset) % 4];
-      if (mc->board[last_move + down] == EMPTY) {
-	int a = 0;
-	int b = 0;
-	if ((mc->board[last_move + down + right] == color
-	     || !MC_ON_BOARD(last_move + down + right)))
-	  a = 1;
-	else if (mc->board[last_move + right] == color
-		 || !MC_ON_BOARD(last_move + right))
-	  a = 2;
-	if (mc->board[last_move + down - right] == color
-	    || !MC_ON_BOARD(last_move + down - right))
-	  b = 1;
-	else if (mc->board[last_move - right] == color
-		 || !MC_ON_BOARD(last_move - right))
-	  b = 2;
-
-	if (a > 0 && b > 0 && a + b < 4
-	    && gg_drand() < 0.6
-	    && last_move + down != mc->board_ko_pos
-	    && !mc_is_self_atari(mc, last_move + down, color)) {
-#if ASSERT_LEGAL
-	  ASSERT1(mc_is_legal(mc, last_move + down, color), last_move + down);
-#endif
-	  return last_move + down;
-	}
-      }
-    }
-
-    /* If the opponent invited a cut, do cut.
-     *
-     *   Y
-     *  o*O
-     *   X
-     */
-    for (k = 0; k < 4; k++) {
-      int down = delta[(k + offset) % 4];
-      int right = delta[(k + 1 + offset) % 4];
-      int other = OTHER_COLOR(color);
-      if (mc->board[last_move + down] == EMPTY
-	  && mc->board[last_move + down + down] == other) {
-	if ((mc->board[last_move + down + right] == color
-	     || mc->board[last_move + down - right] == color)
-	    && mc->board[last_move + down + right] != other
-	    && mc->board[last_move + down - right] != other
-	    && gg_drand() < 0.5
-	    && !mc_is_self_atari(mc, last_move + down, color)) {
-#if ASSERT_LEGAL
-	  ASSERT1(mc_is_legal(mc, last_move + down, color), last_move + down);
-#endif
-	  return last_move + down;
-	}
-      }
-    }
-
-    /* Crosscut.
-     *
-     *  YO
-     * o*X
-     *  o
-     */
-    for (k = 0; k < 4; k++) {
-      int down = delta[(k + offset) % 4];
-      int right = delta[(k + 1 + offset) % 4];
-      int other = OTHER_COLOR(color);
-      if (mc->board[last_move + down] == EMPTY
-	  && mc->board[last_move + down + down] != other) {
-	if (((mc->board[last_move + right] == color
-	      && mc->board[last_move + down + right] == other
-	      && mc->board[last_move + down - right] != other)
-	     || (mc->board[last_move - right] == color
-	      && mc->board[last_move + down - right] == other
-		 && mc->board[last_move + down + right] != other))
-	    && last_move + down != mc->board_ko_pos
-	    && gg_drand() < 0.3
-	    && !mc_is_self_atari(mc, last_move + down, color)) {
-#if ASSERT_LEGAL
-	  ASSERT1(mc_is_legal(mc, last_move + down, color), last_move + down);
-#endif
-	  return last_move + down;
-	}
-      }
-    }
-
-#if 0
-    /* Block.
-     *
-     *  Y?
-     *  *O
-     *  ..
-     */
-    for (k = 0; k < 4; k++) {
-      int down = delta[(k + offset) % 4];
-      int right = delta[(k + 1 + offset) % 4];
-      int other = OTHER_COLOR(color);
-      if (mc->board[last_move + down] == EMPTY
-	  && mc->board[last_move + down + down] == EMPTY
-	  && mc->board[last_move + down + down + right] == EMPTY
-	  && mc->board[last_move + down + right] == color
-	  && gg_drand() < 0.3) {
-#if ASSERT_LEGAL
-	ASSERT1(mc_is_legal(mc, last_move + down, color), last_move + down);
-#endif
-	return last_move + down;
-      }
-    }
-#endif
   }
   
-
-  /* Capturing stones is always fun. */
-  if (1) {
-    pos = BOARDMIN + gg_urand() % (BOARDMAX - BOARDMIN);
-    for (k = 0; k < BOARDMAX - BOARDMIN; k++, pos++) {
-      if (pos == BOARDMAX)
-	pos = BOARDMIN;
-      if (mc->board[pos] == OTHER_COLOR(color)
-	  && mc->reference_stone[pos] == pos
-	  && mc_is_in_atari(mc, pos, &move)
-	  && mc->board_ko_pos != move
-	  && gg_drand() < 0.15 + 0.1 * (mc_countstones(mc, pos, 5) - 1)) {
-#if ASSERT_LEGAL
-	ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-	return move;
-      }
+  /* Temporarily clear the move value of an illegal ko capture. */
+  if (mc->board_ko_pos != NO_MOVE) {
+    if (mc->board[WEST(mc->board_ko_pos)] == OTHER_COLOR(color)
+	|| mc->board[EAST(mc->board_ko_pos)] == OTHER_COLOR(color)) {
+      partition = mc->board_ko_pos & (NUM_MOVE_PARTITIONS - 1);
+      saved_ko_value = move_values[mc->board_ko_pos];
+      move_values[mc->board_ko_pos] = 0;
+      partition_sums[partition] -= saved_ko_value;
+      *move_value_sum -= saved_ko_value;
     }
   }
+  
+  /* Sample a move randomly according to the distribution given by
+   * the move values.
+   */
+  if (*move_value_sum == 0)
+    move = PASS_MOVE;
   else {
-    pos = BOARDMIN + gg_urand() % (BOARDMAX - BOARDMIN);
-    for (k = 0; k < BOARDMAX - BOARDMIN; k++, pos++) {
-      if (pos == BOARDMAX)
-	pos = BOARDMIN;
-      if (mc->board[pos] == OTHER_COLOR(color)
-	  && mc->reference_stone[pos] == pos
-	  && mc_is_in_atari(mc, pos, &move)
-	  && mc->board_ko_pos != move
-	  && gg_drand() < 0.15 + 0.1 * (mc_countstones(mc, pos, 5) - 1)) {
-#if ASSERT_LEGAL
-	ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-	return move;
-      }
-      else if (mc->board[pos] == color
-	       && mc->reference_stone[pos] == pos
-	       && mc_is_in_atari(mc, pos, &move)
-	       && gg_drand() < 0.15 + 0.1 * (mc_countstones(mc, pos, 5) - 1)
-	       && !mc_is_self_atari(mc, move, color)) {
-#if ASSERT_LEGAL
-	ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-	return move;
-      }
+    /* First choose a partition. */
+    x = (int) (gg_drand() * *move_value_sum);
+    for (k = 0; k < NUM_MOVE_PARTITIONS; k++) {
+      x -= partition_sums[k];
+      if (x < 0)
+	break;
     }
-  }      
-    
 
-  if (only_reactive_moves)
-    return PASS_MOVE;
-  
-  /* Make ten attempts to find a move nearby the previous one. */
-  if (last_move != PASS_MOVE && game->settled[last_move] == EMPTY) {
-    for (k = 0; k < 10; k++) {
-      int di = gg_rand() % 5 - 2;
-      int dj = gg_rand() % 5 - 2;
-      int i = I(last_move) + di;
-      int j = J(last_move) + dj;
-      int move = POS(i, j);
-      if (ON_BOARD2(i, j)
-	  && mc->board[move] == EMPTY
-	  && !game->settled[move]
-	  && mc_is_legal(mc, move, color)
-	  && !mc_is_self_atari(mc, move, color)
-	  && !mc_is_suicide(mc, move, OTHER_COLOR(color)))
-	return move;
-    }
-  }
-
-  /* Brown move generation follows below. */
-  num_moves = 0;
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
-    if (mc->board[pos] == EMPTY)
-      moves[num_moves++] = pos;
-
-  move = PASS_MOVE;
-  while (num_moves > 0 && move == PASS_MOVE) {
-    int index = gg_rand() % num_moves;
-    pos = moves[index];
-    /* Consider moving at pos if it is legal and not suicide. */
-    if (game->settled[pos] == EMPTY
-	&& mc_is_legal(mc, pos, color)
-	&& !mc_is_suicide(mc, pos, color)) {
-      /* Further require the move not to be suicide for the opponent... */
-      if (!mc_is_suicide(mc, pos, OTHER_COLOR(color))) {
-	move = pos;
+    /* Then choose a move in that partition. */
+    x = (unsigned int) (gg_drand() * partition_sums[k]);
+    for (pos = partition_lists[k]; pos != 1; pos = partition_lists[pos]) {
+      x -= move_values[pos];
+      if (x < 0)
 	break;
-      }
-      else {
-	/* ...however, if the move captures at least one stone,
-	 * consider it anyway.
-	 */
-	for (k = 0; k < 4; k++) {
-	  int pos2 = pos + delta[k];
-	  if (mc->board[pos2] == OTHER_COLOR(color)) {
-#if ASSERT_LEGAL
-	    ASSERT1(mc_is_legal(mc, pos, color), pos);
-#endif
-	    move = pos;
-	    break;
-	  }
-	}
-      }
     }
-    moves[index] = moves[num_moves - 1];
-    num_moves--;
-  }
 
-  /* If the move seems to use eyespace inefficiently, try to move it
-   * to a better neighbor.
-   */
-  if (1 && move != PASS_MOVE) {
-    int not_own_neighbors = 0;
-    for (k = 0; k < 4; k++) {
-      pos = move + delta[k];
-      if (mc->board[pos] == EMPTY
-	  || mc->board[pos] == OTHER_COLOR(color))
-	not_own_neighbors++;
-    }
-
-    if (not_own_neighbors == 1) {
-      int offset = gg_rand() % 4;
-      for (k = 0; k < 4; k++) {
-	int r;
-	int not_own_neighbors2 = 0;
-	int own_neighbors2 = 0;
-	pos = move + delta[(k + offset) % 4];
-	if (mc->board[pos] == EMPTY) {
-	  for (r = 0; r < 4; r++) {
-	    int pos2 = pos + delta[r];
-	    if (mc->board[pos2] == EMPTY
-		|| mc->board[pos2] == OTHER_COLOR(color))
-	      not_own_neighbors2++;
-	    else if (mc->board[pos2] == color)
-	      own_neighbors2++;
-	  }
-	  if (not_own_neighbors2 > 1
-	      && own_neighbors2 > 0
-	      && !mc_is_self_atari(mc, pos, color)) {
-	    move = pos;
-#if ASSERT_LEGAL
-	    ASSERT1(mc_is_legal(mc, move, color), move);
+    move = pos;
+#if !TURN_OFF_ASSERTIONS
+    ASSERT1(move == PASS_MOVE || move_values[move] > 0, move);
+    ASSERT1(move == PASS_MOVE || mc->board[move] == EMPTY, move);
+    ASSERT1(mc_is_legal(mc, move, color), move);
 #endif
-	    break;
-	  }
-	}
-      }
-    }
   }
 
-  /* If the move is a self atari, with high probability try to make a
-   * backfilling move first.
-   */
-  if (move != PASS_MOVE) {
-    if (mc_is_self_atari(mc, move, color)
-	&& gg_drand() < 0.8) {
-      int offset = gg_rand() % 4;
-      for (k = 0; k < 4; k++) {
-	int pos = move + delta[(k + offset) % 4];
-	if (mc->board[pos] == EMPTY) {
-	  move = pos;
-#if ASSERT_LEGAL
-	  ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-	  break;
-	}
-	else if (mc->board[pos] == color
-		 && mc_has_two_liberties(mc, pos, liberties)) {
-	  if (liberties[0] == move)
-	    move = liberties[1];
-	  else
-	    move = liberties[0];
-#if ASSERT_LEGAL
-	  ASSERT1(mc_is_legal(mc, move, color), move);
-#endif
-	  break;
-	}
-      }
-    }
+  /* Reset the value of an illegal ko capture. */
+  if (saved_ko_value > 0) {
+    partition = mc->board_ko_pos & (NUM_MOVE_PARTITIONS - 1);
+    partition_sums[partition] += saved_ko_value - move_values[mc->board_ko_pos];
+    *move_value_sum += saved_ko_value - move_values[mc->board_ko_pos];
+    move_values[mc->board_ko_pos] = saved_ko_value;
   }
   
+  /* Reset move values for NEAR moves. */
+  for (k = 0; k < num_near_moves; k++) {
+    unsigned int old_value;
+    unsigned int new_value;
+    pos = near_moves[k];
+    partition = pos & (NUM_MOVE_PARTITIONS - 1);
+    old_value = move_values[pos];
+    new_value = saved_near_move_values[k];
+    move_values[pos] = new_value;
+    partition_sums[partition] += new_value - old_value;
+    *move_value_sum += new_value - old_value;
+  }
+
   return move;
 }
 
@@ -1120,7 +1684,8 @@
 static int mc_play_random_move(struct mc_game *game, int move)
 {
   int result = mc_play_move(&game->mc, move, game->color_to_move);
-
+  mc_update_move_values(&game->mc);
+  
   if (result) {
     if (is_pass(move))
       game->consecutive_passes++;
@@ -1132,7 +1697,8 @@
       game->consecutive_ko_captures++;
     else
       game->consecutive_ko_captures = 0;
-    
+
+    game->move_history[game->depth] = move;
     game->last_move = move;
     game->color_to_move = OTHER_COLOR(game->color_to_move);
     game->depth++;
@@ -1153,7 +1719,7 @@
 
   /* First finish the game, if it isn't already. */
   while (game->consecutive_passes < 3) {
-    move = mc_generate_random_move(game, 0);
+    move = mc_generate_random_move(game);
     result = mc_play_random_move(game, move);
     ASSERT1(result, move);
   }
@@ -1389,7 +1955,7 @@
       if (k == -1 && best_uct_value > 0.0)
 	continue;
       else if (k == -1)
-	pos = mc_generate_random_move(&tree->game, 1);
+	pos = mc_generate_random_move(&tree->game);
       else
 	pos = tree->move_ordering[k];
       
@@ -1560,6 +2126,7 @@
   int pos;
 
   mc_init_board_from_global_board(&starting_position.mc);
+  mc_init_move_values(&starting_position.mc);
   starting_position.color_to_move = color;
   /* FIXME: Fill in correct information. */
   starting_position.consecutive_passes = 0;
@@ -1568,6 +2135,7 @@
   starting_position.depth = 0;
   for (pos = BOARDMIN; pos < BOARDMAX; pos++)
     starting_position.settled[pos] = forbidden_moves[pos];
+
   tree.game = starting_position;
   /* FIXME: Don't reallocate between moves. */
   tree.nodes = malloc(nodes * sizeof(*tree.nodes));
Index: patterns/mkmcpat.c
===================================================================
--- patterns/mkmcpat.c	(revision 0)
+++ patterns/mkmcpat.c	(revision 0)
@@ -0,0 +1,154 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see       *
+ * http://www.gnu.org/software/gnugo/ for more information.          *
+ *                                                                   *
+ * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 and 2007 *
+ * by the Free Software Foundation.                                  *
+ *                                                                   *
+ * This program is free software; you can redistribute it and/or     *
+ * modify it under the terms of the GNU General Public License as    *
+ * published by the Free Software Foundation - version 3 or          *
+ * (at your option) any later version.                               *
+ *                                                                   *
+ * This program is distributed in the hope that it will be useful,   *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *
+ * GNU General Public License in file COPYING for more details.      *
+ *                                                                   *
+ * You should have received a copy of the GNU General Public         *
+ * License along with this program; if not, write to the Free        *
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       *
+ * Boston, MA 02111, USA.                                            *
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Compile Monte Carlo local pattern database. This produces mcpat.c. */
+
+/* See also mc_*.db and engine/montecarlo.c. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "liberty.h"
+
+/* Trim leading path, a possible mc_ prefix, and a possible .db suffix
+ * from the filename. The caller has to free the returned pointer when
+ * it's no longer needed.
+ *
+ * FIXME: This code is quite ugly and should be possible to clean up.
+ */
+static char *
+copy_and_trim_name(const char *filename)
+{
+  int name_length = strlen(filename);
+  char *name = malloc(name_length + 1);
+  char *start = name;
+  char *p;
+  char *name2;
+  
+  strcpy(name, filename);
+
+  p = strrchr(name, '/');
+  if (p) {
+    p++;
+    name_length -= (p - name);
+    start = p;
+  }
+  
+  if (strncmp(start, "mc_", 3) == 0) {
+    start += 3;
+    name_length -= 3;
+  }
+  
+  if (strncmp(start + name_length - 3, ".db", 3) == 0)
+    start[name_length - 3] = '\0';
+
+  name2 = malloc(name_length + 1);
+  strcpy(name2, start);
+  free(name);
+  
+  return name2;
+}  
+
+int
+main(int argc, char *argv[])
+{
+  int N = mc_get_size_of_pattern_values_table();
+  unsigned int *values;
+  int i;
+  int k;
+  char *name;
+
+  if (argc < 2) {
+    fprintf(stderr, "Usage: ...\n");
+    exit(EXIT_FAILURE);
+  }
+
+  printf("\
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\\\n\
+ * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see       *\n\
+ * http://www.gnu.org/software/gnugo/ for more information.          *\n\
+ *                                                                   *\n\
+ * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 and 2007 *\n\
+ * by the Free Software Foundation.                                  *\n\
+ *                                                                   *\n\
+ * This program is free software; you can redistribute it and/or     *\n\
+ * modify it under the terms of the GNU General Public License as    *\n\
+ * published by the Free Software Foundation - version 3             *\n\
+ * or (at your option) any later version                             *\n\
+ *                                                                   *\n\
+ * This program is distributed in the hope that it will be useful,   *\n\
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of    *\n\
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *\n\
+ * GNU General Public License in file COPYING for more details.      *\n\
+ *                                                                   *\n\
+ * You should have received a copy of the GNU General Public         *\n\
+ * License along with this program; if not, write to the Free        *\n\
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       *\n\
+ * Boston, MA 02111, USA.                                            *\n\
+\\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n");
+
+  printf("/* This file is automatically generated by mkmcpat. Do not\n");
+  printf(" * edit it directly. Instead, edit the pattern databases\n");
+  printf(" * mc_*.db.\n");
+  printf(" */\n\n");
+  printf("#include <stdio.h> /* for NULL */\n");
+  printf("#include \"liberty.h\"\n\n");
+  printf("#include \"patterns.h\"\n\n");
+
+  values = malloc(N * sizeof(*values));
+
+  for (i = 1; i < argc; i++) {
+    if (!mc_load_patterns_from_db(argv[i], values))
+      exit(EXIT_FAILURE);
+
+    name = copy_and_trim_name(argv[i]);
+
+    printf("static const unsigned int %s_values[] = {\n", name);
+    for (k = 0; k < N; k++) {
+      printf("%u, ", values[k]);
+      if (k % 8 == 7)
+	printf("\n");
+    }
+    printf("\n};\n\n");
+
+    free(name);
+  }
+
+  printf("struct mc_pattern_database mc_pattern_databases[] = {\n");
+  for (i = 1; i < argc; i++) {
+    name = copy_and_trim_name(argv[i]);
+    printf("  {\"%s\", %s_values},\n", name, name);
+    free(name);
+  }
+  printf("  {NULL, NULL}};\n");
+
+  return 0;
+}
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * c-basic-offset: 2
+ * End:
+ */
Index: patterns/mc_montegnu_classic.db
===================================================================
--- patterns/mc_montegnu_classic.db	(revision 0)
+++ patterns/mc_montegnu_classic.db	(revision 0)
@@ -0,0 +1,150 @@
+# This is an approximate adaptation to patterns of the original
+# simulation policy of GNU Go's Monte Carlo code.
+
+# Proper eyes.
+
+oOo
+O*O
+oO?
+
+:0
+
+oOo
+O*O
+---
+
+:0
+
+|Oo
+|*O
++--
+
+:0
+
+
+# If the opponent played self-atari, with high probability capture.
+# This also applies to capturing out of recent atari on own stones.
+
+?X%
+?*%
+%%%
+
+:10000,ocap1,near,osafe
+:13000,ocap2,near
+:20000,ocap3,near
+
+
+# Extend out of recent atari.
+
+?O%
+?*%
+%%%
+
+:2000,xcap1,osafe,near
+:4000,xcap2,osafe,near
+:6000,xcap3,osafe,near
+
+
+# If the opponent might cut, connect or at least try to connect.
+# 
+#  oYo
+#  o*o
+
+?XO
+O*?
+%%%
+
+:1000,near,osafe
+
+?X?
+O*O
+%%%
+
+:1000,near,osafe
+
+?X|
+O*|
+%%%
+
+:1000,near,osafe
+
+OX|
+?*|
+%%%
+
+:1000,near,osafe
+
+
+# If the opponent invited a cut, do cut.
+# 
+#   Y
+#  o*O
+#   X
+# 
+
+?X?
+o*O
+?X?
+
+:400,near,osafe
+
+|X?
+|*O
+|X?
+
+:400,near,osafe
+
+
+# Crosscut.
+# 
+#  YO
+# o*X
+#  o
+#
+
+?XO
+o*X
+?o?
+
+:100,near,osafe
+
+?XO
+o*X
+---
+
+:100,near,osafe
+
+|XO
+|*X
++--
+
+:100,near,osafe
+ 
+
+# Capturing stones is always fun.
+
+?X%
+?*%
+%%%
+
+:30,ocap1,far,osafe
+:40,ocap2,far
+:60,ocap3,far
+
+
+# Slightly prefer near moves.
+
+??%
+?*%
+%%%
+
+:3,near,osafe
+
+
+# Default move value.
+
+??%
+?*%
+%%%
+
+:1
Index: patterns/mc_mogo_classic.db
===================================================================
--- patterns/mc_mogo_classic.db	(revision 0)
+++ patterns/mc_mogo_classic.db	(revision 0)
@@ -0,0 +1,229 @@
+# This is an approximate adaptation to patterns of the simulation
+# policy for an early version of MoGo, as published in the report
+# "Modification of UCT with Patterns in Monte-Carlo Go", RR-6062, by
+# Sylvain Gelly, Yizao Wang, Rémi Munos, and Olivier Teytaud.
+
+# Proper eyes.
+
+oOo
+O*O
+oO?
+
+:0
+
+
+oOo
+O*O
+---
+
+:0
+
+
+|Oo
+|*O
++--
+
+:0
+
+
+# Run away from atari or capture near move.
+
+?X?
+?*?
+???
+
+:10000,ocap1+,osafe,near
+
+?O?
+?*?
+???
+
+:10000,xcap1+,osafe,near
+
+
+# 1. Patterns for hane.
+# 1.1 First figure.
+
+XOX
+.*.
+???
+
+:100,near
+
+
+OXO
+.*.
+???
+
+:100,near
+
+
+# 1.2 Second figure.
+
+XO.
+.*.
+?.?
+
+:100,near
+
+
+OX.
+.*.
+?.?
+
+:100,near
+
+
+# 1.3 Third figure.
+
+XO?
+X*.
+?.?
+
+:100,near
+
+
+OX?
+O*.
+?.?
+
+:100,near
+
+
+# 1.4 Fourth figure.
+
+OXX
+.*.
+?.?
+
+:100,near
+
+
+# 2. Patterns for cut 1.
+
+XO?
+O*X
+???
+
+:100,near
+
+
+XO?
+O*O
+?O?
+
+:100,near
+
+
+XO?
+O*.
+?.?  
+
+:100,near
+
+
+OX?
+X*.
+?.?
+
+:100,near
+
+
+OX?
+X*X
+?X?
+
+:100,near
+
+
+OX?
+X*.
+?.?
+
+:100,near
+
+  
+# 3. Patterns for cut 2.
+
+?O?
+X*X
+ooo
+
+:100,near
+
+
+?X?
+O*O
+xxx
+
+:100,near
+
+	
+# 4. Patterns on the edge.
+# 4.1 First figure.
+
+O.?
+X*?
+---
+
+:100,near
+
+
+X.?
+O*?
+---
+
+:100,near
+
+
+# 4.2 Second figure.
+
+XO?
+x*?
+---
+
+:100,near
+
+
+?X?
+O*o
+---
+
+:100,near
+
+
+# 4.3 Third figure.
+
+XO?
+?*?
+---
+
+:100,near
+
+
+# 4.4 Fourth figure.
+
+OX?
+o*?
+---
+
+:100,near
+
+
+# 4.5 Fifth figure.
+
+?XO
+O*X
+---
+
+:100,near
+
+
+# Default value.
+
+???
+?*?
+???
+
+:1
+
Index: patterns/mc_uniform.db
===================================================================
--- patterns/mc_uniform.db	(revision 0)
+++ patterns/mc_uniform.db	(revision 0)
@@ -0,0 +1,23 @@
+# This is the so called "light playout" simulation policy where moves
+# are chosen with uniform probability over the legal moves, except for
+# playing into small proper eyes.
+
+# Proper eyes.
+
+oOo
+O*O
+oO?
+
+:0
+
+oOo
+O*O
+---
+
+:0
+
+|Oo
+|*O
++--
+
+:0
