This revision of safety_3_10.1a changes one thing: a dragon is not considered surrounded if an ikken tobi jumps out. This is necessary because an ikken tobi is often not a connection but in practice often just as good as one. After this patch, the surround status is a dragon2 field and is computed for every dragon on the board. The time required for this is negligible---usualy less than 0.01 sec on a celeron 433. === This patch implements a new test for when dragons are surrounded. The idea is that this will be an ingredient in the computation of the new weakness field. There is another way in which it can be used, as I will explain later. I believe it correlates pretty well with the intuitive sense of when a group is becoming surrounded and may have difficulty living if it does not already have two eyes. The patch does not affect play but only adds a command line option --decide-surrounded [pos] which allows you to see the computation. The idea is based on my imperfect recollection of and idea of Bruce Wilcox. The convex hull of the neighbor dragons is computed, and a slightly larger area is also marked. If every friendly dragon that meets the hull is contained within it, the dragon is SURROUNDED. If every friendly dragon that meets the hull is contained within the enlargement, it is WEAKLY SURROUNDED. An examination of 9 test cases identified by myself and Arend as ones where GNU is prone to neglect a weak dragon shows that in every one of these cases the dragon is surrounded in this sense. I also have the idea that one may be able to make use of this idea to identify good defensive moves. This will involve caching the polygon when a weak dragon is found. Then any move matching an e or E pattern (as discussed in http://mail.gnu.org/pipermail/gnugo-devel/2002-October/003003.html) is a good defense provided it lies outside the polygon. safety:1 Dragon R3 effective_size 10.83 Owl status ALIVE (certain) Safety WEAKLY_ALIVE weakness estimate 0.83 Neighbors P3 R9 No base. SURROUNDED. P6 breaks out. S2 or R7 makes a base. safety:2 Dragon R3 effective_size 10.83 Owl status ALIVE (certain) Safety WEAK weakness estimate 0.83 Neighbors P3 R9 No base. WEAKLY SURROUNDED. P6 breaks out. safety:3 Dragon E16 effective size 11.08 Owl status ALIVE (certain) Safety WEAKLY_ALIVE Weakness estimate 0.68 Neighbors C16 G17 No base. WEAKLY SURROUNDED. safety:4 Dragon E16 effective_size 8.17 Owl status ALIVE (certain) Safety WEAKLY_ALIVE Weakness estimate 0.83 Neighbors C16 G17 H15 No base. SURROUNDED. F13 and G14 break out. safety:5 Dragon M8 effective_size 15.25 Owl status ALIVE (certain) Safety WEAK Weakness estimate 0.79 Neighbors M11 P11 O5 M6 No base. SURROUNDED. L9 and K8 break out. safety:6 Dragon K4 effective_size 9.08 Owl status ALIVE Safety WEAKLY_ALIVE Weakness estimate 0.62 Neighbors O3 F4 No base SURROUNDED. K6 breaks out. safety:7 Dragon K4 effective_size 10.57 Owl status ALIVE (attack uncertain) Safety WEAK Weakness estimate 0.92 Neighbors F4 K8 O3 (G2) No base SURROUNDED. century2002:50 Dragon F3 effective size 10.17 Owl status ALIVE (certain) Safety WEAKLY_ALIVE weakness estimate 0.72 Neighbors D3 J4 No base. SURROUNDED. F7 breaks out. nngs1:8 Dragon L8-K7-M7 effective size 10.59 Owl status ALIVE (certain). Safety WEAKLY_ALIVE Weakness estimate 0.72 Neighbors K9 Q9 J7 Q5. No base. SURROUNDED. M10 breaks out. Command lines for the above test cases: safety:1 gnugo -l gnugo-3.3.10/regression/games/nngs/gnugo-3.3.6-xtc-200208301619.sgf -L 16 --quiet --decide-surrounded R3 safety:2 gnugo -l gnugo-3.3.10/regression/games/nngs/gnugo-3.3.6-xtc-200208301619.sgf -L 20 --quiet --decide-surrounded R3 safety:3 gnugo -l gnugo-3.3.10/regression/games/cgf2002/gnu-har.sgf --quiet -L 19 --decide-surrounded E16 safety:4 gnugo -l gnugo-3.3.10/regression/games/cgf2002/gnu-har.sgf --quiet -L 21 --decide-surrounded E16 safety:5 gnugo -l gnugo-3.3.10/regression/games/nngs/gnugo-3.1.27-GoFuN-200203080451.sgf --quiet -L 42 --decide-surrounded M8 safety:6 gnugo -l gnugo-3.3.10/regression/games/nngs/abcd-gnugo-3.3.8-200209202043.sgf --quiet -L 12 --decide-surrounded K4 safety:7 gnugo -l gnugo-3.3.10/regression/games/nngs/abcd-gnugo-3.3.8-200209202043.sgf --quiet -L 22 --decide-surrounded K4 century2002:50 gnugo --quiet -l gnugo-3.3.10/regression/games/century21-2002/goint-gnugo.sgf -L 47 --decide-surrounded F3 nngs1:8 gnugo --quiet -l gnugo-3.3.10/regression/games/nngs/gnugo-3.1.26-journeyman-200203020154.sgf -L 32 --decide-surrounded L8 Index: engine/Makefile.am =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/Makefile.am,v retrieving revision 1.12 diff -u -r1.12 Makefile.am --- engine/Makefile.am 26 Sep 2002 20:04:36 -0000 1.12 +++ engine/Makefile.am 10 Oct 2002 22:25:37 -0000 @@ -40,6 +40,7 @@ printutils.c \ readconnect.c \ reading.c \ + safety.c \ score.c \ semeai.c \ sgfdecide.c \ Index: engine/Makefile.in =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/Makefile.in,v retrieving revision 1.37 diff -u -r1.37 Makefile.in --- engine/Makefile.in 26 Sep 2002 22:28:06 -0000 1.37 +++ engine/Makefile.in 10 Oct 2002 22:25:38 -0000 @@ -122,6 +122,7 @@ printutils.c \ readconnect.c \ reading.c \ + safety.c \ score.c \ semeai.c \ sgfdecide.c \ @@ -162,10 +163,10 @@ life.$(OBJEXT) matchpat.$(OBJEXT) move_reasons.$(OBJEXT) \ movelist.$(OBJEXT) optics.$(OBJEXT) owl.$(OBJEXT) \ persistent.$(OBJEXT) printutils.$(OBJEXT) readconnect.$(OBJEXT) \ - reading.$(OBJEXT) score.$(OBJEXT) semeai.$(OBJEXT) \ - sgfdecide.$(OBJEXT) sgffile.$(OBJEXT) shapes.$(OBJEXT) \ - showbord.$(OBJEXT) utils.$(OBJEXT) value_moves.$(OBJEXT) \ - worm.$(OBJEXT) + reading.$(OBJEXT) safety.$(OBJEXT) score.$(OBJEXT) \ + semeai.$(OBJEXT) sgfdecide.$(OBJEXT) sgffile.$(OBJEXT) \ + shapes.$(OBJEXT) showbord.$(OBJEXT) utils.$(OBJEXT) \ + value_moves.$(OBJEXT) worm.$(OBJEXT) libengine_a_OBJECTS = $(am_libengine_a_OBJECTS) DEFS = @DEFS@ @@ -186,11 +187,11 @@ @AMDEP_TRUE@ $(DEPDIR)/optics.Po $(DEPDIR)/owl.Po \ @AMDEP_TRUE@ $(DEPDIR)/persistent.Po $(DEPDIR)/printutils.Po \ @AMDEP_TRUE@ $(DEPDIR)/readconnect.Po $(DEPDIR)/reading.Po \ -@AMDEP_TRUE@ $(DEPDIR)/score.Po $(DEPDIR)/semeai.Po \ -@AMDEP_TRUE@ $(DEPDIR)/sgfdecide.Po $(DEPDIR)/sgffile.Po \ -@AMDEP_TRUE@ $(DEPDIR)/shapes.Po $(DEPDIR)/showbord.Po \ -@AMDEP_TRUE@ $(DEPDIR)/utils.Po $(DEPDIR)/value_moves.Po \ -@AMDEP_TRUE@ $(DEPDIR)/worm.Po +@AMDEP_TRUE@ $(DEPDIR)/safety.Po $(DEPDIR)/score.Po \ +@AMDEP_TRUE@ $(DEPDIR)/semeai.Po $(DEPDIR)/sgfdecide.Po \ +@AMDEP_TRUE@ $(DEPDIR)/sgffile.Po $(DEPDIR)/shapes.Po \ +@AMDEP_TRUE@ $(DEPDIR)/showbord.Po $(DEPDIR)/utils.Po \ +@AMDEP_TRUE@ $(DEPDIR)/value_moves.Po $(DEPDIR)/worm.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -257,6 +258,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/printutils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/readconnect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/reading.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/safety.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/score.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/semeai.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/sgfdecide.Po@am__quote@ Index: engine/dragon.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v retrieving revision 1.86 diff -u -r1.86 dragon.c --- engine/dragon.c 9 Oct 2002 18:36:23 -0000 1.86 +++ engine/dragon.c 10 Oct 2002 22:25:38 -0000 @@ -543,6 +543,18 @@ time_report(2, " owl threats ", NO_MOVE, 1.0); + for (d = 0; d < number_of_dragons; d++) { + dragon2[d].surround_status = surrounded(dragon2[d].origin, 0); + if (debug & DEBUG_DRAGONS) { + if (dragon2[d].surround_status == 1) + gprintf ("surrounded dragon found at %1m\n", dragon2[d].origin); + if (dragon2[d].surround_status == 2) + gprintf ("weakly surrounded dragon found at %1m\n", dragon2[d].origin); + } + } + + time_report(2, " surround status", NO_MOVE, 0.0); + /* Compute the safety value. */ for (d = 0; d < number_of_dragons; d++) { int true_genus; @@ -760,18 +772,19 @@ /* Initialize the rest of the dragon2 data. */ for (d = 0; d < number_of_dragons; d++) { - dragon2[d].neighbors = 0; - dragon2[d].hostile_neighbors = 0; - dragon2[d].moyo_size_pre_owl = -1; - dragon2[d].moyo_size_post_owl = -1; + dragon2[d].neighbors = 0; + dragon2[d].hostile_neighbors = 0; + dragon2[d].moyo_size_pre_owl = -1; + dragon2[d].moyo_size_post_owl = -1; dragon2[d].moyo_territorial_value = 0.0; - dragon2[d].safety = -1; - dragon2[d].escape_route = 0; - set_eyevalue(&dragon2[d].genus, 0, 0, 0, 0); - dragon2[d].heye = NO_MOVE; - dragon2[d].lunch = NO_MOVE; - dragon2[d].semeai = 0; + dragon2[d].safety = -1; + dragon2[d].escape_route = 0; + dragon2[d].heye = NO_MOVE; + dragon2[d].lunch = NO_MOVE; + dragon2[d].semeai = 0; dragon2[d].semeai_margin_of_safety = -1; + dragon2[d].surround_status = 0; + set_eyevalue(&dragon2[d].genus, 0, 0, 0, 0); } dragon2_initialized = 1; Index: engine/gnugo.h =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/gnugo.h,v retrieving revision 1.70 diff -u -r1.70 gnugo.h --- engine/gnugo.h 29 Sep 2002 02:45:46 -0000 1.70 +++ engine/gnugo.h 10 Oct 2002 22:25:38 -0000 @@ -100,6 +100,11 @@ #define CAN_THREATEN_ATTACK 11 #define CAN_THREATEN_DEFENSE 12 +/* Surrounded */ + +#define SURROUNDED 1 +#define WEAKLY_SURROUNDED 2 + /* Final statuses for empty vertices. */ #define BLACK_TERRITORY 13 #define WHITE_TERRITORY 14 @@ -492,6 +497,7 @@ void decide_position(int color); void decide_eye(int pos); void decide_combination(int color); +void decide_surrounded(int pos); #endif /* _GNUGO_H_ */ Index: engine/liberty.h =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v retrieving revision 1.124 diff -u -r1.124 liberty.h --- engine/liberty.h 9 Oct 2002 18:36:23 -0000 1.124 +++ engine/liberty.h 10 Oct 2002 22:25:39 -0000 @@ -294,7 +294,6 @@ void tune_move_ordering(int params[MOVE_ORDERING_PARAMETERS]); void draw_reading_shadow(void); - /* persistent.c */ void purge_persistent_reading_cache(void); int search_persistent_reading_cache(int routine, int str, int *result, @@ -312,7 +311,6 @@ int goal_color); void owl_hotspots(float values[BOARDMAX]); - /* readconnect.c */ int string_connect(int str1, int str2, int *move); int disconnect(int str1, int str2, int *move); @@ -373,6 +371,8 @@ void movelist_change_point(int move, int code, int max_points, int points[], int codes[]); +/* safety.c */ +int surrounded(int pos, int showboard); /* functions to add (or remove) move reasons */ void clear_move_reasons(void); @@ -849,6 +849,7 @@ /* can be captured easily. */ int semeai; /* true if a dragon is part of a semeai */ int semeai_margin_of_safety; /* if small, the semeai is close */ + int surround_status; /* Is it surrounded? */ }; /* dragon2 is dynamically allocated */ Index: engine/safety.c =================================================================== RCS file: engine/safety.c diff -N engine/safety.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ engine/safety.c 10 Oct 2002 22:25:39 -0000 @@ -0,0 +1,365 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * 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 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 2 * + * * + * 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., 59 Temple Place - Suite 330, * + * Boston, MA 02111, USA. * +\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +#include +#include +#include + +#include "gnugo.h" +#include "liberty.h" + +/* Returns true if a dragon is enclosed within the convex hull of + * its hostile neighbor dragons. This is an indication that the dragon is + * in danger. Stones on the second and first lines are not tested. + * + * A CORNER is a vertex of the polygon which comprises this convex + * hull. The algorithm proceeds by first finding the sequence of + * corners on the left side of the polyhedron, then the sequence + * of corners on the right side. + * + * The hull is marked in the array mn with the number 1. A slight + * expansion is marked with the number 2. Return code is SURROUNDED if + * the friendly dragon lies within the area marked 1, + * WEAKLY_SURROUNDED if it lies in the slightly larger area marked 1 + * and 2, and 0 otherwise. + * + * An exception: if the larger area contains any stone of a different + * friendly dragon (which is not DEAD) the return code is 0, unless + * that allied dragon is ENTIRELY contained within the hull. + * + * Another exception: an ikken tobi (one space jump) is generally not + * a connection but in practice may be almost as good. If there is an + * ikken tobi out of the hull, then the dragon is not surrounded. + * + * If the parameter showboard is 1, the figure is drawn. If showboard + * is 2, the figure is only drawn if the region is surrounded. */ + +int +surrounded(int pos, int showboard) +{ + int i, j; + int m, n; + int k; + int dpos; + int surrounded; + + int left_corner[MAX_BOARD]; + int right_corner[MAX_BOARD]; + int left_corners = 0, right_corners = 0; + int top_row, bottom_row; + int color = board[pos]; + int other = OTHER_COLOR(color); + + char mf[BOARDMAX]; /* friendly dragon */ + char mn[BOARDMAX]; /* neighbor dragons */ + + memset(mf, 0, sizeof(mf)); + memset(mn, 0, sizeof(mn)); + + /* mark dragon */ + for (dpos = BOARDMIN; dpos < BOARDMAX; dpos++) + if (ON_BOARD(dpos) + && worm[dpos].origin == dpos + && is_same_dragon(dpos, pos)) + mark_string(dpos, mf, 1); + + if (DRAGON2(pos).hostile_neighbors == 0) + return(0); + + /* mark hostile neighbors */ + for (k = 0; k < DRAGON2(pos).neighbors; k++) { + int nd = DRAGON(DRAGON2(pos).adjacent[k]).origin; + + if (board[nd] != color) { + if (0) + gprintf("neighbor: %1m\n", nd); + for (dpos = BOARDMIN; dpos < BOARDMAX; dpos++) + if (ON_BOARD(dpos) + && worm[dpos].origin == dpos + && is_same_dragon(dpos, nd)) + mark_string(dpos, mn, 1); + } + } + + /* find top row of surrounding polyhedron */ + + top_row = -1; + for (m = 0; m < board_size; m++) { + if (top_row != -1) + break; + for (n = 0; n < board_size; n++) + if (mn[POS(m, n)]) { + left_corner[0] = POS(m, n); + top_row = m; + break; + } + } + /* find top row */ + + bottom_row = -1; + for (m = board_size - 1; m >= 0; m--) { + if (bottom_row != -1) + break; + for (n = 0; n < board_size; n++) + if (mn[POS(m, n)]) { + bottom_row = m; + break; + } + } + + /* find the corners on the left side */ + + for (left_corners = 1; I(left_corner[left_corners-1]) < bottom_row; + left_corners++) { + int best_found = 0; + float best_slope = 0.; + int m = I(left_corner[left_corners-1]); + int n = J(left_corner[left_corners-1]); + + for (i = m + 1; i <= bottom_row; i++) + for (j = 0; j < board_size; j++) + if (mn[POS(i, j)]) { + float slope = ((float) (j - n))/((float) (i - m)); + if (0) + gprintf("(left) at %m, last %m, slope=%f\n", i, j, m, n, slope); + + if (!best_found || slope < best_slope) { + best_found = POS(i, j); + best_slope = slope; + } + } + gg_assert(ON_BOARD(best_found)); + left_corner[left_corners] = best_found; + } + + for (n = board_size-1; n >= 0; n--) + if (mn[POS(top_row, n)]) { + right_corner[0] = POS(top_row, n); + break; + } + + /* find the corners on the left side */ + + for (right_corners = 1; I(right_corner[right_corners-1]) < bottom_row; + right_corners++) { + int best_found = 0; + float best_slope = 0.; + int m = I(right_corner[right_corners-1]); + int n = J(right_corner[right_corners-1]); + + for (i = m + 1; i <= bottom_row; i++) { + for (j = board_size - 1; j >= 0; j--) { + if (mn[POS(i, j)]) { + float slope = ((float) (j - n))/((float) (i - m)); + if (0) + gprintf("(right) at %m, last %m, slope=%f\n", i, j, m, n, slope); + if (!best_found || slope > best_slope) { + best_found = POS(i, j); + best_slope = slope; + } + } + } + } + gg_assert(ON_BOARD(best_found)); + right_corner[right_corners] = best_found; + } + + if (0) { + for (k = 0; k < left_corners; k++) + gprintf("left corner %d: %1m\n", k, left_corner[k]); + + for (k = 0; k < right_corners; k++) + gprintf("right corner %d: %1m\n", k, right_corner[k]); + } + + /* Now mark the interior of the convex hull */ + + for (n = J(left_corner[0]); n <= J(right_corner[0]); n++) + mn[POS(top_row, n)] = 1; + for (n = J(left_corner[left_corners-1]); + n <= J(right_corner[right_corners-1]); n++) + mn[POS(bottom_row, n)] = 1; + for (m = top_row+1; m < bottom_row; m++) { + int left_boundary, right_boundary; + for (k = 1; k < left_corners; k++) { + if (I(left_corner[k]) > m) { + float ti = I(left_corner[k-1]); + float tj = J(left_corner[k-1]); + float bi = I(left_corner[k]); + float bj = J(left_corner[k]); + + if (0) + gprintf("(left) %d: %1m %1m\n", + m, left_corner[k-1], left_corner[k]); + /* left edge in this row is on segment (ti,tj) -> (bi, bj) */ + + left_boundary = ceil(tj + (m - ti) * (bj - tj) / (bi - ti)); + break; + } + } + for (k = 1; k < right_corners; k++) { + if (I(right_corner[k]) > m) { + float ti = I(right_corner[k-1]); + float tj = J(right_corner[k-1]); + float bi = I(right_corner[k]); + float bj = J(right_corner[k]); + + if (0) + gprintf("(right) %d: %1m %1m\n", + m, right_corner[k-1], right_corner[k]); + right_boundary = floor(tj + (m - ti) * (bj - tj) / (bi - ti)); + break; + } + } + for (n = left_boundary; n <= right_boundary; n++) + mn[POS(m, n)] = 1; + } + + /* mark the expanded region */ + + for (dpos = BOARDMIN; dpos < BOARDMAX; dpos++) + if (ON_BOARD(dpos) && !mn[dpos] && + ((mn[NORTH(dpos)]==1) || (mn[SOUTH(dpos)]==1) + || (mn[EAST(dpos)]==1) || (mn[WEST(dpos)]==1))) + mn[dpos] = 2; + + /* Mark allied dragons that intersect the (unexpanded) hull. + * These must all lie entirely within the hull for the + * dragon to be considered surrounded. + * + * We do not use the expanded hull for this since typically the + * surrounding dragons will be in contact with other friendly + * dragons, and we do not want to consider these. + */ + + for (dpos = BOARDMIN; dpos < BOARDMAX; dpos++) + if (ON_BOARD(dpos) && (mn[dpos] == 1) + && (board[dpos] == color) && !mf[dpos]) { + int mpos; + + for (mpos = BOARDMIN; mpos < BOARDMAX; mpos++) + if (ON_BOARD(mpos) && is_same_dragon(mpos, dpos)) + mf[mpos] = 2; + } + + /* determine the surround status of the dragon */ + + surrounded = SURROUNDED; + + for (m = 0; m < board_size; m++) + for (n = 0; n < board_size; n++) { + if (mf[POS(m, n)]) { + if (mn[POS(m, n)] == 0) { + surrounded = 0; + break; + } + else if (mn[POS(m, n)] == 2) + surrounded = WEAKLY_SURROUNDED; + } + } + + /* revise the status if an ikken tobi jumps out. */ + + if (surrounded) { + for (dpos = BOARDMIN; dpos < BOARDMAX && surrounded; dpos++) + if (ON_BOARD(dpos) && mf[dpos]) { + if ((ON_BOARD(NORTH(dpos)) + && board[NORTH(dpos)] == EMPTY + && ON_BOARD(NORTH(NORTH(dpos))) + && board[NORTH(NORTH(dpos))] == color + && !mn[NORTH(NORTH(dpos))] + && ON_BOARD(EAST(NORTH(dpos))) + && board[EAST(NORTH(dpos))] != other + && ON_BOARD(WEST(NORTH(dpos))) + && board[WEST(NORTH(dpos))] != other) + || (ON_BOARD(SOUTH(dpos)) + && board[SOUTH(dpos)] == EMPTY + && ON_BOARD(SOUTH(SOUTH(dpos))) + && board[SOUTH(SOUTH(dpos))] == color + && !mn[SOUTH(SOUTH(dpos))] + && ON_BOARD(EAST(SOUTH(dpos))) + && board[EAST(SOUTH(dpos))] != other + && ON_BOARD(WEST(SOUTH(dpos))) + && board[WEST(SOUTH(dpos))] != other) + || (ON_BOARD(EAST(dpos)) + && board[EAST(dpos)] == EMPTY + && ON_BOARD(EAST(EAST(dpos))) + && board[EAST(EAST(dpos))] == color + && !mn[EAST(EAST(dpos))] + && ON_BOARD(NORTH(EAST(dpos))) + && board[NORTH(EAST(dpos))] != other + && ON_BOARD(SOUTH(EAST(dpos))) + && board[SOUTH(EAST(dpos))] != other) + || (ON_BOARD(WEST(dpos)) + && board[WEST(dpos)] == EMPTY + && ON_BOARD(WEST(WEST(dpos))) + && board[WEST(WEST(dpos))] == color + && !mn[WEST(WEST(dpos))] + && ON_BOARD(NORTH(WEST(dpos))) + && board[NORTH(WEST(dpos))] != other + && ON_BOARD(SOUTH(WEST(dpos))) + && board[SOUTH(WEST(dpos))] != other)) + surrounded = 0; + } + } + if (showboard == 1 || (showboard == 2 && surrounded)) { + start_draw_board(); + for (m = 0; m < board_size; m++) + for (n = 0; n < board_size; n++) { + int col, c; + + if (mf[POS(m,n)]) { + if (mn[POS(m,n)] ==1 ) + col = GG_COLOR_RED; + else if (mn[POS(m,n)] == 2) + col = GG_COLOR_YELLOW; + else col = GG_COLOR_GREEN; + } + else if (mn[POS(m,n)] == 1) + col = GG_COLOR_BLUE; + else if (mn[POS(m,n)] == 2) + col = GG_COLOR_CYAN; + else + col = GG_COLOR_BLACK; + if (board[POS(m, n)] == BLACK) + c = 'X'; + else if (board[POS(m, n)] == WHITE) + c = 'O'; + else if (mn[POS(m, n)]) + c = '*'; + else + c = '.'; + draw_color_char(m, n, c, col); + } + end_draw_board(); + } + + return surrounded; +} + + +/* + * Local Variables: + * tab-width: 8 + * c-basic-offset: 2 + * End: + */ Index: engine/sgfdecide.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/sgfdecide.c,v retrieving revision 1.40 diff -u -r1.40 sgfdecide.c --- engine/sgfdecide.c 9 Oct 2002 18:36:23 -0000 1.40 +++ engine/sgfdecide.c 10 Oct 2002 22:25:39 -0000 @@ -595,6 +595,31 @@ } +void +decide_surrounded(int pos) +{ + int surround_status; + + if (board[pos] == EMPTY) { + fprintf(stderr, "location must not be empty!\n"); + return; + } + + /* Prepare pattern matcher and reading code. */ + reset_engine(); + + silent_examine_position(board[pos], EXAMINE_ALL); + surround_status = surrounded(pos, 1); + if (surround_status == 1) + gprintf("the dragon at %1m is SURROUNDED!\n", pos); + else if (surround_status == 2) + gprintf("the dragon at %1m is WEAKLY SURROUNDED!\n", pos); + else + gprintf("the dragon at %1m is not surrounded.\n", pos); +} + + + /* * Local Variables: * tab-width: 8 Index: engine/value_moves.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v retrieving revision 1.61 diff -u -r1.61 value_moves.c --- engine/value_moves.c 9 Oct 2002 18:36:23 -0000 1.61 +++ engine/value_moves.c 10 Oct 2002 22:25:39 -0000 @@ -1934,10 +1934,10 @@ d1 = lunch_dragon[l]; bb = dragons[d1]; - /* FIXME: This value cannot be computed without some - * measurement of how the actual move affects the dragon. - * The dragon safety alone is not enough. The question is - * whether the dragon is threatened by the move or not. + /* FIXME: This value cannot be computed without some measurement + * of how the actual move affects the dragon. The dragon safety + * alone is not enough. The question is whether the dragon is + * threatened or defended by the move or not. */ this_value = (dragon[bb].effective_size * (1.0 - dragon_safety(bb, 0))); Index: interface/main.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/interface/main.c,v retrieving revision 1.54 diff -u -r1.54 main.c --- interface/main.c 29 Sep 2002 02:45:46 -0000 1.54 +++ interface/main.c 10 Oct 2002 22:25:39 -0000 @@ -80,6 +80,7 @@ OPT_DECIDE_DRAGON, OPT_DECIDE_DRAGON_DATA, OPT_DECIDE_SEMEAI, + OPT_DECIDE_SURROUNDED, OPT_DECIDE_TACTICAL_SEMEAI, OPT_EXPERIMENTAL_SEMEAI, OPT_EXPERIMENTAL_OWL_EXT, @@ -148,7 +149,8 @@ MODE_DECIDE_TACTICAL_SEMEAI, MODE_DECIDE_POSITION, MODE_DECIDE_EYE, - MODE_DECIDE_COMBINATION + MODE_DECIDE_COMBINATION, + MODE_DECIDE_SURROUNDED }; @@ -231,6 +233,7 @@ {"decide-semeai", required_argument, 0, OPT_DECIDE_SEMEAI}, {"decide-tactical-semeai", required_argument, 0, OPT_DECIDE_TACTICAL_SEMEAI}, {"decide-position", no_argument, 0, OPT_DECIDE_POSITION}, + {"decide-surrounded", required_argument, 0, OPT_DECIDE_SURROUNDED}, {"decide-eye", required_argument, 0, OPT_DECIDE_EYE}, {"decide-combination", no_argument, 0, OPT_DECIDE_COMBINATION}, {"nofusekidb", no_argument, 0, OPT_NOFUSEKIDB}, @@ -646,6 +649,15 @@ playmode = MODE_DECIDE_COMBINATION; break; + case OPT_DECIDE_SURROUNDED: + if (strlen(gg_optarg) > 3) { + fprintf(stderr, "Invalid board coordinate: %s\n", gg_optarg); + exit(EXIT_FAILURE); + } + strcpy(decide_this, gg_optarg); + playmode = MODE_DECIDE_SURROUNDED; + break; + case OPT_BRANCH_DEPTH: mandated_branch_depth = atoi(gg_optarg); break; @@ -1132,6 +1144,21 @@ } break; + case MODE_DECIDE_SURROUNDED: + { + int m, n; + + if (!string_to_location(board_size, decide_this, &m, &n)) { + fprintf(stderr, + "usage: --decide-surrounded [pos]\n"); + return EXIT_FAILURE; + } + + rotate(m, n, &m, &n, board_size, orientation); + decide_surrounded(POS(m, n)); + break; + } + case MODE_GTP: if (gtpfile != NULL) { gtp_input_FILE = fopen(gtpfile, "r");