[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnugo-devel] semeai patch
From: |
Gunnar Farneback |
Subject: |
[gnugo-devel] semeai patch |
Date: |
Fri, 28 Nov 2003 17:22:04 +0100 |
User-agent: |
EMH/1.14.1 SEMI/1.14.3 (Ushinoya) FLIM/1.14.2 (Yagi-Nishiguchi) APEL/10.3 Emacs/20.7 (sparc-sun-solaris2.7) (with unibyte mode) |
This patch improves the semeai code to better handle the case where
one small dragon, possibly a single string, is enclosed within a
bigger dragon. It also introduces a new function
find_moves_to_make_seki(), which tries to turn the potential territory
of an already alive group into seki. The latter is done by identifying
tactically critical strings enclosed inside a dragon which is not
obviously alive anyway, then calling owl_analyze_semeai_after_move()
to determine whether the tactically defending move suffices to get a
seki. Naturally this does not cover all cases where seki can be
achieved so there's room for further improvements.
In many of the standard corner positions which can be turned into
seki, one or both players have the option to instead choose a ko for
life and death of both. Exactly who benefits from this depends on a
number of factors like ko threat situation and overall score. A
reasonable general rule is however that if one player only risks a few
points in the ko while the other stands to lose much more, the first
player would be happy with the ko. This patch introduces that
assumption in the semeai code.
Additionally it makes some minor tweaks, a bit of tuning, and fixes a
troublesome off-by-one error.
- if one dragon is considerably smaller than the other in a semeai,
prefer to get ko over seki
- in a semeai, consider also the eyespaces including opponent semeai
worms in order to detect a definite lack of eyespace and to find
certain vital moves
- off-by-one error in loops over semeai_worms[] corrected
- don't allow "safe" common liberties to depend on ko
- new static function find_moves_to_make_seki() in semeai.c
- do semeai analysis for all pairs of critical/dead dragons except
when one is inessential, other exceptional cases removed
- owl tuning
- tuning
- revised test cases
Regression results, relative to (almost) current CVS:
blunder:26 FAIL D19 [!D19|F17]
nicklas3:401 PASS A5 [A5]
trevorc:1000 PASS N9 [N9|M11]
strategy3:135 PASS M13 [M12|N13|M13]
strategy3:141 FAIL J3 [C7]
semeai:51 PASS 1 0 A19 [1 0 (A19|E11)]
semeai:61 PASS 1 0 A15 [1 0 A15]
semeai:62 PASS 1 1 A17 [1 1 A17]
semeai:65 PASS 0 0 PASS [0 0 PASS]
semeai:66 PASS 1 1 PASS [1 1 (PASS|N13)]
semeai:68 PASS 1 1 A5 [1 1 (PASS|A5|B5|C3|D3)]
strategy4:155 PASS D18 [D18]
strategy4:162 PASS O7 [O7|Q7|N7]
strategy4:192 FAIL K3 [A15]
nngs3:700 FAIL P7 [Q2]
strategy5:282 PASS O13 [O13]
ninestones:660 PASS P1 [P1]
tactics1:106 FAIL B8 [F8|F6]
gunnar:42 PASS B19 [B19]
gifu03:2 PASS R1 [R1]
gifu03:302 FAIL N17 [C1|B6]
seki:103 PASS B1 [B1]
seki:105 PASS C1 [C1]
seki:110 PASS B1 [B1]
seki:111 PASS C2 [C2]
seki:203 PASS A2 [A2|B1]
seki:205 PASS C1 [C1|C2]
seki:301 PASS B2 [B2]
seki:302 PASS B2 [B2]
seki:305 PASS C2 [C2]
seki:407 PASS C2 [C2|E1]
seki:412 PASS D1 [D1]
seki:503 PASS C1 [C1]
seki:801 PASS B2 [B2]
seki:802 PASS B2 [B2]
seki:803 PASS C2 [C2]
seki:805 PASS A2 [A2]
seki:808 PASS C2 [C2]
seki:810 PASS A3 [A3]
seki:901 PASS B2 [B2]
seki:902 PASS B2 [B2]
seki:903 PASS C1 [C2|C1]
seki:904 PASS B3 [B3]
seki:910 PASS A1 [A1|A2]
seki:912 PASS C1 [C1]
Comments on the failures:
blunder:26
Possibly a real failure, needs further investigation.
strategy3:141
Semeai reading mistake. The patch only causes the reading to be done,
which is reasonable.
strategy4:192
Not a real failure. The status of the upper left corner is now
correctly understood and valued about right. Is A15 really the biggest
move on the board, by the way?
nngs3:700
Valuation problem. The semeai understanding has improved.
tactics1:106
Same kind of problem as strategy3:141.
gifu03:302
Semeai reading mistake.
/Gunnar
Index: engine/owl.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.183
diff -u -r1.183 owl.c
--- engine/owl.c 13 Nov 2003 22:48:41 -0000 1.183
+++ engine/owl.c 28 Nov 2003 10:22:10 -0000
@@ -288,6 +288,21 @@
static int semeai_worms[MAX_SEMEAI_WORMS];
static int important_semeai_worms[MAX_SEMEAI_WORMS];
+/* Whether one color prefers to get a ko over a seki. */
+static int prefer_ko;
+
+/* Usually it's a bad idea to include the opponent worms involved in
+ * the semeai in the eyespace. For some purposes (determining a
+ * definite lack of eyespace, finding certain vital moves), however,
+ * we want to do that anyway. Then set this variable to 1 before
+ * calling owl_estimate_life() and reset it afterwards.
+ *
+ * FIXME: We should implement a nicer mechanism to propagate this
+ * information to owl_lively(), where it's used.
+ */
+static int include_semeai_worms_in_eyespace = 0;
+
+
/* Called when (apos) and (bpos) point to adjacent dragons
* of the opposite color, both with matcher_status DEAD or
* CRITICAL, analyzes the semeai, assuming that the player
@@ -397,6 +412,25 @@
result_certain = 1;
+ /* In some semeai situations one or both players have the option to
+ * choose between seki and ko for the life and death of both. In
+ * general this choice depends on the ko threat situation, the
+ * overall score, and the strategical effects on surrounding
+ * dragons, but we don't try to correctly estimate this. Instead we
+ * make the reasonable assumption that if one dragon is
+ * substantially smaller than the other dragon, ko is to be
+ * preferred for the smaller dragon and seki for the larger dragon.
+ *
+ * prefer_ko can be either WHITE, BLACK, or EMPTY and tells which
+ * color, if any, prefers to get ko.
+ */
+ if (dragon[apos].size <= 5 && dragon[bpos].size > 3 * dragon[apos].size)
+ prefer_ko = board[apos];
+ else if (dragon[bpos].size <= 5 && dragon[apos].size > 3 * dragon[bpos].size)
+ prefer_ko = board[bpos];
+ else
+ prefer_ko = EMPTY;
+
if (move == PASS_MOVE)
do_owl_analyze_semeai(apos, bpos, owla, owlb, EMPTY, NO_MOVE,
resulta, resultb, semeai_move, 0, owl);
@@ -537,7 +571,7 @@
int upos;
int sworm;
- for (sworm = 0; sworm <= s_worms; sworm++) {
+ for (sworm = 0; sworm < s_worms; sworm++) {
critical_semeai_worms[sworm] = 0;
if (board[semeai_worms[sworm]] == other) {
int acode = attack(semeai_worms[sworm], &upos);
@@ -565,7 +599,7 @@
* threatened, try to save it.
*/
- for (sworm = 0; sworm <= s_worms; sworm++)
+ for (sworm = 0; sworm < s_worms; sworm++)
if (board[semeai_worms[sworm]] == color
&& attack(semeai_worms[sworm], NULL)
&& find_defense(semeai_worms[sworm], &upos)) {
@@ -712,6 +746,23 @@
critical_semeai_worms);
}
+ /* If no moves were found so far, also check the eyespaces when
+ * opponent semeai worms are allowed to be included for vital
+ * moves.
+ */
+ if (moves[0].pos == NO_MOVE) {
+ include_semeai_worms_in_eyespace = 1;
+ if (!owl_estimate_life(owlb, owla, vital_offensive_moves,
+ &live_reasonb, komaster, 1, &probable_eyes_b,
+ &eyemin_b, &eyemax_b))
+ semeai_review_owl_moves(vital_offensive_moves, owla, owlb, color,
+ &safe_outside_liberty_found,
+ &safe_common_liberty_found,
+ mw, moves, 1, 30,
+ critical_semeai_worms);
+ include_semeai_worms_in_eyespace = 0;
+ }
+
if (level < 8) {
/* If no owl moves were found on two consecutive moves,
* turn off the owl phase.
@@ -758,7 +809,7 @@
}
else {
/* common liberty */
- if (safe_move(pos, color)) {
+ if (safe_move(pos, color) == WIN) {
safe_common_liberty_found = 1;
common_liberty.pos = pos;
}
@@ -866,16 +917,19 @@
close_pattern_list(color, &shape_offensive_patterns);
READ_RETURN_SEMEAI(read_result, move, mpos, WIN, WIN);
}
- /* We consider our own safety most important and attacking the
- * opponent as a secondary aim. This means that we prefer seki
- * over a ko for life and death.
- *
- * FIXME: If our dragon is considerably smaller than the
- * opponent dragon, we should probably prefer ko over seki.
+ /* When there is a choice between ko and seki, the prefer_ko
+ * variable decides policy. Thus if prefer_ko == color we
+ * consider attacking the opponent more important than defending
+ * our dragon, and vise versa otherwise.
*/
- else if (this_resulta > best_resulta
- || (this_resulta == best_resulta
- && this_resultb > best_resultb)) {
+ else if ((prefer_ko != color
+ && (this_resulta > best_resulta
+ || (this_resulta == best_resulta
+ && this_resultb > best_resultb)))
+ || (prefer_ko == color
+ && (this_resultb > best_resultb
+ || (this_resultb == best_resultb
+ && this_resulta > best_resulta)))) {
best_resulta = this_resulta;
best_resultb = this_resultb;
best_move = mpos;
@@ -898,6 +952,38 @@
READ_RETURN_SEMEAI(read_result, move, PASS_MOVE, 0, 0);
}
+ /* If we can't find a move and we look dead even if including the
+ * opponent stones in our eyespace, we have lost.
+ */
+ if (tested_moves == 0) {
+ const char *live_reasona;
+ struct eyevalue probable_eyes_a;
+ int eyemin_a;
+ int eyemax_a;
+ int sworm;
+ for (sworm = 0; sworm < s_worms; sworm++) {
+ if (board[semeai_worms[sworm]] == other) {
+ if (important_semeai_worms[sworm])
+ break;
+ }
+ }
+
+ if (sworm == s_worms) {
+ include_semeai_worms_in_eyespace = 1;
+ if (!owl_estimate_life(owla, owlb, vital_defensive_moves,
+ &live_reasona, komaster, 0, &probable_eyes_a,
+ &eyemin_a, &eyemax_a)) {
+ include_semeai_worms_in_eyespace = 0;
+ *resulta = 0;
+ *resultb = 0;
+ *move = PASS_MOVE;
+ SGFTRACE_SEMEAI(PASS_MOVE, 0, 0, "You live, I die - 2");
+ READ_RETURN_SEMEAI(read_result, move, PASS_MOVE, 0, 0);
+ }
+ include_semeai_worms_in_eyespace = 0;
+ }
+ }
+
/* If we can't find a move and opponent passed, it's seki */
if (tested_moves == 0 && pass == 1) {
*resulta = WIN;
@@ -1174,7 +1260,7 @@
}
increase_depth_values();
- for (k = 0; k <= s_worms; k++) {
+ for (k = 0; k < s_worms; k++) {
if (!critical_semeai_worms[k])
continue;
if (board[semeai_worms[k]] == color
@@ -2500,6 +2586,7 @@
memset(found_matches, 0, sizeof(found_matches));
if (level >= 8) {
+ memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache));
if (!does_attack) {
clear_owl_move_data(dummy_moves);
matchpat(owl_shapes_callback, other,
@@ -4895,6 +4982,10 @@
* other dragon and can't be saved is not lively.
*/
if (other_owl_data) {
+
+ if (include_semeai_worms_in_eyespace && other_owl_data->goal[pos])
+ return 0;
+
if (other_owl_data->goal[pos] && !semeai_trust_tactical_attack(pos))
return 1;
/* FIXME: Shouldn't we check other_owl_data->inessential[origin] here? */
Index: engine/semeai.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/semeai.c,v
retrieving revision 1.64
diff -u -r1.64 semeai.c
--- engine/semeai.c 19 Nov 2003 07:53:49 -0000 1.64
+++ engine/semeai.c 28 Nov 2003 10:22:10 -0000
@@ -29,6 +29,7 @@
#define INFINITY 1000
+static void find_moves_to_make_seki(void);
static void update_status(int dr, enum dragon_status new_status,
enum dragon_status new_safety);
@@ -83,25 +84,8 @@
|| (dragon[bpos].status != DEAD
&& dragon[bpos].status != CRITICAL))
continue;
+
- /* A dragon consisting of a single worm which is tactically dead or
- * critical and having just one neighbor should be ignored, since
- * the owl code is more reliable than the semeai code in such cases.
- * We do allow these cases if the worm has 4 liberties and can be
- * defended.
- */
-
- if (dragon[apos].size == worm[apos].size
- && worm[apos].attack_codes[0]
- && (worm[apos].liberties < 4
- || worm[apos].defense_codes[0] == 0))
- continue;
-
- if (dragon[bpos].size == worm[bpos].size
- && worm[bpos].attack_codes[0]
- && (worm[bpos].liberties < 4
- || worm[bpos].defense_codes[0] == 0))
- continue;
/* Ignore inessential worms or dragons */
if (worm[apos].inessential
@@ -110,10 +94,6 @@
|| DRAGON2(bpos).safety == INESSENTIAL)
continue;
- /* If either dragon is a single stone, this is best left
- * to the owl code */
- if (dragon[apos].size == 1 || dragon[bpos].size == 1)
- continue;
/* The array semeai_results_first[d1][d2] will contain the status
* of d1 after the d1 d2 semeai, giving d1 the first move.
@@ -225,6 +205,80 @@
}
else if (best_attack == 0 && attack_certain)
update_status(DRAGON(d1).origin, ALIVE, ALIVE);
+ }
+ }
+ find_moves_to_make_seki();
+}
+
+/* Find moves turning supposed territory into seki. This is not
+ * detected above since it either involves an ALIVE dragon adjacent to
+ * a CRITICAL dragon, or an ALIVE dragon whose eyespace can be invaded
+ * and turned into a seki.
+ *
+ * Currently we only search for tactically critical strings with
+ * dragon status dead, which are neighbors of only one opponent
+ * dragon, which is alive. Through semeai analysis we then determine
+ * whether such a string can in fact live in seki. Relevant testcases
+ * include gunnar:42 and gifu03:2.
+ */
+static void
+find_moves_to_make_seki()
+{
+ int str;
+ int defend_move;
+ int resulta, resultb;
+
+ for (str = BOARDMIN; str < BOARDMAX; str++) {
+ if (IS_STONE(board[str]) && is_worm_origin(str, str)
+ && attack_and_defend(str, NULL, NULL, NULL, &defend_move)
+ && dragon[str].status == DEAD
+ && DRAGON2(str).hostile_neighbors == 1) {
+ int k;
+ int color = board[str];
+ int opponent;
+ int certain;
+
+ for (k = 0; k < DRAGON2(str).neighbors; k++) {
+ opponent = dragon2[DRAGON2(str).adjacent[k]].origin;
+ if (board[opponent] != color)
+ break;
+ }
+
+ if (dragon[opponent].status != ALIVE)
+ continue;
+
+ /* FIXME: These heuristics are not very precise. What we really
+ * want to check is whether str is inside the eyespace of the
+ * opponent, for an interpretation of eyespace that includes
+ * lunches, while it doesn't already have more than one eye
+ * elsewhere.
+ */
+ if (DRAGON2(opponent).moyo_size > 10
+ || min_eyes(&DRAGON2(opponent).genus) > 1)
+ continue;
+
+ owl_analyze_semeai_after_move(defend_move, color, opponent, str,
+ &resulta, &resultb, NULL, 1, &certain);
+
+ /* Do not trust uncertain results. In fact it should only take a
+ * few nodes to determine the semeai result, if it is a proper
+ * potential seki position.
+ */
+ if (resultb != WIN && certain) {
+ int d = dragon[str].id;
+ DEBUG(DEBUG_SEMEAI, "Move to make seki at %1m (%1m vs %1m)\n",
+ defend_move, str, opponent);
+ dragon2[d].semeai = 1;
+ update_status(str, CRITICAL, CRITICAL);
+ dragon2[d].semeai_defense_point = defend_move;
+ dragon2[d].semeai_defense_certain = certain;
+ /* FIXME: The assumption that the attack move coincides with
+ * the defense move is somewhat optimistic.
+ */
+ dragon2[d].semeai_attack_point = defend_move;
+ dragon2[d].semeai_attack_certain = certain;
+ dragon2[d].semeai_target = opponent;
+ }
}
}
}
Index: patterns/owl_attackpats.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/owl_attackpats.db,v
retrieving revision 1.99
diff -u -r1.99 owl_attackpats.db
--- patterns/owl_attackpats.db 19 Nov 2003 07:53:49 -0000 1.99
+++ patterns/owl_attackpats.db 28 Nov 2003 10:22:11 -0000
@@ -1913,6 +1913,24 @@
:8,s,value(45)
+Pattern A503b
+# gf New pattern. (3.5.3)
+
+?XXX atari to eliminate eye or make ko
+Y.O.
+X.X*
+----
+
+:8,s,value(32)
+
+?XXX
+Y.O.
+X.X*
+----
+
+;olib(*)>1
+
+
Pattern A504
Y* cut off one stone
@@ -3127,15 +3145,46 @@
:8,s,value(36)
-# Pattern A906
-# # gf We don't need two copies of this pattern. Removed one. (3.1.14)
-#
-# |O.X try to form nakade
-# |XOX
-# |*..
-# +---
-#
-# :8,s,value(35)
+Pattern A906a
+# gf New pattern. (3.5.3)
+# See seki:303.
+
+|X???
+|.YX?
+|XO.X try to make ko
+|*.O.
++----
+
+:8,s,value(32)
+
+|Xa??
+|.YX?
+|XO.X
+|*.O.
++----
+
+;!o_somewhere(a) || !defend(a)
+
+
+Pattern A906b
+# gf New pattern. (3.5.3)
+# See seki:303.
+
+|X???
+|.YX?
+|.OXX try to make ko
+|*.O.
++----
+
+:8,s,value(32)
+
+|Xa??
+|.YX?
+|.OXX
+|*.O.
++----
+
+;!o_somewhere(a) || !defend(a)
Pattern A907
@@ -4579,6 +4628,24 @@
;owl_escape_value(A)>0 && !xplay_disconnect(*,A,B) && !oplay_connect(*,A,B)
+Pattern A1136
+# gf New pattern. (3.5.3)
+
+?Y?
+O*O
+..?
+?X?
+
+:8,-,value(75)
+
+?B?
+O*O
+..?
+?A?
+
+;owl_escape_value(A)>0 && !xplay_disconnect(*,A,B) && !oplay_connect(*,A,B)
+
+
#########################################################
# #
# Kill or threaten a worm of the dragon #
@@ -4752,6 +4819,24 @@
+----
:8,s,value(50)
+
+
+Pattern A1303c
+# gf New pattern. (3.5.3)
+
+|..X? variation
+|XOYo
+|.*.?
++----
+
+:8,s,value(85)
+
+|..X?
+|XaYo
+|.*.?
++----
+
+;defend(a) != WIN
Pattern A1304
Index: patterns/owl_defendpats.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/owl_defendpats.db,v
retrieving revision 1.108
diff -u -r1.108 owl_defendpats.db
--- patterns/owl_defendpats.db 19 Nov 2003 07:53:49 -0000 1.108
+++ patterns/owl_defendpats.db 28 Nov 2003 10:22:13 -0000
@@ -2607,6 +2607,18 @@
:8,-,value(40)
+Pattern D644
+# gf New pattern. (3.5.3)
+# See seki:111.
+
+oOOo make one definite eye
+.*.O
+X..O
+----
+
+:8,-,value(30)
+
+
#########################################################
# #
# Make eyeshape in the center #
@@ -3677,6 +3689,19 @@
+----
;does_attack(*,A) && xplay_attack(b,*,c,A)
+
+
+Pattern D840
+# gf New pattern. (3.5.3)
+# See seki:203.
+
+|OO??
+|.*O?
+|XXOO make seki
+|.O.O
++----
+
+:8,-,value(25)
#########################################################
Index: patterns/patterns.db
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/patterns.db,v
retrieving revision 1.119
diff -u -r1.119 patterns.db
--- patterns/patterns.db 19 Nov 2003 07:53:49 -0000 1.119
+++ patterns/patterns.db 28 Nov 2003 10:22:16 -0000
@@ -13630,8 +13630,8 @@
Pattern S6c
-# Back out from a potential and horribly complex ko for the
-# life of the entire corner. This moves secures a seki.
+# Eliminate a potential 1000-year ko for the life of the entire
+# corner. This moves secures a seki.
|OO??
|.OOO
@@ -13668,6 +13668,223 @@
+----
;lib(a)==4 && seki_helper(a)
+
+
+Pattern S8
+# gf New pattern. (3.5.3)
+# 7 points gote seki. See seki:301.
+
+|XX???
+|.XXX?
+|.*.XX
+|....X
++-----
+
+:8,sXe,terri(7)
+
+|AA???
+|.AAA?
+|.*.AA
+|....A
++-----
+
+;lib(A)==4 && seki_helper(A)
+
+
+Pattern S9
+# gf New pattern. (3.5.3)
+# 7 points seki. Compare S8. See seki:302
+
+|OO???
+|.OOO?
+|.*.OO
+|....O
++-----
+
+:8,sXe,terri(7)
+
+|aa???
+|.aaa?
+|.*.aa
+|....a
++-----
+
+;lib(a)==4 && seki_helper(a)
+
+
+Pattern S10
+# gf New pattern. (3.5.3)
+# 8 points (mostly) sente seki. See seki:801.
+
+|XXX??
+|..XX?
+|.*.XX
+|....X
++-----
+
+:8,sXe,terri(8),followup(16)
+
+|AAA??
+|..AA?
+|.*.AA
+|....A
++-----
+
+;lib(A)==4 && seki_helper(A)
+
+
+Pattern S10b
+# gf New pattern. (3.5.3)
+# Best way to secure seki. See seki:803.
+
+|OOO??
+|..OO?
+|.X*OO
+|....O
++-----
+
+:8,sXe,terri(8),reverse_followup(16)
+
+|aaa??
+|..aa?
+|bX*aa
+|....a
++-----
+
+;lib(a)==4 && seki_helper(a)
+
+>replace(b,*);
+
+
+Pattern S10c
+# gf New pattern. (3.5.3)
+# Make seki in sente, not gote. See seki:808.
+
+|XXX??
+|..XX?
+|.O*XX
+|..X.X
++-----
+
+:8,sXe,terri(8),followup(16)
+
+|AAA??
+|..AA?
+|bO*AA
+|.cX.A
++-----
+
+;lib(A)==4 && seki_helper(A)
+
+>replace(b,*);
+>replace(c,*);
+
+
+Pattern S10d
+# gf New pattern. (3.5.3)
+# Make seki in sente, not gote. See seki:810.
+# Only replace pattern here. The seki_helper doesn't apply and the
+# semeai code should find either a or * if there's a chance to make seki.
+
+|XXX??
+|*.XX?
+|.OOXX
+|.XX.X
++-----
+
+:8,sX
+
+|XXX??
+|*.XX?
+|aOOXX
+|.XX.X
++-----
+
+>replace(a,*);
+
+
+Pattern S11
+# gf New pattern. (3.5.3)
+# 8 points (mostly) reverse sente seki. Compare S10. See seki:802.
+
+|OOO??
+|..OO?
+|.*.OO
+|....O
++-----
+
+:8,sXe,terri(8),reverse_followup(16)
+
+|aaa??
+|..aa?
+|.*.aa
+|....a
++-----
+
+;lib(a)==4 && seki_helper(a)
+
+
+Pattern S12
+# gf New pattern. (3.5.3)
+# 9 points gote seki. See seki:901.
+
+|XXXX?
+|...X?
+|.*.XX
+|....X
++-----
+
+:8,sXe,terri(9)
+
+|AAAA?
+|...A?
+|.*.AA
+|....A
++-----
+
+;lib(A)==5 && seki_helper(A)
+
+
+Pattern S13
+# gf New pattern. (3.5.3)
+# 9 points seki. Compare S12. See seki:902.
+
+|OOOO?
+|...O?
+|.*.OO
+|....O
++-----
+
+:8,sXe,terri(9)
+
+|aaaa?
+|...a?
+|.*.aa
+|....a
++-----
+
+;lib(a)==5 && seki_helper(a)
+
+
+Pattern S14b
+# gf New pattern. (3.5.3)
+# Make sente seki. See seki:905.
+
+|OOOO?
+|.X.O?
+|.XOOO
+|..*.O
++-----
+
+:8,sX
+
+|OOOO?
+|.X.O?
+|.XOOO
+|.a*.O
++-----
+
+> replace(a,*);
######################################################################
Index: regression/ld_owl.tst
===================================================================
RCS file: /cvsroot/gnugo/gnugo/regression/ld_owl.tst,v
retrieving revision 1.32
diff -u -r1.32 ld_owl.tst
--- regression/ld_owl.tst 24 Aug 2003 21:28:40 -0000 1.32
+++ regression/ld_owl.tst 28 Nov 2003 10:22:17 -0000
@@ -134,6 +134,7 @@
51 dragon_status R3
#? [critical S1 (R1|S1|T5|T4|T3|S2|S3|T1)]
# B1 is a better defense than D1 because the latter only lives by double ko.
+# FIXME: D1 and A5 only attack with ko since black can reply at A2.
52 dragon_status C4
#? [critical (D1|A5) (B1|D1|B2)]
Index: regression/seki.tst
===================================================================
RCS file: /cvsroot/gnugo/gnugo/regression/seki.tst,v
retrieving revision 1.1
diff -u -r1.1 seki.tst
--- regression/seki.tst 17 Nov 2003 10:32:49 -0000 1.1
+++ regression/seki.tst 28 Nov 2003 10:22:18 -0000
@@ -239,9 +239,10 @@
loadsgf games/seki08.sgf
401 reg_genmove white
#? [B1]
-# Most moves secure territory but C1 and C2 are most natural.
+# Most moves secure territory but C1 and C2 are most natural. We also
+# allow B1.
402 reg_genmove black
-#? [C1|C2]
+#? [C1|C2|B1]
# C1 and C2 both secure seki, but C1 is one prisoner better.
# B2 leaves white the option to make ko.
@@ -404,16 +405,18 @@
902 reg_genmove black
#? [B2]
-# Black probably have more moves to make seki but C2 looks most natural.
+# Black probably have more moves to make seki but C2 looks most
+# natural. C1 is also good enough
play white B2
903 reg_genmove black
-#? [C2]
+#? [C2|C1]
play black C2
904 reg_genmove white
#? [B3]
-# B1 gives ko or seki in gote.
+# B1 gives ko or seki in gote. Tenuki also leaves a seki but compared
+# to C1 the latter is 1 point double sente.
play white B3
905 reg_genmove black
#? [C1]
@@ -432,6 +435,7 @@
908 reg_genmove white
#? [A2]
+# 1 point double sente, just like 907.
undo
909 reg_genmove white
#? [A3]
Index: regression/strategy4.tst
===================================================================
RCS file: /cvsroot/gnugo/gnugo/regression/strategy4.tst,v
retrieving revision 1.72
diff -u -r1.72 strategy4.tst
--- regression/strategy4.tst 5 Nov 2003 19:05:19 -0000 1.72
+++ regression/strategy4.tst 28 Nov 2003 10:22:18 -0000
@@ -216,6 +216,9 @@
191 reg_genmove black
#? [C12]
+# A15 captures the white corner stones but does not have much
+# strategical value. The black stones are safe anyway. Thus A15 is
+# worth about 19 points. Other moves may well be larger.
loadsgf games/pooo.sgf 74
192 reg_genmove black
#? [A15]
- [gnugo-devel] semeai patch,
Gunnar Farneback <=