Index: engine/liberty.h =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v retrieving revision 1.200 diff -u -r1.200 liberty.h --- engine/liberty.h 24 Aug 2003 03:04:11 -0000 1.200 +++ engine/liberty.h 30 Aug 2003 06:06:03 -0000 @@ -865,6 +865,7 @@ int semeai_defense_certain; int semeai_attack_point; /* Move found by semeai code to kill dragon */ int semeai_attack_certain; + int semeai_target; /* The opponent dragon involved in the semeai */ enum dragon_status owl_threat_status; /* CAN_THREATEN_ATTACK/DEFENSE */ enum dragon_status owl_status; /* (ALIVE, DEAD, UNKNOWN, CRITICAL, UNCHECKED) */ int owl_attack_point; /* vital point for attack */ Index: engine/semeai.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/semeai.c,v retrieving revision 1.60 diff -u -r1.60 semeai.c --- engine/semeai.c 10 Aug 2003 17:56:51 -0000 1.60 +++ engine/semeai.c 30 Aug 2003 06:06:03 -0000 @@ -143,6 +143,7 @@ int attack_move = PASS_MOVE; int defense_certain = 0; int attack_certain = 0; + int semeai_target = 0; for (d2 = 0; d2 < num_dragons; d2++) { if (semeai_results_first[d1][d2] == -1) @@ -156,6 +157,7 @@ best_defense = semeai_results_first[d1][d2]; defense_move = semeai_move[d1][d2]; defense_certain = semeai_certain[d1][d2]; + semeai_target = dragon2[d2].origin; } if (best_attack < semeai_results_second[d2][d1] || (best_attack == semeai_results_second[d2][d1] @@ -163,6 +165,7 @@ best_attack = semeai_results_second[d2][d1]; attack_move = semeai_move[d2][d1]; attack_certain = semeai_certain[d2][d1]; + semeai_target = dragon2[d2].origin; } } @@ -174,6 +177,7 @@ dragon2[d1].semeai_defense_certain = defense_certain; dragon2[d1].semeai_attack_point = attack_move; dragon2[d1].semeai_attack_certain = attack_certain; + dragon2[d1].semeai_target = semeai_target; } else if (best_attack == 0 && attack_certain) update_status(DRAGON(d1).origin, ALIVE, ALIVE); @@ -182,6 +186,27 @@ } +/* liberty_of_dragon(pos, origin) returns true if the vertex at (pos) is a + * liberty of the dragon with origin at (origin). + */ +static int +liberty_of_dragon(int pos, int origin) +{ + int k; + if (pos == NO_MOVE) + return 0; + + if (board[pos] != EMPTY) + return 0; + + for (k = 0; k < 4; k++) + if (ON_BOARD(pos + delta[k]) && dragon[pos + delta[k]].origin == origin) + return 1; + + return 0; +} + + /* This function adds the semeai related move reasons, using the information * stored in the dragon2 array. * @@ -193,6 +218,10 @@ { int other = OTHER_COLOR(color); int d; + int liberties; + int libs[MAXLIBS]; + int r; + int resulta, resultb, semeai_move, s_result_certain; for (d = 0; d < number_of_dragons; d++) if (dragon2[d].semeai && DRAGON(d).status == CRITICAL) { @@ -201,18 +230,77 @@ && (dragon2[d].owl_defense_point == NO_MOVE || dragon2[d].semeai_defense_certain >= dragon2[d].owl_defense_certain)) { + /* My dragon can be defended */ add_semeai_move(dragon2[d].semeai_defense_point, dragon2[d].origin); DEBUG(DEBUG_SEMEAI, "Adding semeai defense move for %1m at %1m\n", DRAGON(d).origin, dragon2[d].semeai_defense_point); + if (liberty_of_dragon(dragon2[d].semeai_defense_point, + dragon2[d].semeai_target) + && !liberty_of_dragon(dragon2[d].semeai_defense_point, + dragon2[d].origin) + && !is_self_atari(dragon2[d].semeai_defense_point, color)) { + + /* If this is a move to fill the non-common liberties of the + * target, and is not a ko or snap-back, then we try all + * non-common liberties of the target and add all winning + * moves to the move list. + */ + + liberties = findlib(dragon2[d].semeai_target, MAXLIBS, libs); + + for (r = 0; r < liberties; r++) { + if (!liberty_of_dragon(libs[r], dragon2[d].origin) + && !is_self_atari(libs[r], color) + && libs[r] != dragon2[d].semeai_defense_point) { + owl_analyze_semeai_after_move(libs[r], color, + dragon2[d].semeai_target, + dragon2[d].origin, + &resulta, &resultb, &semeai_move, + 1, &s_result_certain); + if (resulta == 0 && resultb == 0) { + add_semeai_move(libs[r], dragon2[d].origin); + DEBUG(DEBUG_SEMEAI, + "Adding semeai defense move for %1m at %1m\n", + DRAGON(d).origin, libs[r]); + } + } + } + } } else if (DRAGON(d).color == other && dragon2[d].semeai_attack_point && (dragon2[d].owl_attack_point == NO_MOVE || dragon2[d].semeai_attack_certain >= dragon2[d].owl_attack_certain)) { + /* Your dragon can be attacked */ add_semeai_move(dragon2[d].semeai_attack_point, dragon2[d].origin); DEBUG(DEBUG_SEMEAI, "Adding semeai attack move for %1m at %1m\n", DRAGON(d).origin, dragon2[d].semeai_attack_point); + if (liberty_of_dragon(dragon2[d].semeai_attack_point, + dragon2[d].origin) + && !liberty_of_dragon(dragon2[d].semeai_attack_point, + dragon2[d].semeai_target) + && !is_self_atari(dragon2[d].semeai_attack_point, color)) { + + liberties = findlib(dragon2[d].origin, MAXLIBS, libs); + + for (r = 0; r < liberties; r++) { + if (!liberty_of_dragon(libs[r], dragon2[d].semeai_target) + && !is_self_atari(libs[r], color) + && libs[r] != dragon2[d].semeai_attack_point) { + owl_analyze_semeai_after_move(libs[r], color, dragon2[d].origin, + dragon2[d].semeai_target, + &resulta, &resultb, &semeai_move, + 1, &s_result_certain); + if (resulta == 0 && resultb == 0) { + add_semeai_move(libs[r], dragon2[d].origin); + DEBUG(DEBUG_SEMEAI, + "Adding semeai attack move for %1m at %1m\n", + DRAGON(d).origin, libs[r]); + } + } + } + } } } }