diff -N -r -u -X .ignore gnugo-copy/config.vcin gnugo/config.vcin
--- gnugo-copy/config.vcin	2007-01-22 14:41:38.781250000 +0100
+++ gnugo/config.vcin	2007-03-09 00:39:05.343750000 +0100
@@ -30,6 +30,9 @@
 /* GAIN/LOSS codes. Disabled by default. */
 #define EXPERIMENTAL_OWL_EXT 0
 
+/* Disable unneeded things. 0 standard. */
+#define FINAL_RELEASE 0
+
 /* Define as 1 to use the grid optimisation, or 2 to run it in self-test mode
    */
 #define GRID_OPT 1
diff -N -r -u -X .ignore gnugo-copy/doc/dfa.texi gnugo/doc/dfa.texi
--- gnugo-copy/doc/dfa.texi	2005-04-16 22:47:35.000000000 +0200
+++ gnugo/doc/dfa.texi	2007-03-14 17:05:58.750000000 +0100
@@ -1,7 +1,6 @@
 In this chapter, we describe the principles of the GNU Go DFA
 pattern matcher.  The aim of this system is to permit a fast
-pattern matching when it becomes time critical like in owl
-module (@ref{The Owl Code}). Since GNU Go 3.2, this is enabled
+pattern matching. Since GNU Go 3.2, this is enabled
 by default. You can still get back the traditional pattern matcher
 by running @command{configure --disable-dfa} and then recompiling
 GNU Go. 
diff -N -r -u -X .ignore gnugo-copy/doc/dragon.texi gnugo/doc/dragon.texi
--- gnugo-copy/doc/dragon.texi	2004-10-25 03:06:22.000000000 +0200
+++ gnugo/doc/dragon.texi	2007-03-14 16:08:11.890625000 +0100
@@ -17,8 +17,8 @@
 Later routines called by @code{genmove()} will then have access to this
 information. This document attempts to explain the philosophy and
 algorithms of this preliminary analysis, which is carried out by the
-two routines @code{make_worm()} and @code{make_dragon()} in 
-@file{dragon.c}.
+two routines @code{make_worms()} (in @file{worm.c}) and
+@code{make_dragons()} (in @file{dragon.c}).
 
 @cindex dragon
 @cindex worm
@@ -83,12 +83,16 @@
   int unconditional_status;
   int attack_points[MAX_TACTICAL_POINTS];
   int attack_codes[MAX_TACTICAL_POINTS];
+  int discarded_attacks[MAX_TACTICAL_POINTS];
   int defense_points[MAX_TACTICAL_POINTS];
   int defend_codes[MAX_TACTICAL_POINTS];
+  int discarded_defenses[MAX_TACTICAL_POINTS];
   int attack_threat_points[MAX_TACTICAL_POINTS];
-  int attack_threat_codes[MAX_TACTICAL_POINTS]; 
+  int attack_threat_codes[MAX_TACTICAL_POINTS];
+  int discarded_att_threats[MAX_TACTICAL_POINTS];
   int defense_threat_points[MAX_TACTICAL_POINTS];
   int defense_threat_codes[MAX_TACTICAL_POINTS];
+  int discarded_def_threats[MAX_TACTICAL_POINTS];
 @};
 @end example
 
@@ -109,7 +113,8 @@
 other worm. Intersections that are shared are counted with equal
 fractional values for each worm. This measures the direct territorial
 value of capturing a worm. @dfn{effective_size} is a floating point number.
-Only intersections at a distance of 4 or less are counted.
+Only intersections at a distance (empty vertices between a worm and an
+intersection) of 5 or less are counted.
 @end quotation
 @item @code{origin}
 @quotation
@@ -220,8 +225,9 @@
 @end quotation
 @item @code{cutstone2} 
 @quotation
-Cutting points are identified by the patterns in the connections
-database. Proper cuts are handled by the fact that attacking and
+Number of potential cuts involving the worm. Cutting points are
+identified by the patterns in the connections database. Proper
+cuts are handled by the fact that attacking and
 defending moves also count as moves cutting or connecting the
 surrounding dragons.  The @code{cutstone2} field is set during 
 @code{find_cuts()}, called from @code{make_domains()}.
@@ -248,7 +254,8 @@
 opposite color can be killed. More precisely an
 @dfn{inessential string} is a string S of genus zero,
 not adjacent to any opponent string which can be easily
-captured, and which has no edge liberties or second
+captured, which is not cutstone, and which has up to
+2 edge liberties and no second
 order liberties, and which satisfies the following
 further property: If the string is removed from the
 board, then the remaining cavity only borders worms of the
@@ -266,7 +273,7 @@
 even if the opponent is allowed an arbitrary number of consecutive
 moves.
 @end quotation
-@item unconditional_status
+@item @code{unconditional_status}
 @quotation
 Unconditional status is also set by the function
 @code{unconditional_life}. This is set @code{ALIVE} for stones which are
@@ -285,14 +292,10 @@
 transformed into an invincible group by some number of consecutive
 moves. Well, this is not entirely true because there is a rare class of
 seki groups not satisfying this condition. Exactly which these are is
-left as an exercise for the reader. Currently @code{unconditional_life},
-which strictly follows the definitions above, calls such seki groups
-unconditionally dead, which of course is a misfeature. It is possible to
-avoid this problem by making the algorithm slightly more complex, but
-this is left for a later revision.
+shown in a comment in @file{unconditional.c}.
 @end quotation
-@item @code{int attack_points[MAX_TACTICAL_POINTS]}
-@item @code{attack_codes[MAX_TACTICAL_POINTS]}
+@item @code{int attack_points[MAX_TACTICAL_POINTS];}
+@item @code{int attack_codes[MAX_TACTICAL_POINTS];}
 @item @code{int defense_points[MAX_TACTICAL_POINTS];}
 @item @code{int defend_codes[MAX_TACTICAL_POINTS];}
 @quotation
@@ -310,6 +313,14 @@
 @quotation
 These are points that threaten to attack or defend a worm.
 @end quotation
+@item @code{int discarded_attacks[MAX_TACTICAL_POINTS];}
+@item @code{int discarded_defenses[MAX_TACTICAL_POINTS];}
+@item @code{int discarded_att_threats[MAX_TACTICAL_POINTS];}
+@item @code{int discarded_def_threats[MAX_TACTICAL_POINTS];}
+@quotation
+These are checked points that haven't led to any positive result.
+Used to not check the same point more than once.
+@end quotation
 @end itemize
 
 The function @code{makeworms()} will generate data for all worms.
@@ -343,10 +354,6 @@
 XXX...       
 
 @end example
-@findex dragon_eye
-
-The code for this type of amalgamation is in the routine
-@code{dragon_eye()}, discussed further in EYES.
 
 Next, we amalgamate strings which seem uncuttable. We amalgamate dragons
 which either share two or more common liberties, or share one liberty
@@ -367,9 +374,9 @@
 @section Connection
 @cindex connections
 
-The fields @code{black_eye.cut} and @code{white_eye.cut} are set where the
+The fields in @code{cutting_points} are set where the
 opponent can cut, and this is done by the B (break) class patterns in
-@file{conn.db}.  There are two important uses for this field, which can be
+@file{conn.db}.  There are two important uses for this table, which can be
 accessed by the autohelper functions @code{xcut()} and @code{ocut()}. The
 first use is to stop amalgamation in positions like
 
@@ -534,6 +541,7 @@
   int safety;
   float weakness;
   float weakness_pre_owl;
+  float strategic_size;
   int escape_route;
   struct eyevalue genus;
   int heye;
@@ -541,16 +549,20 @@
   int surround_status;
   int surround_size;
   int semeais;
-  int semeai_margin_of_safety;
+  int semeai_defense_code;
   int semeai_defense_point;
-  int semeai_defense_certain;  
+  int semeai_defense_certain;
+  int semeai_defense_target;
+  int semeai_attack_code;
   int semeai_attack_point;
   int semeai_attack_certain;
+  int semeai_attack_target;
   int owl_threat_status;
   int owl_status;
   int owl_attack_point;
   int owl_attack_code;
   int owl_attack_certain;
+  int owl_attack_node_count;
   int owl_second_attack_point;
   int owl_defense_point;
   int owl_defense_code;
@@ -607,7 +619,7 @@
 @quotation
 The dragon number, used as a key into the @code{dragon2} array.
 @end quotation
-@item origin
+@item @code{origin}
 @cindex dragon origin
 @quotation
 The origin of the dragon is a unique particular vertex
@@ -616,12 +628,12 @@
 copied to the dragon origins. Amalgamation of two dragons
 amounts to changing the origin of one.
 @end quotation
-@item size
+@item @code{size}
 @cindex dragon size
 @quotation
 The number of stones in the dragon.
 @end quotation
-@item effective size
+@item @code{effective size}
 @cindex effective size
 @quotation
 The sum of the effective sizes of the constituent worms.
@@ -630,14 +642,14 @@
 cardinality of the dragon plus the number of empty vertices which are
 nearer this dragon than any other.
 @end quotation
-@item crude_status
+@item @code{crude_status}
 @quotation
 (ALIVE, DEAD, UNKNOWN, CRITICAL). An early measure of the life
 potential of the dragon. It is computed before the owl code is
 run and is superceded by the status as soon as that becomes
 available.
 @end quotation
-@item status
+@item @code{status}
 @cindex dragon status
 @quotation
 The dragon status is the best measure of the dragon's health.
@@ -649,21 +661,11 @@
 Here are definitions of the fields in the @code{dragon2} array.
 
 @itemize @bullet
-@item origin
+@item @code{origin}
 @quotation
 The origin field is duplicated here.
 @end quotation
-@item adjacent
 @item @code{adjacent[MAX_NEIGHBOR_DRAGONS]}
-@cindex neighbor dragons
-@cindex adjacent dragons
-@findex find_neighbor_dragons
-@quotation
-Dragons of either color near the given one are called @dfn{neighbors}.
-They are computed by the function @code{find_neighbor_dragons()}.
-The @code{dragon2.adjacent} array gives the dragon numbers of
-these dragons.
-@end quotation
 @item @code{neighbors}
 @cindex neighbor dragons
 @cindex adjacent dragons
@@ -671,19 +673,15 @@
 @quotation
 Dragons of either color near the given one are called @dfn{neighbors}.
 They are computed by the function @code{find_neighbor_dragons()}.
-The @code{dragon2.adjacent} array gives the dragon numbers of
-these dragons.
+The @code{adjacent} array gives the dragon numbers of
+these dragons and @code{neighbors} gives the number of them.
 @end quotation
-@item neighbors
-@quotation
-The number of neighbor dragons.
-@end quotation
-@item hostile_neighbors
+@item @code{hostile_neighbors}
 @quotation
 The number of neighbor dragons of the opposite color.
 @end quotation
-@item moyo_size
-@item float moyo_territorial_value
+@item @code{moyo_size}
+@item @code{moyo_territorial_value}
 @findex compute_surrounding_moyo_sizes
 @quotation
 The function @code{compute_surrounding_moyo_sizes()} assigns
@@ -691,7 +689,7 @@
 each dragon (@pxref{Territory and Moyo}). This is the 
 moyo size. They are recorded in these fields.
 @end quotation
-@item safety
+@item @code{safety}
 @cindex dragon safety
 @quotation
 The dragon safety can take on one of the values
@@ -707,8 +705,8 @@
 @item INESSENTIAL - the dragon is unimportant (e.g. nakade stones) and dead
 @end itemize
 @end quotation
-@item weakness
-@item weakness_pre_owl
+@item @code{weakness}
+@item @code{weakness_pre_owl}
 @cindex dragon weakness
 @cindex weakness
 @quotation
@@ -717,7 +715,12 @@
 dragons in greater need of safety. The field @code{weakness_pre_owl}
 is a preliminary computation before the owl code is run.
 @end quotation
-@item escape_route
+@item @code{strategic_size}
+@cindex strategic_size
+@quotation
+An effective size including weakness of neighbors.
+@end quotation
+@item @code{escape_route}
 @cindex dragon escape_route
 @cindex escape_route
 @findex compute_escape
@@ -726,7 +729,7 @@
 in case it cannot make two eyes locally. Documentation
 may be found in @ref{Escape}.
 @end quotation
-@item struct eyevalue genus
+@item @code{genus}
 @cindex dragon genus
 @cindex genus
 @quotation
@@ -744,11 +747,11 @@
 
 @end example
 @end quotation
-@item heye
+@item @code{heye}
 @quotation
 Location of a half eye attached to the dragon.
 @end quotation
-@item lunch
+@item @code{lunch}
 @cindex dragon lunch
 @cindex lunch
 @quotation
@@ -756,8 +759,8 @@
 can be captured. In contrast with worm lunches, a dragon
 lunch must be able to defend itself.
 @end quotation
-@item surround_status
-@item surround_size
+@item @code{surround_status}
+@item @code{surround_size}
 @cindex surround_status
 @cindex surround_size
 @cindex surround
@@ -766,18 +769,26 @@
 it is @dfn{surrounded}. See @ref{Surrounded Dragons} and
 the comments in @file{surround.c} for more information about the
 algorithm.  Used in computing the escape_route, and also callable
-from patterns (currently used by CB258).  
+from patterns.  
 @end quotation
-@item semeais
-@item semeai_defense_point
-@item semeai_defense_certain
-@item semeai_attack_point
-@item semeai_attack_certain
-@cindex semeai
+@item @code{semeais}
+@item @code{semeai_defense_code}
+@item @code{semeai_defense_point}
+@item @code{semeai_defense_certain}
+@item @code{semeai_defense_target}
+@item @code{semeai_attack_code}
+@item @code{semeai_attack_point}
+@item @code{semeai_attack_certain}
+@item @code{semeai_attack_target}
+@cindex semeais
+@cindex semeai_defense_code
 @cindex semeai_defense_point
 @cindex semeai_defense_certain
+@cindex semeai_defense_target
+@cindex semeai_attack_code
 @cindex semeai_attack_point
 @cindex semeai_attack_certain
+@cindex semeai_attack_target
 @quotation
 If two dragons of opposite color both have the status CRITICAL
 or DEAD they are in a @dfn{semeai} (capturing race), and their
@@ -785,20 +796,26 @@
 @code{owl_analyze_semeai()} in @file{owl.c}, which attempts to
 determine which is alive, which dead, or if the result is
 seki, and whether it is important who moves first. The
-function @file{new_semeai()} in @file{semeai.c} attempts
+function @code{semeai()} in @file{semeai.c} attempts
 to revise the statuses and to generate move reasons based
 on these results. The field @code{dragon2.semeais} is nonzero
 if the dragon is an element of a semeai, and equals the
 number of semeais (seldom more than one). The semeai defense
 and attack points are locations the defender or attacker
-must move to win the semeai. The field @code{semeai_margin_of_safety}
-is intended to indicate whether the semeai is close or not
-but currently this field is not maintained. The fields
+must move to win the semeai and the result code of these moves is
+also stored. In @code{semeai_defense_target} and
+@code{semeai_attack_target} an origin of an opponent dragon in
+semeai, on which the move has impact, is stored. The fields
 @code{semeai_defense_certain} and @code{semeai_attack_certain}
 indicate that the semeai code was able to finish analysis
 without running out of nodes.
 @end quotation
-@item owl_status
+@item @code{owl_threat_status}
+@quotation
+Informs, whether the dragon has any defense or attack threats
+(@code{CAN_THREATEN_ATTACK} or @code{CAN_THREATEN_DEFENSE}).
+@end quotation
+@item @code{owl_status}
 @quotation
 This is a classification similar to @code{dragon.crude_status}, but
 based on the life and death reading in @file{owl.c}.
@@ -810,48 +827,67 @@
 @code{owl_defend()} is run, and if it can be defended it
 is classified as @code{CRITICAL}, and if not, as @code{DEAD}.
 @end quotation
-@item owl_attack_point
+@item @code{owl_attack_point}
 @cindex owl_attack_point
 @quotation
 If the dragon can be attacked this is the point to attack the dragon.
 @end quotation
-@item owl_attack_code
+@item @code{owl_attack_code}
 @cindex owl_attack_code
 @quotation
-The owl attack code, It can be WIN, KO_A, KO_B or 0 (@pxref{Return Codes}).
+The owl attack code, It can be WIN, KO_A, GAIN, LOSS,
+KO_B or 0 (@pxref{Return Codes}).
 @end quotation
-@item owl_attack_certain
+@item @code{owl_attack_certain}
 @cindex owl_attack_certain
 @quotation
 The owl reading is able to finish analyzing the attack
 without running out of nodes.
 @end quotation
-@item owl_second_attack_point
+@item @code{owl_attack_node_count}
+@cindex owl_attack_node_count
+@quotation
+Number of nodes used during analyze of attack move.
+@end quotation
+@item @code{owl_second_attack_point}
 @cindex owl_second_attack_point
 @quotation
 A second attack point.
 @end quotation
-@item owl_defense_point
+@item @code{owl_defense_point}
 @cindex owl_defense_point
 @quotation
 If the dragon can be defended, this is the place to play.
 @end quotation
-@item owl_defense_code
+@item @code{owl_defense_code}
 @cindex owl_defense_code
 @quotation
-The owl defense code, It can be WIN, KO_A, KO_B or 0 (@pxref{Return Codes}).
+The owl defense code, It can be WIN, KO_A, GAIN, LOSS,
+KO_B or 0 (@pxref{Return Codes}).
 @end quotation
-@item owl_defense_certain
+@item @code{owl_defense_certain}
 @cindex owl_defense_certain
 @quotation
 The owl code is able to finish analyzing the defense without
 running out of nodes.
 @end quotation
-@item owl_second_defense_point
+@item @code{owl_second_defense_point}
 @cindex owl_second_defense_point
 @quotation
 A second owl defense point.
 @end quotation
+@item @code{owl_attack_kworm}
+@cindex owl_attack_kworm
+@quotation
+Position of a worm, which can be killed during attack on the dragon
+(@code{owl_attack_code} has to be @code{GAIN}).
+@end quotation
+@item @code{owl_defense_kworm}
+@cindex owl_defense_kworm
+@quotation
+Position of our worm (part of the dragon) abandoned during defense of
+the dragon (@code{owl_defend_code} has to be @code{LOSS}).
+@end quotation
 @end itemize
 
 @node Dragons in Color
diff -N -r -u -X .ignore gnugo-copy/doc/move_generation.texi gnugo/doc/move_generation.texi
--- gnugo-copy/doc/move_generation.texi	2005-10-18 19:22:28.000000000 +0200
+++ gnugo/doc/move_generation.texi	2007-03-13 13:46:22.937500000 +0100
@@ -214,11 +214,12 @@
 the simultaneous attack of one worm and the defense of another. As for
 attack and defense moves, it's important that all moves which win a
 semeai are found, so an informed choice can be made between them.
+Semeai move reasons are set by the semeai module.
+
+One might also wish to list moves which increase the lead in a semeai
+race (removes ko threats) for use as secondary move reasons. Analogously,
+if we are behind in the race. However this has not been implemented yet.
 
-Semeai move reasons should be set by the semeai module. However this
-has not been implemented yet. One might also wish to list moves
-which increase the lead in a semeai race (removes ko threats) for use
-as secondary move reasons. Analogously if we are behind in the race.
 
 @node  Making eyes
 @subsection Making or destroying eyes
@@ -229,8 +230,8 @@
 will be valued substantially higher if this is the case. As usual it's
 important to find all moves that change the eye count.
 
-(This is part of what eye_finder was doing. Currently it only finds
-one vital point for each unstable eye space.)
+The eye module (@file{optics.c}) is handling this. It uses eyes patterns
+database @file{patterns/eyes.db}.
 
 @node  Antisuji moves
 @subsection Antisuji moves
@@ -247,8 +248,12 @@
 territory move reason. That move reason is added by the @samp{e}
 patterns in @file{patterns/patterns.db}. Similarly the @samp{E} patterns
 attempt to generate or mitigate a moyo, which is a region of influence
-not yet secure territory, yet valuable. Such a pattern sets the ``expand
-moyo'' move reason.
+not yet secure territory, yet valuable. There are also other patterns for
+reducing territory, invasions and making bariers (to defend before
+invasions) - they are in @file{patterns/influence.db} and
+@file{patterns/barriers.db}. These patterns set the ``expand moyo'',
+``expand territory'' and ``invasion'' move reasons. They also have
+influence on a move territorial valuation.
 
 @node Owl attack and defense
 @subsection Attacking and Defending Dragons
@@ -310,7 +315,8 @@
 as explained for example in @emph{The Endgame} by Ogawa
 and Davies.
 
-Moves are valued with respect to four different criteria. These are
+Moves are valued with respect to four different main criteria. These
+are
 
 @itemize @bullet
 @item territorial value
@@ -362,6 +368,7 @@
 * Minimum Value::                 Minimum value
 * Secondary Value::               Other, more indirect, gains from a move
 * Threats and Followup Value::    Valuation of attack and defense threats
+* Additional ko value::    Additional threat value for a ko fight
 @end menu
 
 @node Territorial value
@@ -384,6 +391,7 @@
 
 @node Strategical value
 @subsection Strategical Value
+@findex estimate_strategical_value
 
 Strategical defense or attack reasons are assigned to any move
 which matches a pattern of type @samp{a} or @samp{d}. These are
@@ -394,6 +402,8 @@
 to check its status or safety. This is done later, during
 the valuation phase.
 
+The whole algorithm is placed in @code{estimate_strategical_value}.
+
 @node Shape factor
 @subsection Shape Factor
 
@@ -451,6 +461,13 @@
 which we cannot legally take, then such a move becomes attractive as a ko
 threat and the full followup value is taken into account.
 
+@node Additional ko value
+@subsection Additional ko value
+
+Some moves give us additional threats and some give them to an opponent.
+In such situations we should give some bonus or penalty for creating ko
+threats. As for now only positive contribution is counted.
+
 @node End Game
 @section End Game
 
diff -N -r -u -X .ignore gnugo-copy/doc/patterns.texi gnugo/doc/patterns.texi
--- gnugo-copy/doc/patterns.texi	2007-02-18 18:41:23.531250000 +0100
+++ gnugo/doc/patterns.texi	2007-03-14 16:59:16.109375000 +0100
@@ -85,12 +85,6 @@
 Elements are not generated for @samp{?} markers, but they are not
 completely ignored - see below.
         
-The line beginning @samp{:} describes various attributes of the pattern, such
-as its symmetry and its class. Optionally, a function called a
-``helper'' can be provided to assist the matcher in deciding whether
-to accept move. Most patterns do not require a helper, and this field
-is filled with NULL.
-
 @findex shapes_callback
 The matcher in @file{matchpat.c} searches the board for places where this
 layout appears on the board, and the callback function
@@ -100,7 +94,7 @@
 After the pattern, there is some supplementary information in the format:
 @example
 
-  :trfno, classification, [values], helper_function
+  :trfno, attributes, [values], helper_function
 
 @end example
 
@@ -110,6 +104,10 @@
 represents the axis of symmetry. (E.g. @samp{|} means symmetrical about a
 vertical axis.)
 
+@code{helper_function} is a function that can be provided to assist the matcher
+in deciding whether to accept move. Most patterns do not require a helper,
+and this field is filled with NULL.
+
 The above pattern could equally well be written on the left edge:
 
 @example
@@ -127,11 +125,7 @@
 way, or for that matter, on the top or right edges, or in any
 of the four corners. As a matter of convention all the edge patterns 
 in @file{patterns.db} are written on the bottom edge or in the lower left
-corners. In the @file{patterns/} directory there is a program called
-@code{transpat} which can rotate or otherwise transpose patterns.
-This program is not built by default---if you think you need it,
-@code{make transpat} in the @file{patterns/} directory and
-consult the usage remarks at the beginning of @file{patterns/transpat.c}.
+corners.
 
 @node  Pattern Classification
 @section Pattern Attributes
@@ -415,6 +409,11 @@
 need to remove the stones we placed from the reading stack. This is done
 with the function @code{popgo()}.
 
+IMPORTANT: The macro @code{OFFSET} is not used anymore, because it has
+fixed coordinates and patterns can be now rotated randomly by DFA
+optimizer. All helpers that require usage of this macro have to be moved
+to autohelpers.
+
 @node  Autohelpers and Constraints
 @section Autohelpers and Constraints
 
@@ -566,7 +565,8 @@
 The autohelper functions are translated into C code by the program in
 @file{mkpat.c}. To see exactly how the functions are implemented,
 consult the autohelper function definitions in that file. Autohelper
-functions can be used in both constraint and action lines.
+functions can be used in both constraint and action lines. Here is
+a partial list of them:
 
 @example
 
@@ -1063,11 +1063,10 @@
 
 The patterns in @file{conn.db} are used for helping @code{make_dragons()}
 amalgamate worms into dragons and to some extent for modifying eye spaces.
-The patterns in this database use the classifications @samp{B}, 
-@samp{C}, and @samp{e}. @samp{B} patterns are used for finding cutting points,
+The patterns in this database use the classifications @samp{B} and 
+@samp{C}. @samp{B} patterns are used for finding cutting points,
 where amalgamation should not be performed, @samp{C} patterns are used for
-finding existing connections, over which amalgamation is to be done, and 
-@samp{e} patterns are used for modifying eye spaces and reevaluating lunches.
+finding existing connections, over which amalgamation is to be done.
 There are also some patterns without classification, which use action lines to
 have an impact. These are matched together with the @samp{C} patterns. Further
 details and examples can be found in @xref{Worms and Dragons}.
@@ -1181,26 +1180,10 @@
 @findex find_connections
 @quotation 
 Find explicit connection patterns and amalgamate the involved dragons.
-This goes through the connection database consulting patterns except those of
-type B, E or e. When such a function is found, the function
+This goes through the connection database consulting only patterns of type C.
+When such a function is found, the function
 @code{cut_connect_callback} is invoked.
 @end quotation
-@item void modify_eye_spaces1(void)
-@findex modify_eye_spaces1
-@quotation 
-Find explicit connection patterns and amalgamate the involved dragons.
-This goes through the connection database consulting only patterns
-of type E (@pxref{Connections Database}). When such a function is found, the
-function @code{cut_connect_callback} is invoked.  
-@end quotation
-@item void modify_eye_spaces1(void)
-@findex modify_eye_spaces1
-@quotation 
-Find explicit connection patterns and amalgamate the involved dragons.
-This goes through the connection database consulting only patterns
-of type e (@pxref{Connections Database}). When such a function is found, the
-function @code{cut_connect_callback} is invoked.  
-@end quotation
 @end itemize
 
 @node  Tuning
diff -N -r -u -X .ignore gnugo-copy/doc/reading.texi gnugo/doc/reading.texi
--- gnugo-copy/doc/reading.texi	2006-11-04 16:55:55.046875000 +0100
+++ gnugo/doc/reading.texi	2007-03-14 17:29:06.781250000 +0100
@@ -66,8 +66,8 @@
 
 The function @code{do_attack} and @code{do_find_defense} are wrappers
 themselves and call @code{attack1}, @code{attack2}, @code{attack3} or
-@code{attack4} resp.  @code{defend1}, @code{defend1}, @code{defend1}
-or @code{defend1} depending on the number of liberties.
+@code{attack4} resp.  @code{defend1}, @code{defend2}, @code{defend3}
+or @code{defend4} depending on the number of liberties.
 
 These are fine-tuned to generate and try out the moves in an efficient
 order. They generate a few moves themselves (mostly direct liberties
@@ -123,15 +123,6 @@
 3 liberties are considered, but branching is inhibited, so fewer
 variations are considered.
 
-%@findex small_semeai
-%Currently the reading code does not try to defend a string by
-%attacking a boundary string with more than two liberties. Because
-%of this restriction, it can make oversights. A symptom of this is
-%two adjacent strings, each having three or four liberties, each
-%classified as @code{DEAD}. To resolve such situations, a function
-%@code{small_semeai()} (in @file{engine/semeai.c}) looks for such
-%pairs of strings and corrects their classification.
-
 The @code{backfill_depth} is a similar variable with a default 12. Below
 this depth, GNU Go will try "backfilling" to capture stones.
 For example in this situation:
@@ -173,27 +164,26 @@
 be attacked, and if so, @code{*move} returns the attacking move,
 unless @code{*movei} is a null pointer. (Use null pointers if
 you are interested in the result of the attack but not the
-attacking move itself.) Returns @code{WIN}, if the attack succeeds,
-0 if it fails, and @code{KO_A} or @code{KO_B} if the result depends on ko
-@ref{Return Codes}.
+attacking move itself.) Returns a result code of the move
+@xref{Return Codes}.
 @end quotation
 @findex find_defense
 @item @code{find_defense(int str, int *move)}
 @quotation 
-Attempts to find a move that will save the string at @code{str}. It
-returns true if such a move is found, with @code{*move} the location
+Attempts to find a move that will save the string at @code{str}, and if
+so, @code{*move} returns the location
 of the saving move (unless @code{*move} is a null pointer). It is not
 checked that tenuki defends, so this may give an erroneous answer if
-@code{!attack(str)}.  Returns @code{KO_A} or @code{KO_B} if the
-result depends on ko @xref{Return Codes}. 
+@code{!attack(str)}.  Returns a result code of the move
+@xref{Return Codes}. 
 @end quotation
 @findex safe_move
 @item @code{safe_move(int str, int color)} :
 @quotation
 The function @code{safe_move(str, color)} checks whether a move at
 @code{str} is illegal or can immediately be captured. If @code{stackp==0}
-the result is cached. If the move only can be captured by a ko, it's
-considered safe. This may or may not be a good convention.
+the result is cached. Returns a result code of an attack on the placed
+stone.
 @end quotation
 @end itemize
 
@@ -388,7 +378,7 @@
 Some calculations can be safely saved from move to move. If the
 opponent's move is not close to our worm or dragon, we do not have to
 reconsider the life or death of that group on the next move. So
-the result is saved in a persistent cache. Persistent caches are used for
+the result is saved in a persistent cache. Persistent caches
 are used in the engine for several types of read results.
 
 @itemize @bullet
diff -N -r -u -X .ignore gnugo-copy/engine/board.c gnugo/engine/board.c
--- gnugo-copy/engine/board.c	2007-03-07 23:04:16.015625000 +0100
+++ gnugo/engine/board.c	2007-03-11 00:03:38.531250000 +0100
@@ -222,10 +222,10 @@
  */
 
 #define LIBERTY(pos) \
-  (board[pos] == EMPTY)
+  (!board[pos])
 
 #define UNMARKED_LIBERTY(pos) \
-  (board[pos] == EMPTY && ml[pos] != liberty_mark)
+  (!board[pos] && ml[pos] != liberty_mark)
 
 #define MARK_LIBERTY(pos) \
   ml[pos] = liberty_mark
@@ -683,7 +683,7 @@
   /* 1. The color must be BLACK or WHITE. */
   gg_assert(color == BLACK || color == WHITE);
  
-  if (pos != PASS_MOVE) {
+  if (pos) {
     /* 2. Unless pass, the move must be inside the board. */
     ASSERT_ON_BOARD1(pos);
     
@@ -691,7 +691,7 @@
     shadow[pos] = 1;
 
     /* 3. The location must be empty. */
-    if (board[pos] != EMPTY)
+    if (board[pos])
       return 0;
     
     /* 4. Test if the location is the ko point. */
@@ -838,14 +838,14 @@
    * undone stones */
   memcpy(&board_hash_stack[stackp], &board_hash, sizeof(board_hash));
 
-  if (board_ko_pos != NO_MOVE)
+  if (board_ko_pos)
     hashdata_invert_ko(&board_hash, board_ko_pos);
 
   board_ko_pos = NO_MOVE;
   
   stackp++;
 
-  if (pos != PASS_MOVE) {
+  if (pos) {
     PUSH_VALUE(black_captured);
     PUSH_VALUE(white_captured);
     do_play_move(pos, color);
@@ -864,7 +864,7 @@
   /* 1. The color must be BLACK or WHITE. */
   gg_assert(color == BLACK || color == WHITE);
  
-  if (pos != PASS_MOVE) {
+  if (pos) {
     /* 2. Unless pass, the move must be inside the board. */
     ASSERT_ON_BOARD1(pos);
     
@@ -872,7 +872,7 @@
     shadow[pos] = 1;
 
     /* 3. The location must be empty. */
-    if (board[pos] != EMPTY)
+    if (board[pos])
       return 0;
     
     /* 4. The location must not be the ko point, unless ignore_ko == 1. */
@@ -1049,7 +1049,7 @@
 {
   ASSERT1(stackp == 0, pos);
   ASSERT_ON_BOARD1(pos);
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
 
   board[pos] = color;
   hashdata_invert_stone(&board_hash, pos, color);
@@ -1094,14 +1094,14 @@
   gg_assert(hashdata_is_equal(oldkey, board_hash));
 #endif
 
-  if (board_ko_pos != NO_MOVE)
+  if (board_ko_pos)
     hashdata_invert_ko(&board_hash, board_ko_pos);
   board_ko_pos = NO_MOVE;
 
   /* If the move is a pass, we can skip some steps. */
-  if (pos != PASS_MOVE) {
+  if (pos) {
     ASSERT_ON_BOARD1(pos);
-    ASSERT1(board[pos] == EMPTY, pos);
+    ASSERT1(!board[pos], pos);
 
     /* Do play the move. */
     if (!is_suicide(pos, color))
@@ -1159,9 +1159,9 @@
 {
   ASSERT1(stackp == 0, pos);
   ASSERT1(color == WHITE || color == BLACK, pos);
-  ASSERT1(pos == PASS_MOVE || ON_BOARD1(pos), pos);
-  ASSERT1(pos == PASS_MOVE || board[pos] == EMPTY, pos);
-  ASSERT1(komaster == EMPTY && kom_pos == NO_MOVE, pos);
+  ASSERT1(!pos || ON_BOARD1(pos), pos);
+  ASSERT1(!pos || !board[pos], pos);
+  ASSERT1(!komaster && !kom_pos, pos);
 
   if (move_history_pointer >= MAX_MOVE_HISTORY) {
     /* The move history is full. We resolve this by collapsing the
@@ -1199,7 +1199,7 @@
   move_history_color[move_history_pointer] = color;
   move_history_pos[move_history_pointer] = pos;
   move_history_hash[move_history_pointer] = board_hash;
-  if (board_ko_pos != NO_MOVE)
+  if (board_ko_pos)
     hashdata_invert_ko(&move_history_hash[move_history_pointer], board_ko_pos);
   move_history_pointer++;
   
@@ -1251,7 +1251,7 @@
 int
 get_last_move()
 {
-  if (move_history_pointer == 0)
+  if (!move_history_pointer)
     return PASS_MOVE;
 
   return move_history_pos[move_history_pointer - 1];
@@ -1263,7 +1263,7 @@
 int
 get_last_player()
 {
-  if (move_history_pointer == 0)
+  if (!move_history_pointer)
     return EMPTY;
 
   return move_history_color[move_history_pointer - 1];
@@ -1282,7 +1282,7 @@
 int
 is_pass(int pos)
 {
-  return pos == PASS_MOVE;
+  return !pos;
 }
 
 
@@ -1300,14 +1300,14 @@
 is_legal(int pos, int color)
 {
   /* 0. A pass move is always legal. */
-  if (pos == PASS_MOVE)
+  if (!pos)
     return 1;
 
   /* 1. The move must be inside the board. */
   ASSERT_ON_BOARD1(pos);
 
   /* 2. The location must be empty. */
-  if (board[pos] != EMPTY) 
+  if (board[pos]) 
     return 0;
 
   /* 3. The location must not be the ko point. */
@@ -1357,33 +1357,33 @@
   int checked_pos;
   int stone;
   ASSERT_ON_BOARD1(pos);
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
 
   /* Check for suicide. */
   checked_pos = SOUTH(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY
+  if (!stone
       || (ON_BOARD(checked_pos)
           && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
 
   checked_pos = WEST(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY
+  if (!stone
       || (ON_BOARD(checked_pos)
           && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
 
   checked_pos = NORTH(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY
+  if (!stone
       || (ON_BOARD(checked_pos)
           && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
 
   checked_pos = EAST(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY
+  if (!stone
       || (ON_BOARD(checked_pos)
           && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1))))
     return 0;
@@ -1400,7 +1400,7 @@
 is_illegal_ko_capture(int pos, int color)
 {
   ASSERT_ON_BOARD1(pos);
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
 
   return (pos == board_ko_pos
     /*    The ko position is guaranteed to have all neighbors of the
@@ -1426,14 +1426,14 @@
   gg_assert(stackp == 0);
 
   /* 1. A pass move is always legal, no matter what. */
-  if (pos == PASS_MOVE)
+  if (!pos)
     return 1;
 
   /* 2. The move must be inside the board. */
   ASSERT_ON_BOARD1(pos);
 
   /* 3. The location must be empty. */
-  if (board[pos] != EMPTY) 
+  if (board[pos]) 
     return 0;
 
   /* 4. Simple ko repetition is only allowed if no ko rule is in use.
@@ -1612,7 +1612,7 @@
     *is_conditional_ko = 1;
 
     /* Conditional ko capture, set komaster parameters (1b and 5c). */
-    if (komaster == EMPTY || komaster == WEAK_KO) {
+    if (!komaster || komaster == WEAK_KO) {
       set_new_komaster(color);
       set_new_kom_pos(kpos);
       return 1;
@@ -1631,7 +1631,7 @@
 	  || (komaster == GRAY_WHITE && color == WHITE)
 	  || (komaster == GRAY_BLACK && color == BLACK))
 	 && (board[kom_pos] == color
-	     || (board[kom_pos] == EMPTY
+	     || (!board[kom_pos]
 	         && is_suicide(kom_pos, OTHER_COLOR(color))))) {
       set_new_komaster(EMPTY);
       set_new_kom_pos(NO_MOVE);
@@ -1660,7 +1660,7 @@
     /* 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 (1a and 5b).
      */
-    if (previous_board_ko_pos != NO_MOVE) {
+    if (previous_board_ko_pos) {
       set_new_komaster(WEAK_KO);
       set_new_kom_pos(previous_board_ko_pos);
     }
@@ -1724,14 +1724,14 @@
 int
 are_neighbors(int pos1, int pos2)
 {
-  if (board[pos1] == EMPTY) {
-    if (board[pos2] == EMPTY)
+  if (!board[pos1]) {
+    if (!board[pos2])
       return (gg_abs(pos1 - pos2) == NS || gg_abs(pos1 - pos2) == WE);
     else
       return neighbor_of_string(pos1, pos2);
   }
   else {
-    if (board[pos2] == EMPTY)
+    if (!board[pos2])
       return neighbor_of_string(pos2, pos1);
     else
       return adjacent_strings(pos1, pos2);
@@ -1768,7 +1768,7 @@
   int str_nr;
 
   ASSERT1(IS_STONE(board[str_pos]), str_pos);
-  ASSERT1(libs != NULL, str_pos);
+  ASSERT1(libs, str_pos);
 
   /* We already have the list of liberties and only need to copy it to
    * libs[].
@@ -1863,7 +1863,7 @@
   int checked_pos;
   int str_nr;
 
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
   ASSERT1(IS_STONE(color), pos);
 
   /* Find neighboring strings of the same color. If there are more than two of
@@ -2045,7 +2045,7 @@
 
   struct board_cache_entry *entry = &approxlib_cache[pos][color - WHITE];
 
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
   ASSERT1(IS_STONE(color), pos);
 
   if (!libs) {
@@ -2086,7 +2086,7 @@
 
 #else /* not USE_BOARD_CACHES */
 
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
   ASSERT1(IS_STONE(color), pos);
 
   if (!libs) {
@@ -2130,9 +2130,9 @@
   MARK_LIBERTY(pos);
 
   checked_pos = SOUTH(pos);
-  if (board[checked_pos] == EMPTY) {
+  if (!board[checked_pos]) {
     if (ml[checked_pos] != liberty_mark) {
-      if (libs != NULL)
+      if (libs)
         libs[liberties] = checked_pos;
       liberties++;
       /* Stop counting if we reach maxlib. */
@@ -2147,7 +2147,7 @@
     last_lib = cur_lib + string[str_nr].liberties;
     for (; cur_lib < last_lib; cur_lib++) {
       if (UNMARKED_LIBERTY(*cur_lib)) {
-	if (libs != NULL)
+	if (libs)
 	  libs[liberties] = *cur_lib;
 	liberties++;
 	if (liberties >= maxlib)
@@ -2158,9 +2158,9 @@
   }
   
   checked_pos = WEST(pos);
-  if (board[checked_pos] == EMPTY) {
+  if (!board[checked_pos]) {
     if (ml[checked_pos] != liberty_mark) {
-      if (libs != NULL)
+      if (libs)
         libs[liberties] = checked_pos;
       liberties++;
       /* Stop counting if we reach maxlib. */
@@ -2175,7 +2175,7 @@
     last_lib = cur_lib + string[str_nr].liberties;
     for (; cur_lib < last_lib; cur_lib++) {
       if (UNMARKED_LIBERTY(*cur_lib)) {
-	if (libs != NULL)
+	if (libs)
 	  libs[liberties] = *cur_lib;
 	liberties++;
 	if (liberties >= maxlib)
@@ -2186,9 +2186,9 @@
   }
   
   checked_pos = NORTH(pos);
-  if (board[checked_pos] == EMPTY) {
+  if (!board[checked_pos]) {
     if (ml[checked_pos] != liberty_mark) {
-      if (libs != NULL)
+      if (libs)
         libs[liberties] = checked_pos;
       liberties++;
       /* Stop counting if we reach maxlib. */
@@ -2203,7 +2203,7 @@
     last_lib = cur_lib + string[str_nr].liberties;
     for (; cur_lib < last_lib; cur_lib++) {
       if (UNMARKED_LIBERTY(*cur_lib)) {
-	if (libs != NULL)
+	if (libs)
 	  libs[liberties] = *cur_lib;
 	liberties++;
 	if (liberties >= maxlib)
@@ -2214,9 +2214,9 @@
   }
 
   checked_pos = EAST(pos);
-  if (board[checked_pos] == EMPTY) {
+  if (!board[checked_pos]) {
     if (ml[checked_pos] != liberty_mark) {
-      if (libs != NULL)
+      if (libs)
         libs[liberties] = checked_pos;
       liberties++;
 /* Unneeded since we're about to leave. */
@@ -2233,7 +2233,7 @@
     last_lib = cur_lib + string[str_nr].liberties;
     for (; cur_lib < last_lib; cur_lib++) {
       if (UNMARKED_LIBERTY(*cur_lib)) {
-	if (libs != NULL)
+	if (libs)
 	  libs[liberties] = *cur_lib;
 	liberties++;
 	if (liberties >= maxlib)
@@ -2275,7 +2275,7 @@
 
   for (delta_o = delta; delta_o < last_delta_4; delta_o++) {
     checked_pos = pos + *delta_o;
-    if (board[checked_pos] == EMPTY) {
+    if (!board[checked_pos]) {
       if (ml[checked_pos] != liberty_mark) {
         if (libs)
           libs[liberties] = checked_pos;
@@ -2359,7 +2359,7 @@
 
   struct board_cache_entry *entry = &accuratelib_cache[pos][color - WHITE];
 
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
   ASSERT1(IS_STONE(color), pos);
 
   if (!libs) {
@@ -2396,7 +2396,7 @@
 
 #else /* not USE_BOARD_CACHES */
 
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
   ASSERT1(IS_STONE(color), pos);
 
   if (!libs) {
@@ -2434,7 +2434,7 @@
 
   for (act_delta = delta; act_delta < last_delta_4; act_delta++) {
     int checked_pos = pos + *act_delta;
-    if (board[checked_pos] == EMPTY) {
+    if (!board[checked_pos]) {
       if (ml[checked_pos] != liberty_mark) {
         /* A trivial liberty */
         if (libs)
@@ -2609,8 +2609,8 @@
 int
 count_common_libs(int str1_pos, int str2_pos)
 {
-  int all_libs1[MAXLIBS], *libs1;
-  int *last_lib;
+  static int all_libs1[MAXLIBS];
+  int *last_lib, *libs1;
   int liberties1, liberties2;
   int str1_nr, str2_nr;
   int commonlibs = 0;
@@ -2683,8 +2683,8 @@
 int
 find_common_libs(int str1_pos, int str2_pos, int maxlib, int *libs)
 {
-  int all_libs1[MAXLIBS], *libs1;
-  int *last_lib;
+  static int all_libs1[MAXLIBS];
+  int *last_lib, *libs1;
   int liberties1, liberties2;
   int str1_nr, str2_nr;
   int commonlibs = 0;
@@ -2694,7 +2694,7 @@
   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);
+  ASSERT1(libs, str1_pos);
 
   str1_nr = string_number[str1_pos];
   str2_nr = string_number[str2_pos];
@@ -2759,8 +2759,8 @@
 int
 have_common_lib(int str1_pos, int str2_pos, int *lib)
 {
-  int all_libs1[MAXLIBS], *libs1;
-  int *last_lib;
+  static int all_libs1[MAXLIBS];
+  int *last_lib, *libs1;
   int liberties1, liberties2;
   int str1_nr, str2_nr;
   int color;
@@ -2984,7 +2984,7 @@
 extended_chainlinks(int str_pos, int adj[MAXCHAIN], int both_colors)
 {
   int *cur_neighbor, *last_neigbor;
-  int libs[MAXLIBS];
+  static int libs[MAXLIBS];
   int *cur_lib, *last_lib;
   int checked_pos;
   int color;
@@ -3104,7 +3104,7 @@
   int liberties;
   
   ASSERT_ON_BOARD1(pos);
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
   ASSERT1(IS_STONE(color), pos);
 
   /* 1. Try first to solve the problem without much work. */
@@ -3112,7 +3112,7 @@
   
   checked_pos = SOUTH(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY)
+  if (!stone)
     trivial_liberties++;
   else if (stone == color) {
     liberties = LIBERTIES(string_number[checked_pos]);
@@ -3131,7 +3131,7 @@
 
   checked_pos = WEST(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY)
+  if (!stone)
     trivial_liberties++;
   else if (stone == color) {
     liberties = LIBERTIES(string_number[checked_pos]);
@@ -3150,7 +3150,7 @@
 
   checked_pos = NORTH(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY)
+  if (!stone)
     trivial_liberties++;
   else if (stone == color) {
     liberties = LIBERTIES(string_number[checked_pos]);
@@ -3169,7 +3169,7 @@
 
   checked_pos = EAST(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY)
+  if (!stone)
     trivial_liberties++;
   else if (stone == color) {
     liberties = LIBERTIES(string_number[checked_pos]);
@@ -3198,7 +3198,7 @@
   if ((far_liberties > 0) + captures >= 2)
     return 0;
 
-  if (captures == 0 && far_liberties + trivial_liberties <= 1)
+  if (!captures && far_liberties + trivial_liberties <= 1)
     return 1;
 
   /* 2. It was not so easy.  We use accuratelib() in this case. */
@@ -3253,25 +3253,25 @@
 
   ASSERT_ON_BOARD1(pos);
   ASSERT_ON_BOARD1(str_pos);
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
   ASSERT1(IS_STONE(board[str_pos]), str_pos);
 
   color = board[str_pos];
   str_nr = string_number[str_pos];
 
-  if (board[SOUTH(pos)] == EMPTY
+  if (!board[SOUTH(pos)]
       && NEIGHBOR_OF_STRING(SOUTH(pos), str_nr, color))
     return 1;
 
-  if (board[EAST(pos)] == EMPTY
+  if (!board[EAST(pos)]
       && NEIGHBOR_OF_STRING(EAST(pos), str_nr, color))
     return 1;
 
-  if (board[NORTH(pos)] == EMPTY
+  if (!board[NORTH(pos)]
       && NEIGHBOR_OF_STRING(NORTH(pos), str_nr, color))
     return 1;
 
-  if (board[WEST(pos)] == EMPTY
+  if (!board[WEST(pos)]
       && NEIGHBOR_OF_STRING(WEST(pos), str_nr, color))
     return 1;
 
@@ -3490,7 +3490,7 @@
 {
   ASSERT_ON_BOARD1(pos);
 
-  if (board[pos] == EMPTY) {
+  if (!board[pos]) {
     int color;
     if (ON_BOARD(SOUTH(pos)))
       color = board[SOUTH(pos)];
@@ -3533,12 +3533,12 @@
 
   this_board_hash = board_hash;
 
-  if (board_ko_pos != NO_MOVE)
+  if (board_ko_pos)
     hashdata_invert_ko(&this_board_hash, board_ko_pos);
 
   really_do_trymove(pos, color);
   new_board_hash = board_hash;
-  if (board_ko_pos != NO_MOVE)
+  if (board_ko_pos)
     hashdata_invert_ko(&new_board_hash, board_ko_pos);
   undo_trymove();
 
@@ -3564,7 +3564,7 @@
 {
   int other = OTHER_COLOR(color);
 
-  ASSERT1(board[pos] == EMPTY, pos);
+  ASSERT1(!board[pos], pos);
 
   if (board[SOUTH(pos)] == other && LIBERTIES(string_number[SOUTH(pos)]) == 1)
     return 1;
@@ -3754,7 +3754,7 @@
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
     if (!ON_BOARD(pos))
       continue;
-    if (board[pos] == EMPTY)
+    if (!board[pos])
       fprintf(stderr, " . ");
     else
       fprintf(stderr, "%2d ", string_number[pos]);
@@ -3766,7 +3766,7 @@
   }
 
   for (s = 0; s < next_string; s++) {
-    if (board[string[s].origin] == EMPTY)
+    if (!board[string[s].origin])
       continue;
     
     gprintf("%o%d %s %1m size %d, %d liberties, %d neighbors\n", s,
@@ -3858,7 +3858,7 @@
      * already visited liberties and neighbors.
      */
     checked_pos = SOUTH(pos);
-    if (board[checked_pos] == EMPTY) {
+    if (!board[checked_pos]) {
       if (ml[checked_pos] != liberty_mark) {
         ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
       }
@@ -3872,7 +3872,7 @@
     }
     
     checked_pos = WEST(pos);
-    if (board[checked_pos] == EMPTY) {
+    if (!board[checked_pos]) {
       if (ml[checked_pos] != liberty_mark) {
         ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
       }
@@ -3886,7 +3886,7 @@
     }
     
     checked_pos = NORTH(pos);
-    if (board[checked_pos] == EMPTY) {
+    if (!board[checked_pos]) {
       if (ml[checked_pos] != liberty_mark) {
         ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
       }
@@ -3900,7 +3900,7 @@
     }
     
     checked_pos = EAST(pos);
-    if (board[checked_pos] == EMPTY) {
+    if (!board[checked_pos]) {
       if (ml[checked_pos] != liberty_mark) {
         ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
       }
@@ -4481,7 +4481,7 @@
    */
   checked_pos = SOUTH(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY) {
+  if (!stone) {
     if (ml[checked_pos] != liberty_mark)
       ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
   }
@@ -4501,7 +4501,7 @@
 
   checked_pos = WEST(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY) {
+  if (!stone) {
     if (ml[checked_pos] != liberty_mark)
       ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
   }
@@ -4521,7 +4521,7 @@
   
   checked_pos = NORTH(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY) {
+  if (!stone) {
     if (ml[checked_pos] != liberty_mark)
       ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
   }
@@ -4541,7 +4541,7 @@
   
   checked_pos = EAST(pos);
   stone = board[checked_pos];
-  if (stone == EMPTY) {
+  if (!stone) {
     if (ml[checked_pos] != liberty_mark)
 #if 0
       ADD_AND_MARK_LIBERTY(str_nr, checked_pos);
@@ -4709,7 +4709,7 @@
   }
 
   /* Choose strategy depending on the number of friendly neighbors. */
-  if (neighbor_allies == 0)
+  if (!neighbor_allies)
     create_new_string(pos, color);
   else if (neighbor_allies == 1) {
     gg_assert(extend_nr >= 0);
@@ -4732,7 +4732,7 @@
   if (string[str_nr].liberties == 1
       && captured_stones == 1) {
     /* In case of a double ko: clear old ko position first. */
-    if (board_ko_pos != NO_MOVE)
+    if (board_ko_pos)
       hashdata_invert_ko(&board_hash, board_ko_pos);
     board_ko_pos = string_libs[str_nr].list[0];
     hashdata_invert_ko(&board_hash, board_ko_pos);
@@ -4772,7 +4772,7 @@
     pos = move + delta[k];
     if (!ON_BOARD(pos))
       (*number_edges)++;
-    else if (board[pos] == EMPTY)
+    else if (!board[pos])
       (*number_open)++;
     else {
       int s = string_number[pos];
@@ -4808,7 +4808,7 @@
 #define code1(pos, stone) \
   if (stone == GRAY) \
     (*number_edges)++; \
-  else if (stone == EMPTY) \
+  else if (!stone) \
     (*number_open)++; \
   else { \
     int str_nr = string_number[pos]; \
diff -N -r -u -X .ignore gnugo-copy/engine/board.vcproj gnugo/engine/board.vcproj
--- gnugo-copy/engine/board.vcproj	2007-02-06 14:39:49.953125000 +0100
+++ gnugo/engine/board.vcproj	2007-03-09 00:36:16.578125000 +0100
@@ -200,10 +200,6 @@
 				</FileConfiguration>
 			</File>
 			<File
-				RelativePath="board.h"
-				>
-			</File>
-			<File
 				RelativePath="boardlib.c"
 				>
 				<FileConfiguration
@@ -341,6 +337,14 @@
 			Name="Header Files"
 			Filter="h;hpp;hxx;hm;inl"
 			>
+			<File
+				RelativePath="board.h"
+				>
+			</File>
+			<File
+				RelativePath="..\config.h"
+				>
+			</File>
 		</Filter>
 	</Files>
 	<Globals>
diff -N -r -u -X .ignore gnugo-copy/engine/engine.vcproj gnugo/engine/engine.vcproj
--- gnugo-copy/engine/engine.vcproj	2007-02-06 14:39:50.515625000 +0100
+++ gnugo/engine/engine.vcproj	2007-03-09 00:36:16.734375000 +0100
@@ -986,6 +986,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\config.h"
+				>
+			</File>
+			<File
 				RelativePath="gnugo.h"
 				>
 			</File>
diff -N -r -u -X .ignore gnugo-copy/engine/genmove.c gnugo/engine/genmove.c
--- gnugo-copy/engine/genmove.c	2007-01-24 17:49:31.812500000 +0100
+++ gnugo/engine/genmove.c	2007-03-12 13:16:48.406250000 +0100
@@ -167,53 +167,57 @@
     return;
   }
 
-  if (stones_on_board(BLACK | WHITE) != 0) {
-    if (NEEDS_UPDATE(initial_influence_examined))
-      compute_worm_influence();
+  if (!stones_on_board(BLACK | WHITE)) {
+    initialize_dragon_data();
+    compute_scores(chinese_rules || aftermath_play);
 
-    if (how_much == EXAMINE_INITIAL_INFLUENCE) {
+#ifndef GG_TURN_OFF_TRACES
+    verbose = save_verbose;
+#endif
+
+    gg_assert(test_gray_border() < 0);
 
 #ifndef GG_TURN_OFF_TRACES
-      verbose = save_verbose;
+    if (printworms)
+      show_dragons();
 #endif
 
-      gg_assert(test_gray_border() < 0);
-      return;
-    }
+    return;
+  }
+
+  if (NEEDS_UPDATE(initial_influence_examined))
+    compute_worm_influence();
 
-    if (how_much == EXAMINE_DRAGONS_WITHOUT_OWL) {
-      if (NEEDS_UPDATE(dragons_examined_without_owl))
-	make_dragons(1);
+  if (how_much == EXAMINE_INITIAL_INFLUENCE) {
 
 #ifndef GG_TURN_OFF_TRACES
-      verbose = save_verbose;
+    verbose = save_verbose;
 #endif
 
-      gg_assert(test_gray_border() < 0);
-      return;
-    }
-    
-    if (NEEDS_UPDATE(dragons_examined)) {
-      make_dragons(0);
-      compute_scores(chinese_rules || aftermath_play);
-      /* We have automatically done a partial dragon analysis as well. */
-      dragons_examined_without_owl = position_number;
-    }
-    if (how_much == EXAMINE_DRAGONS) {
+    gg_assert(test_gray_border() < 0);
+    return;
+  }
+
+  if (how_much == EXAMINE_DRAGONS_WITHOUT_OWL) {
+    if (NEEDS_UPDATE(dragons_examined_without_owl))
+      make_dragons(1);
 
 #ifndef GG_TURN_OFF_TRACES
-      verbose = save_verbose;
+    verbose = save_verbose;
 #endif
 
-      gg_assert(test_gray_border() < 0);
-      return;
-    }
+    gg_assert(test_gray_border() < 0);
+    return;
   }
-  else if (how_much == EXAMINE_INITIAL_INFLUENCE
-	   || how_much == EXAMINE_DRAGONS
-	   || how_much == EXAMINE_ALL) {
-    initialize_dragon_data();
+    
+  if (NEEDS_UPDATE(dragons_examined)) {
+    make_dragons(0);
     compute_scores(chinese_rules || aftermath_play);
+    /* We have automatically done a partial dragon analysis as well. */
+    dragons_examined_without_owl = position_number;
+  }
+
+  if (how_much == EXAMINE_DRAGONS) {
 
 #ifndef GG_TURN_OFF_TRACES
     verbose = save_verbose;
diff -N -r -u -X .ignore gnugo-copy/engine/influence.c gnugo/engine/influence.c
--- gnugo-copy/engine/influence.c	2007-02-07 19:31:13.750000000 +0100
+++ gnugo/engine/influence.c	2007-03-12 11:42:17.718750000 +0100
@@ -1152,7 +1152,7 @@
  * the -m command line option).
  *
  * It is assumed that color is in turn to move. (This affects the
- * barrier patterns (class A, D) and intrusions (class B)). Color
+ * barrier patterns (class A, D) and intrusions (class B)).
  */
 
 void
diff -N -r -u -X .ignore gnugo-copy/engine/liberty.h gnugo/engine/liberty.h
--- gnugo-copy/engine/liberty.h	2007-03-06 14:59:14.187500000 +0100
+++ gnugo/engine/liberty.h	2007-03-14 15:51:13.640625000 +0100
@@ -832,10 +832,9 @@
 
   /* The following arrays keeps track of up to MAX_TACTICAL_POINTS
    * different attack, defense, attack threat, and defense threat
-   * points with corresponding result codes. (0 = loss, 1 = bad ko, 2
-   * = good ko, 3 = win). The arrays are guaranteed to be sorted with
-   * respect to the codes so that the first element contains the best
-   * result. Checked and discarded moves are stored, too.
+   * points with corresponding result codes. The arrays are guaranteed to
+   * be sorted with respect to the codes so that the first element contains
+   * the best result. Checked and discarded moves are stored, too.
    */
   int attack_points[MAX_TACTICAL_POINTS];
   int attack_codes[MAX_TACTICAL_POINTS];
@@ -924,12 +923,12 @@
   enum dragon_status owl_threat_status; /* CAN_THREATEN_ATTACK/DEFENSE       */
   enum dragon_status owl_status; /* (ALIVE, DEAD, UNKNOWN, CRITICAL, UNCHECKED)    */
   int owl_attack_point;    /* vital point for attack                         */
-  int owl_attack_code;     /* ko result code                                 */
+  int owl_attack_code;     /* result code				     */
   int owl_attack_certain;  /* 0 if owl reading node limit is reached         */
   int owl_attack_node_count;
   int owl_second_attack_point;/* if attacker gets both attack points, wins   */
   int owl_defense_point;   /* vital point for defense                        */
-  int owl_defense_code;    /* ko result code                                 */
+  int owl_defense_code;    /* result code                                    */
   int owl_defense_certain; /* 0 if owl reading node limit is reached         */
   int owl_second_defense_point;/* if defender gets both attack points, wins  */
   int owl_attack_kworm;    /* only valid when owl_attack_code is GAIN        */
diff -N -r -u -X .ignore gnugo-copy/engine/worm.c gnugo/engine/worm.c
--- gnugo-copy/engine/worm.c	2007-03-08 13:36:55.250000000 +0100
+++ gnugo/engine/worm.c	2007-03-14 13:12:20.250000000 +0100
@@ -39,15 +39,15 @@
 static int find_lunch(int str, int *lunch);
 static void propagate_worm2(int str);
 static int genus(int str);
-static void markcomponent(int str, int pos, int mg[BOARDMAX]);
+static void markcomponent(int pos, signed char mg[BOARDMAX]);
 static int examine_cavity(int pos, int *edge);
 static void cavity_recurse(int pos, int mx[BOARDMAX], 
 			   int *border_color, int *edge, int str);
 static void ping_cave(int str, int *result1,  int *result2,
 		      int *result3, int *result4);
 static void ping_recurse(int pos, int *counter, 
-			 int mx[BOARDMAX], 
-			 int mr[BOARDMAX], int color);
+			 int mx[BOARDSIZE], 
+			 int mr[BOARDSIZE], int color, int other);
 static int touching(int pos, int color);
 static void find_attack_patterns(void);
 static void attack_callback(int anchor, int color,
@@ -434,6 +434,7 @@
    *  - the genus must be zero 
    *  - there can be no second order liberties
    *  - it can't be a cutstone
+   *  - there is no neighboring attackable worm (lunch)
    *  - if it is removed from the board, the remaining cavity has
    *    border color the opposite color of the string 
    *  - it contains at most two edge vertices.
@@ -1296,11 +1297,10 @@
  * to the string by placing n stones of the same color on the board, 
  * but no fewer. The path of connection may pass through an intervening group
  * of the same color. The stones placed at distance >1 may not touch a
- * group of the opposite color. At the edge, also diagonal neighbors
- * count as touching. The path may also not pass through a liberty at distance
- * 1 if that liberty is flanked by two stones of the opposing color. This
- * reflects the fact that the O stone is blocked from expansion to the
- * left by the two X stones in the following situation:
+ * group of the opposite color. The path may also not pass through a liberty
+ * at distance 1 if that liberty is flanked by two stones of the opposing
+ * color. This reflects the fact that the O stone is blocked from expansion
+ * to the left by the two X stones in the following situation:
  * 
  *          X.
  *          .O
@@ -1317,10 +1317,10 @@
 ping_cave(int str, int *lib1, int *lib2, int *lib3, int *lib4)
 {
   int pos;
-  int k;
   int libs[MAXLIBS];
-  int mrc[BOARDMAX];
-  int mse[BOARDMAX];
+  int *cur_lib, *last_lib;
+  int mrc[BOARDSIZE];
+  int mse[BOARDSIZE];
   int color = board[str];
   int other = OTHER_COLOR(color);
 
@@ -1328,16 +1328,17 @@
 
   /* Find and mark the first order liberties. */
   *lib1 = findlib(str, MAXLIBS, libs);
-  for (k = 0; k < *lib1; k++)
-    mse[libs[k]] = 1;
+  cur_lib = libs;
+  last_lib = libs + *lib1;
+  for (; cur_lib < last_lib; cur_lib++)
+    mse[*cur_lib] = 1;
 
   /* Reset mse at liberties which are flanked by two stones of the
    * opposite color, or one stone and the edge.
    */
 
   for (pos = BOARDMIN; pos < BOARDMAX; pos++)
-    if (ON_BOARD(pos)
-	&& mse[pos]
+    if (mse[pos]
 	&& (((      !ON_BOARD(SOUTH(pos)) || board[SOUTH(pos)] == other)
 	     && (   !ON_BOARD(NORTH(pos)) || board[NORTH(pos)] == other))
 	    || ((   !ON_BOARD(WEST(pos))  || board[WEST(pos)]  == other)
@@ -1346,34 +1347,37 @@
   
   *lib2 = 0;
   memset(mrc, 0, sizeof(mrc));
-  ping_recurse(str, lib2, mse, mrc, color);
+  ping_recurse(str, lib2, mse, mrc, color, other);
 
   *lib3 = 0;
   memset(mrc, 0, sizeof(mrc));
-  ping_recurse(str, lib3, mse, mrc, color);
+  ping_recurse(str, lib3, mse, mrc, color, other);
 
   *lib4 = 0;
   memset(mrc, 0, sizeof(mrc));
-  ping_recurse(str, lib4, mse, mrc, color);
+  ping_recurse(str, lib4, mse, mrc, color, other);
 }
 
 
-/* recursive function called by ping_cave */
+/* recursive function called by ping_cave
+ * mx - marked liberties of any order
+ * mr - marked checked positions */
 
 static void 
 ping_recurse(int pos, int *counter,
-	     int mx[BOARDMAX], int mr[BOARDMAX],
-	     int color)
+	     int mx[BOARDSIZE], int mr[BOARDSIZE],
+	     int color, int other)
 {
-  int k;
+  int apos;
+  const int *cur_delta;
   mr[pos] = 1;
 
-  for (k = 0; k < 4; k++) {
-    int apos = pos + delta[k];
-    if (board[apos] == EMPTY
-	&& mx[apos] == 0
-	&& mr[apos] == 0
-	&& !touching(apos, OTHER_COLOR(color))) {
+  for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) {
+    apos = pos + *cur_delta;
+    if (!board[apos]
+	&& !mr[apos]
+	&& !mx[apos]
+	&& !touching(apos, other)) {
       (*counter)++;
       mr[apos] = 1;
       mx[apos] = 1;
@@ -1381,13 +1385,12 @@
   }
   
   if (!is_ko_point(pos)) {
-    for (k = 0; k < 4; k++) {
-      int apos = pos + delta[k];
-      if (ON_BOARD(apos)
-	  && mr[apos] == 0
-	  && (mx[apos] == 1
+    for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) {
+      apos = pos + *cur_delta;
+      if (!mr[apos]
+	  && (mx[apos]
 	      || board[apos] == color))
-	ping_recurse(apos, counter, mx, mr, color);
+	ping_recurse(apos, counter, mx, mr, color, other);
     }
   }
 }
@@ -1416,15 +1419,16 @@
 genus(int str)
 {
   int pos;
-  int mg[BOARDMAX];
+  signed char mg[BOARDMAX];
   int gen = -1;
 
   memset(mg, 0, sizeof(mg));
+  mark_string(str, mg, 1);
+
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (ON_BOARD(pos)
-	&& !mg[pos]
-	&& (board[pos] == EMPTY || !is_same_worm(pos, str))) {
-      markcomponent(str, pos, mg);
+    if (!mg[pos]
+	&& ON_BOARD(pos)) {
+      markcomponent(pos, mg);
       gen++;
     }
   }
@@ -1434,20 +1438,19 @@
 
 
 /* This recursive function marks the component at (pos) of 
- * the complement of the string with origin (str)
+ * the complement of the string.
  */
 
 static void 
-markcomponent(int str, int pos, int mg[BOARDMAX])
+markcomponent(int pos, signed char mg[BOARDMAX])
 {
-  int k;
+  const int *cur_delta;
   mg[pos] = 1;
-  for (k = 0; k < 4; k++) {
-    int apos = pos + delta[k];
-    if (ON_BOARD(apos)
-	&& mg[apos] == 0
-	&& (board[apos] == EMPTY || !is_same_worm(apos, str)))
-      markcomponent(str, apos, mg);
+  for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) {
+    int apos = pos + *cur_delta;
+    if (!mg[apos]
+	&& ON_BOARD(apos))
+      markcomponent(apos, mg);
   }
 }
 
@@ -1468,7 +1471,7 @@
 {
   int border_color = EMPTY;
   int ml[BOARDMAX];
-  int origin = NO_MOVE;
+  int origin;
   
   ASSERT_ON_BOARD1(pos);
   gg_assert(edge != NULL);
@@ -1479,10 +1482,12 @@
 
   if (IS_STONE(board[pos]))
     origin = find_origin(pos);
+  else
+    origin = NO_MOVE;
   
   cavity_recurse(pos, ml, &border_color, edge, origin);
 
-  if (border_color != EMPTY)
+  if (border_color)
     return border_color;
 
   /* We should have returned now, unless the board is completely empty.
@@ -1491,11 +1496,10 @@
    * Notice that the board appears completely empty if there's only a
    * single string and pos points to it.
    */
-  gg_assert(border_color == EMPTY
-	    && ((pos == NO_MOVE
-		 && stones_on_board(BLACK | WHITE) == 0)
-		|| (pos != NO_MOVE
-		    && stones_on_board(BLACK | WHITE) == countstones(pos))));
+  gg_assert((origin == NO_MOVE
+	     && stones_on_board(BLACK | WHITE) == 0)
+	    || (origin != NO_MOVE
+		&& stones_on_board(BLACK | WHITE) == countstones(pos)));
   
   return GRAY;
 }
@@ -1522,34 +1526,23 @@
 cavity_recurse(int pos, int mx[BOARDMAX], 
 	       int *border_color, int *edge, int str)
 {
-  int k;
-  ASSERT1(mx[pos] == 0, pos);
+  const int *cur_delta;
+  ASSERT1(!mx[pos], pos);
 
   mx[pos] = 1;
 
-  if (is_edge_vertex(pos) && board[pos] == EMPTY) 
+  if (is_edge_vertex(pos) && !board[pos]) 
     (*edge)++;
 
   /* Loop over the four neighbors. */
-  for (k = 0; k < 4; k++) {
-    int apos = pos + delta[k];
+  for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) {
+    int apos = pos + *cur_delta;
     if (ON_BOARD(apos) && !mx[apos]) {
-      int neighbor_empty = 0;
-      
-      if (board[apos] == EMPTY)
-	neighbor_empty = 1;
-      else {
-	/* Count the neighbor as empty if it is part of the (ai, aj) string. */
-	if (str == find_origin(apos))
-	  neighbor_empty = 1;
-	else
-	  neighbor_empty = 0;
-      }
-      
-      if (!neighbor_empty)
-	*border_color |= board[apos];
-      else
+      /* Count the neighbor as empty if it is part of the (ai, aj) string. */
+      if (!board[apos] || str == find_origin(apos))
 	cavity_recurse(apos, mx, border_color, edge, str);
+      else
+	*border_color |= board[apos];
     }
   }
 }
diff -N -r -u -X .ignore gnugo-copy/interface/gnugo.vcproj gnugo/interface/gnugo.vcproj
--- gnugo-copy/interface/gnugo.vcproj	2007-02-06 14:39:50.203125000 +0100
+++ gnugo/interface/gnugo.vcproj	2007-03-09 00:36:16.765625000 +0100
@@ -400,6 +400,10 @@
 			Filter="h;hpp;hxx;hm;inl"
 			>
 			<File
+				RelativePath="..\config.h"
+				>
+			</File>
+			<File
 				RelativePath=".\interface.h"
 				>
 			</File>
diff -N -r -u -X .ignore gnugo-copy/makevcdist.pl gnugo/makevcdist.pl
--- gnugo-copy/makevcdist.pl	2007-01-22 14:36:53.171875000 +0100
+++ gnugo/makevcdist.pl	2007-03-09 00:40:52.593750000 +0100
@@ -17,6 +17,7 @@
    EXPERIMENTAL_SEMEAI => 1,
    EXPERIMENTAL_OWL_EXT => 0,
    EXPERIMENTAL_CONNECTIONS => 1,
+   FINAL_RELEASE => 0,
    LARGE_SCALE => 0,
    GRID_OPT => 1,
    OWL_THREATS => 0,
diff -N -r -u -X .ignore gnugo-copy/patterns/patterns.vcproj gnugo/patterns/patterns.vcproj
--- gnugo-copy/patterns/patterns.vcproj	2007-02-16 23:36:34.484375000 +0100
+++ gnugo/patterns/patterns.vcproj	2007-03-09 00:36:16.796875000 +0100
@@ -623,6 +623,10 @@
 			Filter="h;hpp;hxx;hm;inl"
 			>
 			<File
+				RelativePath="..\config.h"
+				>
+			</File>
+			<File
 				RelativePath="dfa.h"
 				>
 			</File>
