[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnugo-devel] Simple patch
From: |
Inge Wallin |
Subject: |
[gnugo-devel] Simple patch |
Date: |
Sat, 10 Nov 2001 23:21:18 +0100 (MET) |
Here is a very simple patch, but I am afraid that it is all I am
capable right now with my fever. The patch is against the CVS as it
looked today at 12 o'clock Swedish time (abt 12 hours ago).
Summary:
- atari_atari moved to combination.c
- restricted_defend1 and restricted attack2 now public functions
- bugfix in find_double_threats: remove threat reasons after remaking
them into an attack_either reason
- old disabled function remove_move_reason() now enabled
- some simple cleaning
- genmove now 1D
- Some tests in endgame.tst corrected.
-Inge
================================================================
diff -ur gnugo-sync/engine/combination.c gnugo-iw/engine/combination.c
--- gnugo-sync/engine/combination.c Sat Nov 10 12:18:23 2001
+++ gnugo-iw/engine/combination.c Sat Nov 10 21:56:28 2001
@@ -25,7 +25,6 @@
* especially, combinations of threats.
*/
-/* FIXME: Move much of atari_atari here. */
#include "liberty.h"
#include "gnugo.h"
@@ -88,13 +87,14 @@
ii = POS(i, j);
/* Generate ATTACK_EITHER_MOVE move reasons for each pair of the
- * threatened strings.
+ * threatened strings. We must also remove the threats, because
+ * otherwise we would get followup points for them also.
*
* FIXME:
* - This is perhaps not the best way to do it, but realistically
* it will be seldom that more than two strings are threatened
* at the same point. Still, we should find a better way.
- * - attack_either_move should be generalized to more than two strings.
+ * - ATTACK_EITHER_MOVE should be generalized to more than two strings.
*/
num_a_threatened_groups = get_attack_threats(ii, MAX_THREATENED_STRINGS,
a_threatened_groups);
@@ -113,14 +113,20 @@
*/
if (board[a_threatened_groups[k]] == EMPTY
|| board[a_threatened_groups[l]] == EMPTY) {
- if (!attack(ii, NULL))
+ if (!attack(ii, NULL)) {
add_attack_either_move(ii, a_threatened_groups[k],
a_threatened_groups[l]);
+ remove_attack_threat_move(ii, a_threatened_groups[k]);
+ remove_attack_threat_move(ii, a_threatened_groups[l]);
+ }
}
else if (!defend_both(a_threatened_groups[k],
- a_threatened_groups[l]))
+ a_threatened_groups[l])) {
add_attack_either_move(ii, a_threatened_groups[k],
a_threatened_groups[l]);
+ remove_attack_threat_move(ii, a_threatened_groups[k]);
+ remove_attack_threat_move(ii, a_threatened_groups[l]);
+ }
}
popgo();
}
@@ -136,6 +142,524 @@
* - combinations of breakins into enemy territory
*/
}
+
+
+/* ================================================================ */
+/* Combination attacks */
+/* ================================================================ */
+
+
+/* atari_atari(color, *move) looks for a series of ataris on
+ * strings of the other color culminating in the capture of
+ * a string which is thought to be invulnerable by the reading
+ * code. Such a move can be missed since it may be that each
+ * string involved individually can be rescued, but nevertheless
+ * one of them can be caught. The simplest example is a double
+ * atari. The return value is the size of the smallest opponent
+ * worm.
+ *
+ * One danger with this scheme is that the first atari
+ * tried might be irrelevant to the actual combination.
+ * To detect this possibility, once we've found a combination,
+ * we mark that first move as forbidden, then try again. If
+ * no combination of the same size or larger turns up, then
+ * the first move was indeed essential.
+ *
+ * For the purpose of the move generation, returns the
+ * size of the smallest of the worms under attack.
+ */
+
+static int aa_status[BOARDMAX]; /* ALIVE, DEAD or CRITICAL */
+static int forbidden[BOARDMAX];
+static void compute_aa_status(int color);
+static int get_aa_status(int pos);
+static int do_atari_atari(int color, int *attack_point,
+ int *defense_point, int cpos,
+ int save_verbose, int minsize);
+
+/* Set to 1 if you want verbose traces from this function. */
+
+int
+atari_atari(int color, int *move, int save_verbose)
+{
+ int fpos;
+ int aa_val;
+
+ /* Collect worm statuses of opponent's worms. We need to
+ * know this because we only want to report unexpected
+ * results. For example, we do not want to report success
+ * if we find we can kill a worm which is already dead.
+ * The worm status of empty points is set to UNKNOWN to signal
+ * that stones added along the way need special attention.
+ */
+ if (aa_depth < 2)
+ return 0;
+ memset(forbidden, 0, sizeof(forbidden));
+
+ compute_aa_status(color);
+
+ aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
+ save_verbose, 0);
+
+ if (aa_val == 0)
+ return 0;
+
+ /* We try excluding the first atari found and see if the
+ * combination still works. Repeat until failure.
+ */
+ while (1) {
+ int new_aa_val;
+ forbidden[fpos] = 1;
+ new_aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
+ save_verbose, aa_val);
+
+ /* The last do_atari_atari call fails. When do_atari_atari fails,
+ * it does not change the value of (fpos), so these correspond
+ * to a move that works and is necessary.
+ */
+ if (new_aa_val == 0) {
+ if (move) *move = fpos;
+ return aa_val;
+ }
+ aa_val = new_aa_val;
+ }
+
+ /* We'll never get here, but the compiler may be more happy if it
+ * looks like we're returning something.
+ */
+ return 0;
+}
+
+
+/* Helper function for computing the aa_status for a string. */
+static void
+compute_aa_status(int color)
+{
+ int other = OTHER_COLOR(color);
+ int pos;
+ /* Collect worm statuses of opponent's worms. We need to
+ * know this because we only want to report unexpected
+ * results. For example, we do not want to report success
+ * if we find we can kill a worm which is already dead.
+ * The worm status of empty points is set to UNKNOWN to signal
+ * that stones added along the way need special attention.
+ */
+ for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+ if (board[pos] == other) {
+ if (dragon[pos].matcher_status == DEAD)
+ aa_status[pos] = DEAD;
+ else if (worm[pos].attack_codes[0] != 0) {
+ if (worm[pos].defend_codes[0] != 0)
+ aa_status[pos] = CRITICAL;
+ else
+ aa_status[pos] = DEAD;
+ }
+ else
+ aa_status[pos] = ALIVE;
+ }
+ else if(ON_BOARD(pos))
+ aa_status[pos] = UNKNOWN;
+ }
+
+ /* reclassify a worm with 2 liberties as INSUBSTANTIAL if capturing
+ * it does not result in a live group.
+ */
+ for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+ if (board[pos] == other
+ && worm[pos].origin == pos
+ && worm[pos].liberties == 2
+ && aa_status[pos] == ALIVE
+ && !owl_substantial(pos)) {
+ int pos2;
+ for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++)
+ if (ON_BOARD(pos2) && is_worm_origin(pos2, pos))
+ aa_status[pos2] = INSUBSTANTIAL;
+ }
+ }
+
+ if (debug & DEBUG_ATARI_ATARI) {
+ gprintf("compute_aa_status() for %C\n", color);
+ gprintf("aa_status: (ALIVE worms not listed)\n");
+ for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
+ if (board[pos] == other && is_worm_origin(pos, pos)) {
+ const char *status = "UNKNOWN (shouldn't happen)";
+ if (aa_status[pos] == DEAD)
+ status = "DEAD";
+ else if (aa_status[pos] == CRITICAL)
+ status = "CRITICAL";
+ else if (aa_status[pos] == INSUBSTANTIAL)
+ status = "INSUBSTANTIAL";
+
+ if (aa_status[pos] != ALIVE)
+ gprintf("%1M: %s\n", pos, status);
+ }
+ }
+ }
+}
+
+/* Helper function for retrieving the aa_status for a string. We can't
+ * reliably do this simply by looking up aa_status[pos] since this is
+ * only valid at vertices which were non-empty at the start of the
+ * reading. For later added stones, we need to find their aa_status by
+ * locating a part of the string which was a worm at the beginning of
+ * the reading.
+ */
+static int
+get_aa_status(int pos)
+{
+ int stones[MAX_BOARD * MAX_BOARD];
+ int num_stones;
+ int k;
+
+ if (aa_status[pos] != UNKNOWN)
+ return aa_status[pos];
+
+ num_stones = findstones(pos, MAX_BOARD * MAX_BOARD, stones);
+ for (k = 0; k < num_stones; k++)
+ if (aa_status[stones[k]] != UNKNOWN)
+ return aa_status[stones[k]];
+
+ return UNKNOWN;
+}
+
+
+/* Helper function for atari_atari. Here worms is the number of
+ * opponent worms involved in the combination, and (last_friendly) is
+ * the location of the last friendly move played. Moves marked
+ * with the forbidden array are not tried. If no move is found,
+ * the values of *attack_point and *defense_point are not changed.
+ *
+ * If not NULL, *attack_point is left pointing to the location of the
+ * attacking move, and *defense_point points to a move defending the
+ * combination. In rare cases a defensive move might not be found. If
+ * a non-static function calling do_atari_atari gets a return value of
+ * 1 but NO_MOVE as the defense point, this should be treated as
+ * equivalent to a return value of 0.
+ */
+
+static int
+do_atari_atari(int color, int *attack_point, int *defense_point,
+ int last_friendly, int save_verbose, int minsize)
+{
+ int m, n;
+ int k;
+
+ int other = OTHER_COLOR(color);
+
+ if (debug & DEBUG_ATARI_ATARI) {
+ gprintf("%odo_atari_atari: ");
+ dump_stack();
+ gprintf("%oforbidden moves: ");
+ for (m = 0; m < board_size; m++)
+ for (n = 0; n < board_size; n++) {
+ if (forbidden[POS(m, n)])
+ gprintf("%o%1m ", POS(m, n));
+ }
+ gprintf("\n");
+ }
+
+ /* First look for strings adjacent to the last friendly move played
+ * (or to another stone in the same string) which can be
+ * unexpectedly attacked.
+ */
+ if (last_friendly != NO_MOVE)
+ for (m = 0; m < board_size; m++)
+ for (n = 0; n < board_size; n++) {
+ int pos = POS(m, n);
+ int apos;
+
+ if (board[pos] != other)
+ continue;
+
+ if (pos != find_origin(pos))
+ continue;
+
+ if (minsize > 0 && countstones(pos) < minsize)
+ continue;
+
+ if (get_aa_status(pos) != ALIVE)
+ continue;
+
+ if (board[last_friendly] != EMPTY
+ && !adjacent_strings(last_friendly, pos))
+ continue;
+
+ if (board[last_friendly] == EMPTY
+ && !liberty_of_string(last_friendly, pos))
+ continue;
+
+ if (debug & DEBUG_ATARI_ATARI)
+ gprintf("Considering attack of %1m. depth = %d.\n", pos, depth);
+ if (attack(pos, &apos)) {
+ if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
+ gprintf("%oThe worm %1m can be attacked at %1m after ", pos, apos);
+ dump_stack();
+ }
+ if (attack_point) *attack_point = apos;
+
+ /* We look for a move defending the combination.
+ * Normally this is found by find_defense but failing
+ * that, if the attacking move is a safe move for color,
+ * it probably defends.
+ */
+ if (defense_point) {
+ if (!find_defense(pos, defense_point)) {
+ if (safe_move(apos, other)) {
+ *defense_point = apos;
+ }
+ /* No defense is found */
+ else {
+ *defense_point = NO_MOVE;
+ }
+ }
+ }
+
+ DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%1m)\n",
+ countstones(pos), pos);
+ return countstones(pos);
+ }
+ }
+
+ if (stackp > aa_depth)
+ return 0;
+
+ /* Next look for a string, not insubstantial, having exactly two
+ * liberties and no boundary stones in atari. Atari, fill, then try
+ * again. If that doesn't work, try the other atari.
+ */
+ for (m = 0; m < board_size; m++)
+ for (n = 0; n < board_size; n++) {
+ int pos = POS(m, n);
+ int libs[2];
+ int status;
+
+ if (board[pos] != other)
+ continue;
+
+ if (pos != find_origin(pos))
+ continue;
+
+ if (minsize > 0 && countstones(pos) < minsize)
+ continue;
+
+ status = get_aa_status(pos);
+ if (status != ALIVE)
+ continue;
+
+ if (findlib(pos, 2, libs) != 2)
+ continue;
+
+ for (k = 0; k < 2; k++) {
+ int apos = libs[k];
+ int bpos;
+
+ if (!forbidden[apos]
+ && (accurate_approxlib(apos, color, 2, NULL) > 1
+ || safe_move(apos, color))) {
+ if (trymove(apos, color, "do_atari_atari-A", pos,
+ EMPTY, NO_MOVE)) {
+ /* try to defend the stone (m,n) which is in atari */
+ int aa_val = 0;
+
+ /* Because we know (m, n) is in atari there is a trivial
+ * attack and we can be sure find_defense() will give a
+ * useful defense point if it returns non-zero. Usually we
+ * would need to call attack_and_defend() to be certain of
+ * this.
+ *
+ * On the other hand, if there is no defense we have
+ * already been successful.
+ */
+ if (find_defense(pos, &bpos)
+ && trymove(bpos, other, "do_atari_atari-B", pos,
+ EMPTY, NO_MOVE)) {
+ /* These moves may have been irrelevant for later
+ * reading, so in order to avoid horizon problems, we
+ * need to temporarily increase the depth values.
+ */
+ increase_depth_values();
+ increase_depth_values();
+ aa_val = do_atari_atari(color, NULL, defense_point,
+ apos, save_verbose, minsize);
+ decrease_depth_values();
+ decrease_depth_values();
+ popgo();
+ }
+ else {
+ /* No way to save the ataried stone. We have been successful. */
+ popgo();
+ if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
+ gprintf("%oThe worm %m can be attacked at %1m after ", m, n,
+ apos);
+ dump_stack();
+ }
+ if (attack_point) *attack_point = apos;
+ if (defense_point && !find_defense(pos, defense_point))
+ *defense_point = NO_MOVE;
+
+ DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%m)\n",
+ countstones(pos), m, n);
+ return countstones(pos);
+ }
+
+ if (aa_val) {
+ /* The atari at (ai,aj) seems to work but we still
+ * must check there is not a better defense.
+ */
+ int cpos;
+ int res = restricted_defend1(pos, &cpos, EMPTY, 0,
+ 1, &bpos);
+ if (res) {
+ if (trymove(cpos, other, "do_atari_atari-C",
+ pos, EMPTY, NO_MOVE)) {
+ increase_depth_values();
+ increase_depth_values();
+ if (!do_atari_atari(color, NULL, defense_point,
+ apos, save_verbose, minsize))
+ aa_val = 0;
+ decrease_depth_values();
+ decrease_depth_values();
+ popgo();
+ }
+ }
+ if (aa_val) {
+ if (attack_point) *attack_point = apos;
+ popgo();
+ DEBUG(DEBUG_ATARI_ATARI,
+ "%oreturn value:%d (min %d, %d (%m))\n",
+ gg_min(aa_val, countstones(pos)), aa_val,
+ countstones(pos), m, n);
+ /* If no defense point is known and (ai,aj) is a safe
+ * move for other, it probably defends the combination.
+ */
+ if (defense_point
+ && (*defense_point == NO_MOVE
+ || !safe_move(*defense_point, other))
+ && safe_move(apos, other)) {
+ *defense_point = apos;
+ }
+ return gg_min(aa_val, countstones(pos));
+ }
+ }
+ popgo();
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/* Ask the atari_atari code whether there appears any combination
+ * attack which would capture at least minsize stones after playing at
+ * (tpos). If this happens, (*move) points to a move which prevents
+ * this blunder.
+ *
+ * FIXME: Most of the code below is common with atari_atari() and
+ * should be broken out of both functions.
+ */
+int
+atari_atari_confirm_safety(int color, int tpos, int *move, int minsize)
+{
+ int fpos;
+ int defense_point = NO_MOVE, after_defense_point = NO_MOVE;
+ int aa_val, after_aa_val;
+ int other = OTHER_COLOR(color);
+
+ /* If aa_depth is too small, we can't see any combination attacks,
+ * so in this respect the move is safe enough.
+ */
+ if (aa_depth < 2)
+ return 1;
+
+ memset(forbidden, 0, sizeof(forbidden));
+
+ compute_aa_status(other);
+
+ /* Accept illegal ko capture here. */
+ if (!tryko(tpos, color, NULL, EMPTY, NO_MOVE))
+ /* Really shouldn't happen. */
+ abortgo(__FILE__, __LINE__, "trymove", I(tpos), J(tpos));
+ increase_depth_values();
+
+ aa_val = do_atari_atari(other, &fpos, &defense_point,
+ NO_MOVE, 0, minsize);
+ after_aa_val = aa_val;
+
+ if (aa_val == 0 || defense_point == NO_MOVE) {
+
+ /* No sufficiently large combination attack, so the move is safe from
+ * this danger.
+ *
+ * On rare occasions do_atari_atari might find a combination
+ * but no defense. In this case we assume that the combination
+ * is illusory.
+ */
+
+ popgo();
+ decrease_depth_values();
+ return 1;
+ }
+
+ while (aa_val >= after_aa_val) {
+ /* Try dropping moves from the combination and see if it still
+ * works. What we really want is to get the proper defense move
+ * into (*move).
+ */
+ after_defense_point = defense_point;
+ forbidden[fpos] = 1;
+ aa_val = do_atari_atari(other, &fpos, &defense_point,
+ NO_MOVE, 0, aa_val);
+ }
+
+ popgo();
+ decrease_depth_values();
+ /* We know that a combination exists, but we don't know if
+ * the original move at (aa) was really relevant. So we
+ * try omitting it and see if a combination is still found.
+ */
+ if (do_atari_atari(other, NULL, NULL, NO_MOVE, 0, minsize) >= after_aa_val)
+ return 1;
+ else {
+ if (move) *move = after_defense_point;
+ return 0;
+ }
+}
+
+
+/* Ask the atari_atari code if after color plays at (apos)
+ * and other plays at (bpos) there appears any combination
+ * attack. Returns the size of the combination.
+ *
+ * FIXME: Most of the code below is common with atari_atari() and
+ * should be broken out of both functions.
+ */
+
+int
+atari_atari_try_combination(int color, int apos, int bpos)
+{
+ int other = OTHER_COLOR(color);
+ int aa_val = 0;
+ int save_verbose = verbose;
+
+ if (aa_depth < 2)
+ return 0;
+ if (verbose > 0)
+ verbose--;
+ memset(forbidden, 0, sizeof(forbidden));
+
+ compute_aa_status(color);
+
+ if (trymove(apos, color, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
+ if (trymove(bpos, other, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
+ aa_val = do_atari_atari(color, NULL, NULL, apos, 0, 0);
+ popgo();
+ }
+ popgo();
+ }
+ verbose = save_verbose;
+ return aa_val;
+}
+
/*
* Local Variables:
Only in gnugo-iw/engine: combination.o
diff -ur gnugo-sync/engine/dragon.c gnugo-iw/engine/dragon.c
--- gnugo-sync/engine/dragon.c Sat Nov 10 12:18:23 2001
+++ gnugo-iw/engine/dragon.c Sat Nov 10 21:57:47 2001
@@ -97,8 +97,8 @@
"Initialising dragon from worm at %1m, size %d\n",
ii, worm[ii].size);
}
-
time_report(2, " time to initialize dragons", -1, -1, 1.0);
+
make_domains(black_eye, white_eye, 0);
time_report(2, " time to make domains", -1, -1, 1.0);
@@ -196,7 +196,6 @@
}
}
}
-
time_report(2, " time to find lunches", -1, -1, 1.0);
/* In case origins of dragons got moved, put the dragons of eyes aright. */
@@ -338,7 +337,6 @@
}
}
}
-
time_report(2, " time to compute genus", -1, -1, 1.0);
/* Compute the escape route measure. */
@@ -351,7 +349,6 @@
DRAGON2(ii).escape_route = compute_escape(ii, 0);
}
}
-
time_report(2, " time to compute escape", -1, -1, 1.0);
/* Update the segmentation of the initial influence before we
@@ -506,7 +503,6 @@
time_report(3, " owl reading for dragon at ", m, n, 1.0);
}
}
-
time_report(2, " owl reading", -1, -1, 1.0);
/* The dragon data is now correct at the origin of each dragon but
@@ -543,7 +539,6 @@
dragon[ii].matcher_status = dragon[ii].status;
}
}
-
time_report(2, " compute matcher status", -1, -1, 1.0);
/* Compute the safety value. */
@@ -590,7 +585,6 @@
else
dragon2[d].safety = ALIVE;
}
-
time_report(2, " compute dragon safety", -1, -1, 1.0);
/* Resolve semeais. This may revise the safety and status fields. */
@@ -637,7 +631,6 @@
}
}
}
-
time_report(2, " revise inessentiality", -1, -1, 1.0);
/* Count the non-dead dragons. */
Only in gnugo-iw/engine: dragon.o
Only in gnugo-iw/engine: filllib.o
Only in gnugo-iw/engine: fuseki.o
diff -ur gnugo-sync/engine/genmove.c gnugo-iw/engine/genmove.c
--- gnugo-sync/engine/genmove.c Sat Nov 10 12:18:23 2001
+++ gnugo-iw/engine/genmove.c Sat Nov 10 22:20:13 2001
@@ -35,7 +35,7 @@
#define NEEDS_UPDATE(x) (x != position_number ? (x = position_number, 1) : 0)
static int get_level(int *level);
-static int do_genmove(int *i, int *j, int color, float pure_threat_value);
+static int do_genmove(int *move, int color, float pure_threat_value);
static double slowest_time = 0.;
static int slowest_i = -1;
@@ -219,7 +219,15 @@
int
genmove(int *i, int *j, int color)
{
- return do_genmove(i, j, color, 0.4);
+ int move;
+ int retval;
+
+ retval = do_genmove(&move, color, 0.4);
+
+ if (i) *i = I(move);
+ if (j) *j = J(move);
+
+ return retval;
}
@@ -231,9 +239,16 @@
int
genmove_conservative(int *i, int *j, int color)
{
- return do_genmove(i, j, color, 0.0);
-}
+ int move;
+ int retval;
+ retval = do_genmove(&move, color, 0.4);
+
+ if (i) *i = I(move);
+ if (j) *j = J(move);
+
+ return retval;
+}
/*
@@ -241,10 +256,9 @@
*/
static int
-do_genmove(int *i, int *j, int color, float pure_threat_value)
+do_genmove(int *move, int color, float pure_threat_value)
{
float val;
- int move;
int save_verbose;
start_timer(0);
@@ -261,8 +275,7 @@
stats.hash_collisions = 0;
/* no move is found yet. */
- *i = -1;
- *j = -1;
+ *move = NO_MOVE;
val = -1;
if (get_level(&level))
fprintf(stderr, "level = %d\n", level);
@@ -356,9 +369,9 @@
gg_assert(stackp == 0);
/* Review the move reasons and estimate move values. */
- if (review_move_reasons(i, j, &val, color,
+ if (review_move_reasons(move, &val, color,
pure_threat_value, lower_bound))
- TRACE("Move generation likes %m with value %f\n", *i, *j, val);
+ TRACE("Move generation likes %1m with value %f\n", *move, val);
gg_assert(stackp == 0);
time_report(1, "review move reasons", -1, -1, 1.0);
@@ -366,8 +379,8 @@
if (val <= 6.0 && !disable_endgame_patterns) {
endgame_shapes(color);
gg_assert(stackp == 0);
- if (review_move_reasons(i, j, &val, color, pure_threat_value, score))
- TRACE("Move generation likes %m with value %f\n", *i, *j, val);
+ if (review_move_reasons(move, &val, color, pure_threat_value, score))
+ TRACE("Move generation likes %1m with value %f\n", *move, val);
gg_assert(stackp == 0);
time_report(1, "endgame", -1, -1, 1.0);
}
@@ -380,9 +393,9 @@
if (revise_semeai(color)) {
shapes(color);
endgame_shapes(color);
- if (review_move_reasons(i, j, &val, color, pure_threat_value, score)) {
- TRACE("Upon reconsideration move generation likes %m with value %f\n",
- *i, *j, val);
+ if (review_move_reasons(move, &val, color, pure_threat_value, score)) {
+ TRACE("Upon reconsideration move generation likes %1m with value %f\n",
+ *move, val);
}
}
time_report(1, "move reasons with revised semeai status", -1, -1, 1.0);
@@ -392,12 +405,10 @@
* all missing dame points.
*/
if (val < 0.0
- && fill_liberty(&move, color)) {
+ && fill_liberty(move, color)) {
val = 1.0;
TRACE("Filling a liberty at %1m\n", move);
- *i = I(move);
- *j = J(move);
- move_considered(*i, *j, val);
+ move_considered(I(*move), J(*move), val);
time_report(1, "fill liberty", -1, -1, 1.0);
}
@@ -407,12 +418,10 @@
if (val < 0.0
&& !doing_scoring
&& (play_out_aftermath || capture_all_dead)
- && aftermath_genmove(&move, color, NULL, 0) > 0) {
- *i = I(move);
- *j = J(move);
+ && aftermath_genmove(move, color, NULL, 0) > 0) {
val = 1.0;
- TRACE("Aftermath move at %m\n", *i, *j);
- move_considered(*i, *j, val);
+ TRACE("Aftermath move at %1m\n", *move);
+ move_considered(I(*move), J(*move), val);
time_report(1, "aftermath_genmove", -1, -1, 1.0);
}
@@ -422,23 +431,20 @@
if (val < 0.0
&& !doing_scoring
&& capture_all_dead
- && aftermath_genmove(&move, color, NULL, 1) > 0) {
- *i = I(move);
- *j = J(move);
+ && aftermath_genmove(move, color, NULL, 1) > 0) {
val = 1.0;
- TRACE("Aftermath move at %m\n", *i, *j);
- move_considered(*i, *j, val);
+ TRACE("Aftermath move at %1m\n", *move);
+ move_considered(I(*move), J(*move), val);
time_report(1, "aftermath_genmove", -1, -1, 1.0);
}
/* If no move is found then pass. */
if (val < 0.0) {
TRACE("I pass.\n");
- *i = -1;
- *j = -1;
+ *move = NO_MOVE;
}
else
- TRACE("genmove() recommends %m with value %f\n", *i, *j, val);
+ TRACE("genmove() recommends %1m with value %f\n", *move, val);
/* If statistics is turned on, this is the place to show it. */
if (showstatistics) {
@@ -451,15 +457,16 @@
}
if (showtime) {
- double spent = time_report(0, "TIME to generate move at ", *i, *j, 1.0);
+ double spent = time_report(0, "TIME to generate move at ",
+ I(*move), J(*move), 1.0);
total_time += spent;
if (spent > slowest_time) {
slowest_time = spent;
- slowest_i = *i;
- slowest_j = *j;
+ slowest_i = I(*move);
+ slowest_j = J(*move);
slowest_movenum = movenum+1;
}
- if (*i == -1) {
+ if (*move == NO_MOVE) {
gprintf("\nSLOWEST MOVE: %d at %m ", slowest_movenum,
slowest_i, slowest_j);
fprintf(stderr, "(%.2f seconds)\n", slowest_time);
@@ -472,8 +479,7 @@
}
return val;
-
-} /* end genmove */
+}
/* This is called for each move which has been considered. For
Only in gnugo-iw/engine: genmove.o
Only in gnugo-iw/engine: globals.o
Only in gnugo-iw/engine: hash.o
Only in gnugo-iw/engine: influence.o
Only in gnugo-iw/engine: interface.o
Only in gnugo-iw/engine: libboard.a
Only in gnugo-iw/engine: libengine.a
diff -ur gnugo-sync/engine/liberty.h gnugo-iw/engine/liberty.h
--- gnugo-sync/engine/liberty.h Sat Nov 10 12:18:26 2001
+++ gnugo-iw/engine/liberty.h Sat Nov 10 22:06:48 2001
@@ -226,6 +226,12 @@
int attack_either(int astr, int bstr);
int defend_both(int astr, int bstr);
int break_through(int apos, int bpos, int cpos);
+
+int restricted_defend1(int str, int *move, int komaster, int kom_pos,
+ int num_forbidden_moves, int *forbidden_moves);
+int restricted_attack2(int str, int *move, int komaster, int kom_pos,
+ int num_forbidden_moves, int *forbidden_moves);
+
int naive_ladder(int str, int *move);
#define MOVE_ORDERING_PARAMETERS 67
void tune_move_ordering(int params[MOVE_ORDERING_PARAMETERS]);
@@ -287,6 +293,7 @@
void add_attack_move(int pos, int ww, int code);
void add_defense_move(int pos, int ww, int code);
void add_attack_threat_move(int pos, int ww, int code);
+void remove_attack_threat_move(int pos, int ww);
void add_defense_threat_move(int pos, int ww, int code);
int get_attack_threats(int pos, int max_strings, int strings[]);
int get_defense_threats(int pos, int max_strings, int strings[]);
@@ -363,7 +370,7 @@
int minsize);
int atari_atari_try_combination(int color, int apos, int bpos);
-int review_move_reasons(int *i, int *j, float *val, int color,
+int review_move_reasons(int *move, float *val, int color,
float pure_threat_value, float lower_bound);
int fill_liberty(int *move, int color);
int aftermath_genmove(int *aftermath_move, int color,
Only in gnugo-iw/engine: life.o
Only in gnugo-iw/engine: matchpat.o
diff -ur gnugo-sync/engine/move_reasons.c gnugo-iw/engine/move_reasons.c
--- gnugo-sync/engine/move_reasons.c Sat Nov 10 12:18:47 2001
+++ gnugo-iw/engine/move_reasons.c Sat Nov 10 22:20:12 2001
@@ -356,7 +356,6 @@
move[pos].reason[k] = find_reason(type, what);
}
-#if 0
/*
* Remove a move reason for (pos). Ignore silently if the reason
* wasn't there.
@@ -387,7 +386,7 @@
move[pos].reason[n] = move[pos].reason[k];
move[pos].reason[k] = -1;
}
-#endif
+
/*
* Check whether a move reason already is recorded for a move.
@@ -510,6 +509,15 @@
add_move_reason(pos, ATTACK_THREAT_MOVE, worm_number);
}
+void
+remove_attack_threat_move(int pos, int ww)
+{
+ int worm_number = find_worm(worm[ww].origin);
+
+ ASSERT_ON_BOARD1(ww);
+ remove_move_reason(pos, ATTACK_THREAT_MOVE, worm_number);
+}
+
/*
* Add to the reasons for the move at (pos) that it defends the worm
* at (ww).
@@ -1128,7 +1136,7 @@
int unstable_worms[MAX_WORMS];
int N = 0; /* number of unstable worms */
int m, n;
- int pos;
+ int ii;
int k;
int other = OTHER_COLOR(color);
@@ -1136,24 +1144,27 @@
/* Identify the unstable worms and store them in a list. */
for (m = 0; m < board_size; m++)
- for (n = 0; n <board_size; n++)
- if (BOARD(m, n)
- && worm[POS(m, n)].origin == POS(m, n)
- && worm[POS(m, n)].attack_codes[0] != 0
- && worm[POS(m, n)].defend_codes[0] != 0) {
- unstable_worms[N] = find_worm(POS(m, n));
+ for (n = 0; n <board_size; n++) {
+ ii = POS(m, n);
+
+ if (board[ii]
+ && worm[ii].origin == ii
+ && worm[ii].attack_codes[0] != 0
+ && worm[ii].defend_codes[0] != 0) {
+ unstable_worms[N] = find_worm(ii);
N++;
}
+ }
/* To avoid horizon effects, we temporarily increase the depth values. */
increase_depth_values();
for (m = 0; m < board_size; m++)
for (n = 0; n < board_size; n++) {
- pos = POS(m, n);
+ ii = POS(m, n);
for (k = 0; k < MAX_REASONS; k++) {
- int r = move[pos].reason[k];
+ int r = move[ii].reason[k];
int what;
if (r < 0)
@@ -1172,12 +1183,12 @@
break;
}
- if (k<MAX_REASONS && move[pos].reason[k] != -1) {
- /* Try the move at (pos) and see what happens. */
+ if (k<MAX_REASONS && move[ii].reason[k] != -1) {
+ /* Try the move at (ii) and see what happens. */
int cursor_at_start_of_line = 0;
- TRACE("%1m ", pos);
- if (trymove(pos, color, "find_more_attack_and_defense_moves",
+ TRACE("%1m ", ii);
+ if (trymove(ii, color, "find_more_attack_and_defense_moves",
NO_MOVE, EMPTY, NO_MOVE)) {
for (k = 0; k < N; k++) {
int aa = worms[unstable_worms[k]];
@@ -1186,21 +1197,21 @@
* unless we already know the move works as defense move.
*/
if (board[aa] == color
- && !defense_move_reason_known(pos, unstable_worms[k]))
+ && !defense_move_reason_known(ii, unstable_worms[k]))
if (!attack(aa, NULL)) {
if (!cursor_at_start_of_line)
TRACE("\n");
TRACE("%ofound extra point of defense of %1m at %1m\n",
- aa, pos);
+ aa, ii);
cursor_at_start_of_line = 1;
- add_defense_move(pos, aa, WIN);
+ add_defense_move(ii, aa, WIN);
}
/* string of opponent color, see if there still is a defense,
* unless we already know the move works as attack move.
*/
if (board[aa] == other
- && !attack_move_reason_known(pos, unstable_worms[k]))
+ && !attack_move_reason_known(ii, unstable_worms[k]))
if (!find_defense(aa, NULL)) {
/* Maybe find_defense() doesn't find the defense. Try to
* defend with the stored defense move.
@@ -1219,9 +1230,9 @@
if (!cursor_at_start_of_line)
TRACE("\n");
TRACE("%ofound extra point of attack of %1m at %1m\n",
- aa, pos);
+ aa, ii);
cursor_at_start_of_line = 1;
- add_attack_move(pos, aa, WIN);
+ add_attack_move(ii, aa, WIN);
}
}
}
@@ -2182,12 +2193,12 @@
static float cautious_impact_values[10][10] = {
/* (bi, bj) DEAD ALIV CRIT INES TACT WEAK WE_A SEKI STRO INVI */
/* DEAD */ {0.3, 0.9, 0.0, 0.0, 0.0, 0.8, 0.85,0.8, 0.95,1.0 },
-/* ALIVE */ {0.0, 0.2, 0.05,0.0, 0.0, 0.1,0.15,0.10, 0.2 ,0.2 },
+/* ALIVE */ {0.0, 0.2, 0.05,0.0, 0.0, 0.1,0.15, 0.10,0.2 ,0.2 },
/* CRITICAL */ {0.0, 1.04,0.85,0.0, 0.0, 0.75,0.9, 0.85,1.08,1.1 },
/* INESSENTIAL */ {0.1, 0.6, 0.0, 0.0, 0.0, 0.3, 0.5, 0.5, 0.6, 0.6 },
/* TACT. DEAD */ {0.2, 0.9, 0.0, 0.0, 0.0, 0.8, 0.85,0.8, 0.95,1.0 },
/* WEAK */ {0.1, 0.6, 0.25,0.0, 0.0, 0.2, 0.25,0.25,0.65,0.65},
-/* WEAK ALIVE */ {0.0, 0.4, 0.3, 0.0, 0.0, 0.2,0.2, 0.2 ,0.45,0.45},
+/* WEAK ALIVE */ {0.0, 0.4, 0.3, 0.0, 0.0, 0.2, 0.2, 0.2 ,0.45,0.45},
/* SEKI */ {0.0, 0.2, 0.15,0.0, 0.0, 0.1, 0.15,0.2, 0.25,0.3 },
/* STR. ALIVE */ {0.0, 0.02,0.01,0.0, 0.0, 0.01,0.01,0.01,0.02,0.02},
/* INVINCIBLE */ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }};
@@ -2371,7 +2382,7 @@
if (DRAGON2(aa).safety == INESSENTIAL || worm[aa].inessential) {
DEBUG(DEBUG_MOVE_REASONS,
- " %1m: 0 - attack on %1m (inessential)\n", pos, aa);
+ " %1m: 0.0 - attack on %1m (inessential)\n", pos, aa);
break;
}
@@ -3280,8 +3291,7 @@
* substantial enough that capturing it saves the strategically
* attacked dragon.
*/
- if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE)
- {
+ if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE) {
int s;
for (s = 0; s < DRAGON2(aa).neighbors; s++) {
@@ -3418,7 +3428,6 @@
int strings = 0;
int own_strings = 0;
int k, l;
- int oo;
int fewlibs = 0;
for (k = 0; k < 4; k++) {
@@ -3429,14 +3438,13 @@
continue;
origin = find_origin(ii);
- oo = origin;
for (l = 0; l < strings; l++)
- if (ss[l] == oo)
+ if (ss[l] == origin)
break;
if (l == strings) {
- ss[strings] = oo;
+ ss[strings] = origin;
strings++;
}
}
@@ -3698,14 +3706,14 @@
* captures here though, because if that is the best move, we
* should reevaluate ko threats.
*/
- if (!(is_illegal_ko_capture(pos, color) || is_legal(pos, color))) {
- move[pos].value = 0.0;
- TRACE("Move at %1m wasn't legal.\n", pos);
- }
- else {
+ if (is_legal(pos, color) || is_illegal_ko_capture(pos, color)) {
/* Add a random number between 0 and 0.01 to use in comparisons. */
move[pos].value += 0.01 * move[pos].random_number;
}
+ else {
+ move[pos].value = 0.0;
+ TRACE("Move at %1m wasn't legal.\n", pos);
+ }
}
}
@@ -3786,10 +3794,11 @@
for (m = 0; m < board_size; m++)
for (n = 0; n < board_size; n++) {
pos = POS(m, n);
- ii = replacement_map[pos];
+ ii = replacement_map[pos];
if (ii == NO_MOVE)
continue;
+
TRACE("Redistributing points from %1m to %1m.\n", pos, ii);
if (move[ii].final_value < move[pos].final_value) {
TRACE("%1m is now valued %f.\n", ii, move[pos].final_value);
@@ -3809,10 +3818,11 @@
* misevaluated the dangers or because the opponent misplays.
*/
int
-review_move_reasons(int *i, int *j, float *val, int color,
+review_move_reasons(int *the_move, float *val, int color,
float pure_threat_value, float score)
{
int m, n;
+ int ii;
float tval;
float bestval = 0.0;
int best_move = NO_MOVE;
@@ -3860,7 +3870,6 @@
* moves and print them.
*/
print_top_moves();
-
while (!good_move_found) {
bestval = 0.0;
best_move = NO_MOVE;
@@ -3868,20 +3877,22 @@
/* Search through all board positions for the highest valued move. */
for (m = 0; m < board_size; m++)
for (n = 0; n < board_size; n++) {
- if (move[POS(m, n)].final_value == 0.0)
+ ii = POS(m, n);
+
+ if (move[ii].final_value == 0.0)
continue;
- tval = move[POS(m, n)].value;
+ tval = move[ii].value;
if (tval > bestval) {
- if (is_legal(POS(m, n), color) || is_illegal_ko_capture(POS(m, n),
color)) {
+ if (is_legal(ii, color) || is_illegal_ko_capture(ii, color)) {
bestval = tval;
- best_move = POS(m, n);
+ best_move = ii;
}
else {
- TRACE("Move at %m would be suicide.\n", m, n);
- move[POS(m, n)].value = 0.0;
- move[POS(m, n)].final_value = 0.0;
+ TRACE("Move at %1m would be suicide.\n", ii);
+ move[ii].value = 0.0;
+ move[ii].final_value = 0.0;
}
}
}
@@ -3932,9 +3943,8 @@
if (bestval > 0.0
&& best_move != NO_MOVE) {
+ *the_move = best_move;
*val = bestval;
- *i = I(best_move);
- *j = J(best_move);
return 1;
}
else
Only in gnugo-iw/engine: move_reasons.o
Only in gnugo-iw/engine: optics.o
Only in gnugo-iw/engine: owl.o
Only in gnugo-iw/engine: printutils.o
Only in gnugo-iw/engine: readconnect.o
diff -ur gnugo-sync/engine/reading.c gnugo-iw/engine/reading.c
--- gnugo-sync/engine/reading.c Sat Nov 3 19:11:45 2001
+++ gnugo-iw/engine/reading.c Sat Nov 10 22:18:01 2001
@@ -76,8 +76,6 @@
static int do_find_defense(int str, int *move, int komaster, int kom_pos);
static int defend1(int str, int *move, int komaster, int kom_pos);
-static int restricted_defend1(int str, int *move, int komaster, int kom_pos,
- int num_forbidden_moves, int *forbidden_moves);
static int defend2(int str, int *move, int komaster, int kom_pos);
static int defend3(int str, int *move, int komaster, int kom_pos);
static int defend4(int str, int *move, int komaster, int kom_pos);
@@ -94,8 +92,6 @@
static int do_attack(int str, int *move, int komaster, int kom_pos);
static int attack1(int str, int *move, int komaster, int kom_pos);
static int attack2(int str, int *move, int komaster, int kom_pos);
-static int restricted_attack2(int str, int *move, int komaster, int kom_pos,
- int num_forbidden_moves, int *forbidden_moves);
static int attack3(int str, int *move, int komaster, int kom_pos);
static int attack4(int str, int *move, int komaster, int kom_pos);
static int find_cap2(int str, int alib, int blib, int *move,
@@ -762,522 +758,6 @@
}
-/* ================================================================ */
-/* Global reading functions */
-/* ================================================================ */
-
-/* atari_atari(color, *move) looks for a series of ataris on
- * strings of the other color culminating in the capture of
- * a string which is thought to be invulnerable by the reading
- * code. Such a move can be missed since it may be that each
- * string involved individually can be rescued, but nevertheless
- * one of them can be caught. The simplest example is a double
- * atari. The return value is the size of the smallest opponent
- * worm.
- *
- * One danger with this scheme is that the first atari
- * tried might be irrelevant to the actual combination.
- * To detect this possibility, once we've found a combination,
- * we mark that first move as forbidden, then try again. If
- * no combination of the same size or larger turns up, then
- * the first move was indeed essential.
- *
- * For the purpose of the move generation, returns the
- * size of the smallest of the worms under attack.
- */
-
-static int aa_status[BOARDMAX]; /* ALIVE, DEAD or CRITICAL */
-static int forbidden[BOARDMAX];
-static void compute_aa_status(int color);
-static int get_aa_status(int pos);
-static int do_atari_atari(int color, int *attack_point,
- int *defense_point, int cpos,
- int save_verbose, int minsize);
-
-/* Set to 1 if you want verbose traces from this function. */
-
-int
-atari_atari(int color, int *move, int save_verbose)
-{
- int fpos;
- int aa_val;
-
- /* Collect worm statuses of opponent's worms. We need to
- * know this because we only want to report unexpected
- * results. For example, we do not want to report success
- * if we find we can kill a worm which is already dead.
- * The worm status of empty points is set to UNKNOWN to signal
- * that stones added along the way need special attention.
- */
- if (aa_depth < 2)
- return 0;
- memset(forbidden, 0, sizeof(forbidden));
-
- compute_aa_status(color);
-
- aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
- save_verbose, 0);
-
- if (aa_val == 0)
- return 0;
-
- /* We try excluding the first atari found and see if the
- * combination still works. Repeat until failure.
- */
- while (1) {
- int new_aa_val;
- forbidden[fpos] = 1;
- new_aa_val = do_atari_atari(color, &fpos, NULL, NO_MOVE,
- save_verbose, aa_val);
-
- /* The last do_atari_atari call fails. When do_atari_atari fails,
- * it does not change the value of (fpos), so these correspond
- * to a move that works and is necessary.
- */
- if (new_aa_val == 0) {
- if (move) *move = fpos;
- return aa_val;
- }
- aa_val = new_aa_val;
- }
-
- /* We'll never get here, but the compiler may be more happy if it
- * looks like we're returning something.
- */
- return 0;
-}
-
-
-/* Helper function for computing the aa_status for a string. */
-static void
-compute_aa_status(int color)
-{
- int other = OTHER_COLOR(color);
- int pos;
- /* Collect worm statuses of opponent's worms. We need to
- * know this because we only want to report unexpected
- * results. For example, we do not want to report success
- * if we find we can kill a worm which is already dead.
- * The worm status of empty points is set to UNKNOWN to signal
- * that stones added along the way need special attention.
- */
- for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
- if (board[pos] == other) {
- if (dragon[pos].matcher_status == DEAD)
- aa_status[pos] = DEAD;
- else if (worm[pos].attack_codes[0] != 0) {
- if (worm[pos].defend_codes[0] != 0)
- aa_status[pos] = CRITICAL;
- else
- aa_status[pos] = DEAD;
- }
- else
- aa_status[pos] = ALIVE;
- }
- else if(ON_BOARD(pos))
- aa_status[pos] = UNKNOWN;
- }
-
- /* reclassify a worm with 2 liberties as INSUBSTANTIAL if capturing
- * it does not result in a live group.
- */
- for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
- if (board[pos] == other
- && worm[pos].origin == pos
- && worm[pos].liberties == 2
- && aa_status[pos] == ALIVE
- && !owl_substantial(pos)) {
- int pos2;
- for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++)
- if (ON_BOARD(pos2) && is_worm_origin(pos2, pos))
- aa_status[pos2] = INSUBSTANTIAL;
- }
- }
-
- if (debug & DEBUG_ATARI_ATARI) {
- gprintf("compute_aa_status() for %C\n", color);
- gprintf("aa_status: (ALIVE worms not listed)\n");
- for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
- if (board[pos] == other && is_worm_origin(pos, pos)) {
- const char *status = "UNKNOWN (shouldn't happen)";
- if (aa_status[pos] == DEAD)
- status = "DEAD";
- else if (aa_status[pos] == CRITICAL)
- status = "CRITICAL";
- else if (aa_status[pos] == INSUBSTANTIAL)
- status = "INSUBSTANTIAL";
-
- if (aa_status[pos] != ALIVE)
- gprintf("%1M: %s\n", pos, status);
- }
- }
- }
-}
-
-/* Helper function for retrieving the aa_status for a string. We can't
- * reliably do this simply by looking up aa_status[pos] since this is
- * only valid at vertices which were non-empty at the start of the
- * reading. For later added stones, we need to find their aa_status by
- * locating a part of the string which was a worm at the beginning of
- * the reading.
- */
-static int
-get_aa_status(int pos)
-{
- int stones[MAX_BOARD * MAX_BOARD];
- int num_stones;
- int k;
-
- if (aa_status[pos] != UNKNOWN)
- return aa_status[pos];
-
- num_stones = findstones(pos, MAX_BOARD * MAX_BOARD, stones);
- for (k = 0; k < num_stones; k++)
- if (aa_status[stones[k]] != UNKNOWN)
- return aa_status[stones[k]];
-
- return UNKNOWN;
-}
-
-
-/* Helper function for atari_atari. Here worms is the number of
- * opponent worms involved in the combination, and (last_friendly) is
- * the location of the last friendly move played. Moves marked
- * with the forbidden array are not tried. If no move is found,
- * the values of *attack_point and *defense_point are not changed.
- *
- * If not NULL, *attack_point is left pointing to the location of the
- * attacking move, and *defense_point points to a move defending the
- * combination. In rare cases a defensive move might not be found. If
- * a non-static function calling do_atari_atari gets a return value of
- * 1 but NO_MOVE as the defense point, this should be treated as
- * equivalent to a return value of 0.
- */
-
-static int
-do_atari_atari(int color, int *attack_point, int *defense_point,
- int last_friendly, int save_verbose, int minsize)
-{
- int m, n;
- int k;
-
- int other = OTHER_COLOR(color);
-
- if (debug & DEBUG_ATARI_ATARI) {
- gprintf("%odo_atari_atari: ");
- dump_stack();
- gprintf("%oforbidden moves: ");
- for (m = 0; m < board_size; m++)
- for (n = 0; n < board_size; n++) {
- if (forbidden[POS(m, n)])
- gprintf("%o%1m ", POS(m, n));
- }
- gprintf("\n");
- }
-
- /* First look for strings adjacent to the last friendly move played
- * (or to another stone in the same string) which can be
- * unexpectedly attacked.
- */
- if (last_friendly != NO_MOVE)
- for (m = 0; m < board_size; m++)
- for (n = 0; n < board_size; n++) {
- int pos = POS(m, n);
- int apos;
-
- if (board[pos] != other)
- continue;
-
- if (pos != find_origin(pos))
- continue;
-
- if (minsize > 0 && countstones(pos) < minsize)
- continue;
-
- if (get_aa_status(pos) != ALIVE)
- continue;
-
- if (board[last_friendly] != EMPTY
- && !adjacent_strings(last_friendly, pos))
- continue;
-
- if (board[last_friendly] == EMPTY
- && !liberty_of_string(last_friendly, pos))
- continue;
-
- if (debug & DEBUG_ATARI_ATARI)
- gprintf("Considering attack of %1m. depth = %d.\n", pos, depth);
- if (attack(pos, &apos)) {
- if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
- gprintf("%oThe worm %1m can be attacked at %1m after ", pos, apos);
- dump_stack();
- }
- if (attack_point) *attack_point = apos;
-
- /* We look for a move defending the combination.
- * Normally this is found by find_defense but failing
- * that, if the attacking move is a safe move for color,
- * it probably defends.
- */
- if (defense_point) {
- if (!find_defense(pos, defense_point)) {
- if (safe_move(apos, other)) {
- *defense_point = apos;
- }
- /* No defense is found */
- else {
- *defense_point = NO_MOVE;
- }
- }
- }
-
- DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%1m)\n",
- countstones(pos), pos);
- return countstones(pos);
- }
- }
-
- if (stackp > aa_depth)
- return 0;
-
- /* Next look for a string, not insubstantial, having exactly two
- * liberties and no boundary stones in atari. Atari, fill, then try
- * again. If that doesn't work, try the other atari.
- */
- for (m = 0; m < board_size; m++)
- for (n = 0; n < board_size; n++) {
- int pos = POS(m, n);
- int libs[2];
- int status;
-
- if (board[pos] != other)
- continue;
-
- if (pos != find_origin(pos))
- continue;
-
- if (minsize > 0 && countstones(pos) < minsize)
- continue;
-
- status = get_aa_status(pos);
- if (status != ALIVE)
- continue;
-
- if (findlib(pos, 2, libs) != 2)
- continue;
-
- for (k = 0; k < 2; k++) {
- int apos = libs[k];
- int bpos;
-
- if (!forbidden[apos]
- && (accurate_approxlib(apos, color, 2, NULL) > 1
- || safe_move(apos, color))) {
- if (trymove(apos, color, "do_atari_atari-A", pos,
- EMPTY, NO_MOVE)) {
- /* try to defend the stone (m,n) which is in atari */
- int aa_val = 0;
-
- /* Because we know (m, n) is in atari there is a trivial
- * attack and we can be sure find_defense() will give a
- * useful defense point if it returns non-zero. Usually we
- * would need to call attack_and_defend() to be certain of
- * this.
- *
- * On the other hand, if there is no defense we have
- * already been successful.
- */
- if (find_defense(pos, &bpos)
- && trymove(bpos, other, "do_atari_atari-B", pos,
- EMPTY, NO_MOVE)) {
- /* These moves may have been irrelevant for later
- * reading, so in order to avoid horizon problems, we
- * need to temporarily increase the depth values.
- */
- increase_depth_values();
- increase_depth_values();
- aa_val = do_atari_atari(color, NULL, defense_point,
- apos, save_verbose, minsize);
- decrease_depth_values();
- decrease_depth_values();
- popgo();
- }
- else {
- /* No way to save the ataried stone. We have been successful. */
- popgo();
- if (save_verbose || (debug & DEBUG_ATARI_ATARI)) {
- gprintf("%oThe worm %m can be attacked at %1m after ", m, n,
- apos);
- dump_stack();
- }
- if (attack_point) *attack_point = apos;
- if (defense_point && !find_defense(pos, defense_point))
- *defense_point = NO_MOVE;
-
- DEBUG(DEBUG_ATARI_ATARI, "%oreturn value:%d (%m)\n",
- countstones(pos), m, n);
- return countstones(pos);
- }
-
- if (aa_val) {
- /* The atari at (ai,aj) seems to work but we still
- * must check there is not a better defense.
- */
- int cpos;
- int res = restricted_defend1(pos, &cpos, EMPTY, 0,
- 1, &bpos);
- if (res) {
- if (trymove(cpos, other, "do_atari_atari-C",
- pos, EMPTY, NO_MOVE)) {
- increase_depth_values();
- increase_depth_values();
- if (!do_atari_atari(color, NULL, defense_point,
- apos, save_verbose, minsize))
- aa_val = 0;
- decrease_depth_values();
- decrease_depth_values();
- popgo();
- }
- }
- if (aa_val) {
- if (attack_point) *attack_point = apos;
- popgo();
- DEBUG(DEBUG_ATARI_ATARI,
- "%oreturn value:%d (min %d, %d (%m))\n",
- gg_min(aa_val, countstones(pos)), aa_val,
- countstones(pos), m, n);
- /* If no defense point is known and (ai,aj) is a safe
- * move for other, it probably defends the combination.
- */
- if (defense_point
- && (*defense_point == NO_MOVE
- || !safe_move(*defense_point, other))
- && safe_move(apos, other)) {
- *defense_point = apos;
- }
- return gg_min(aa_val, countstones(pos));
- }
- }
- popgo();
- }
- }
- }
- }
- return 0;
-}
-
-/* Ask the atari_atari code whether there appears any combination
- * attack which would capture at least minsize stones after playing at
- * (tpos). If this happens, (*move) points to a move which prevents
- * this blunder.
- *
- * FIXME: Most of the code below is common with atari_atari() and
- * should be broken out of both functions.
- */
-int
-atari_atari_confirm_safety(int color, int tpos, int *move, int minsize)
-{
- int fpos;
- int defense_point = NO_MOVE, after_defense_point = NO_MOVE;
- int aa_val, after_aa_val;
- int other = OTHER_COLOR(color);
-
- /* If aa_depth is too small, we can't see any combination attacks,
- * so in this respect the move is safe enough.
- */
- if (aa_depth < 2)
- return 1;
-
- memset(forbidden, 0, sizeof(forbidden));
-
- compute_aa_status(other);
-
- /* Accept illegal ko capture here. */
- if (!tryko(tpos, color, NULL, EMPTY, NO_MOVE))
- /* Really shouldn't happen. */
- abortgo(__FILE__, __LINE__, "trymove", I(tpos), J(tpos));
- increase_depth_values();
-
- aa_val = do_atari_atari(other, &fpos, &defense_point,
- NO_MOVE, 0, minsize);
- after_aa_val = aa_val;
-
- if (aa_val == 0 || defense_point == NO_MOVE) {
-
- /* No sufficiently large combination attack, so the move is safe from
- * this danger.
- *
- * On rare occasions do_atari_atari might find a combination
- * but no defense. In this case we assume that the combination
- * is illusory.
- */
-
- popgo();
- decrease_depth_values();
- return 1;
- }
-
- while (aa_val >= after_aa_val) {
- /* Try dropping moves from the combination and see if it still
- * works. What we really want is to get the proper defense move
- * into (*move).
- */
- after_defense_point = defense_point;
- forbidden[fpos] = 1;
- aa_val = do_atari_atari(other, &fpos, &defense_point,
- NO_MOVE, 0, aa_val);
- }
-
- popgo();
- decrease_depth_values();
- /* We know that a combination exists, but we don't know if
- * the original move at (aa) was really relevant. So we
- * try omitting it and see if a combination is still found.
- */
- if (do_atari_atari(other, NULL, NULL, NO_MOVE, 0, minsize) >= after_aa_val)
- return 1;
- else {
- if (move) *move = after_defense_point;
- return 0;
- }
-}
-
-
-/* Ask the atari_atari code if after color plays at (apos)
- * and other plays at (bpos) there appears any combination
- * attack. Returns the size of the combination.
- *
- * FIXME: Most of the code below is common with atari_atari() and
- * should be broken out of both functions.
- */
-
-int
-atari_atari_try_combination(int color, int apos, int bpos)
-{
- int other = OTHER_COLOR(color);
- int aa_val = 0;
- int save_verbose = verbose;
-
- if (aa_depth < 2)
- return 0;
- if (verbose > 0)
- verbose--;
- memset(forbidden, 0, sizeof(forbidden));
-
- compute_aa_status(color);
-
- if (trymove(apos, color, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
- if (trymove(bpos, other, NULL, NO_MOVE, EMPTY, NO_MOVE)) {
- aa_val = do_atari_atari(color, NULL, NULL, apos, 0, 0);
- popgo();
- }
- popgo();
- }
- verbose = save_verbose;
- return aa_val;
-}
-
-
/* ================================================================ */
/* Defensive functions */
/* ================================================================ */
@@ -4956,6 +4436,7 @@
/* Restricted Attack and Defense */
/* ================================================================ */
+
/* These functions try to attack and defend a string, avoiding moves
* from a certain set. It is assumed that as soon as the string gets
* three liberties, it is alive.
@@ -4979,7 +4460,7 @@
* move that defends the string (str) with one liberty,
* not considering moves from the list.
*/
-static int
+int
restricted_defend1(int str, int *move, int komaster, int kom_pos,
int num_forbidden_moves, int *forbidden_moves)
{
@@ -5109,7 +4590,7 @@
* move that attacks the string (str) with two liberties,
* not considering moves from the list.
*/
-static int
+int
restricted_attack2(int str, int *move, int komaster, int kom_pos,
int num_forbidden_moves, int *forbidden_moves)
{
@@ -5197,7 +4678,10 @@
return 0;
}
-/* Returns true if the move is in a given list of moves. */
+
+/*
+ * Returns true if the move is in a given list of moves.
+ */
static int
in_list(int move, int num_moves, int *moves)
diff -ur gnugo-sync/regression/endgame.tst gnugo-iw/regression/endgame.tst
--- gnugo-sync/regression/endgame.tst Sat Nov 10 15:37:00 2001
+++ gnugo-iw/regression/endgame.tst Sat Nov 10 16:38:08 2001
@@ -17,9 +17,10 @@
103 gg_genmove black
#? [G9]
+# E7 has slightly worse shape but does the job as well as E8 or D8
loadsgf games/endgame1.sgf 4
104 gg_genmove white
-#? [E8|D8]
+#? [E8|D8|E7]
loadsgf games/endgame1.sgf 5
105 gg_genmove black
@@ -30,13 +31,14 @@
#? [G1|H1|F3]
# J3 is 0 points double sente.
+# Double sente?? White can't play there. /iw
loadsgf games/endgame1.sgf 7
107 gg_genmove black
-#? [J3|A7]*
+#? [J3|A7]
loadsgf games/endgame1.sgf 8
108 gg_genmove white
-#? [G1]
+#? [G1|H1]
loadsgf games/endgame1.sgf 9
109 gg_genmove black
- [gnugo-devel] Simple patch,
Inge Wallin <=