/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * 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, 2003, 2004, 2005, 2006, 2007, * * 2008 and 2009 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 3 or * * (at your option) any later version. * * * * 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., 51 Franklin Street, Fifth Floor, * * Boston, MA 02111, USA. * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* ================================================================ */ /* Show status for a string, a dragon, etc in an SGF file. */ /* ================================================================ */ #include "gnugo.h" #include #include #include "liberty.h" #include "sgftree.h" /* * decide_string tries to attack and defend the string at (pos), * and then writes the number of variations considered in the attack * and defence to the sgf file. */ void decide_string(int pos) { int aa, dd; int acode, dcode; SGFTree tree; if (board[pos] == EMPTY) { fprintf(stderr, "gnugo: --decide-string called on an empty vertex\n"); return; } if (*outfilename) sgffile_begindump(&tree); /* Prepare pattern matcher and reading code. */ reset_engine(); count_variations = 1; acode = attack(pos, &aa); if (acode) { if (acode == WIN) gprintf("%1m can be attacked at %1m (%d variations)\n", pos, aa, count_variations); else if (acode == KO_A) gprintf("%1m can be attacked with ko (good) at %1m (%d variations)\n", pos, aa, count_variations); else if (acode == KO_B) gprintf("%1m can be attacked with ko (bad) at %1m (%d variations)\n", pos, aa, count_variations); if (debug & DEBUG_READING_PERFORMANCE) { gprintf("Reading shadow: \n"); draw_reading_shadow(); } count_variations = 1; dcode = find_defense(pos, &dd); if (dcode) { if (dcode == WIN) gprintf("%1m can be defended at %1m (%d variations)\n", pos, dd, count_variations); else if (dcode == KO_A) gprintf("%1m can be defended with ko (good) at %1m (%d variations)\n", pos, dd, count_variations); else if (dcode == KO_B) gprintf("%1m can be defended with ko (bad) at %1m (%d variations)\n", pos, dd, count_variations); } else gprintf("%1m cannot be defended (%d variations)\n", pos, count_variations); if (debug & DEBUG_READING_PERFORMANCE) { gprintf("Reading shadow: \n"); draw_reading_shadow(); } } else { gprintf("%1m cannot be attacked (%d variations)\n", pos, count_variations); if (debug & DEBUG_READING_PERFORMANCE) { gprintf("Reading shadow: \n"); draw_reading_shadow(); } } sgffile_enddump(outfilename); count_variations = 0; } /* * decide_connection tries to connect and disconnect the strings at * (apos) and (bpos), and then writes the number of variations * considered in the attack and defence to the sgf file. */ void decide_connection(int apos, int bpos) { int move; int result; SGFTree tree; ASSERT_ON_BOARD1(apos); ASSERT_ON_BOARD1(bpos); if (board[apos] == EMPTY || board[bpos] == EMPTY) { fprintf(stderr, "gnugo: --decide-connection called on an empty vertex\n"); return; } if (board[apos] != board[bpos]) { fprintf(stderr, "gnugo: --decide-connection called for strings of different colors\n"); return; } if (*outfilename) sgffile_begindump(&tree); /* Prepare pattern matcher and reading code. */ reset_engine(); count_variations = 1; result = string_connect(apos, bpos, &move); if (result == WIN) { if (move == NO_MOVE) gprintf("%1m and %1m are connected as it stands (%d variations)\n", apos, bpos, count_variations); else gprintf("%1m and %1m can be connected at %1m (%d variations)\n", apos, bpos, move, count_variations); } else if (result == KO_A) gprintf("%1m and %1m can be connected with ko (good) at %1m (%d variations)\n", apos, bpos, move, count_variations); else if (result == KO_B) gprintf("%1m and %1m can be connected with ko (bad) at %1m (%d variations)\n", apos, bpos, move, count_variations); else gprintf("%1m and %1m cannot be connected (%d variations)\n", apos, bpos, count_variations); count_variations = 1; result = disconnect(apos, bpos, &move); if (result == WIN) { if (move == NO_MOVE) gprintf("%1m and %1m are disconnected as it stands (%d variations)\n", apos, bpos, count_variations); else gprintf("%1m and %1m can be disconnected at %1m (%d variations)\n", apos, bpos, move, count_variations); } else if (result == KO_A) gprintf("%1m and %1m can be disconnected with ko (good) at %1m (%d variations)\n", apos, bpos, move, count_variations); else if (result == KO_B) gprintf("%1m and %1m can be disconnected with ko (bad) at %1m (%d variations)\n", apos, bpos, move, count_variations); else gprintf("%1m and %1m cannot be disconnected (%d variations)\n", apos, bpos, count_variations); sgffile_enddump(outfilename); count_variations = 0; } /* * decide_owl (formerly called decide_dragon) tries to attack and defend * the dragon at (pos), and then writes the number of variations considered * in the attack and defence to the sgf file. */ void decide_owl(int pos) { int move = NO_MOVE; int acode, dcode; SGFTree tree; int result_certain; int kworm; if (board[pos] == EMPTY) { fprintf(stderr, "gnugo: --decide-dragon called on an empty vertex\n"); return; } /* Prepare pattern matcher and reading code. */ reset_engine(); silent_examine_position(EXAMINE_DRAGONS_WITHOUT_OWL); gprintf("finished examine_position\n"); /* We want to see the reading performed, not just a result picked * from the cache. Thus we clear the cache here. */ reading_cache_clear(); if (*outfilename) sgffile_begindump(&tree); count_variations = 1; acode = owl_attack(pos, &move, &result_certain, &kworm); if (acode) { if (acode == WIN) { if (move == NO_MOVE) gprintf("%1m is dead as it stands", pos); else gprintf("%1m can be attacked at %1m (%d variations)", pos, move, count_variations); } else if (acode == KO_A) gprintf("%1m can be attacked with ko (good) at %1m (%d variations)", pos, move, count_variations); else if (acode == KO_B) gprintf("%1m can be attacked with ko (bad) at %1m (%d variations)", pos, move, count_variations); else if (acode == GAIN) gprintf("%1m can be attacked with gain (captures %1m) at %1m (%d variations)", pos, kworm, move, count_variations); } else gprintf("%1m cannot be attacked (%d variations)", pos, count_variations); if (result_certain) gprintf("\n"); else gprintf(" result uncertain\n"); reading_cache_clear(); count_variations = 1; dcode = owl_defend(pos, &move, &result_certain, &kworm); if (dcode) { if (dcode == WIN) { if (move == NO_MOVE) gprintf("%1m is alive as it stands", pos); else gprintf("%1m can be defended at %1m (%d variations)", pos, move, count_variations); } else if (dcode == KO_A) gprintf("%1m can be defended with ko (good) at %1m (%d variations)", pos, move, count_variations); else if (dcode == KO_B) gprintf("%1m can be defended with ko (bad) at %1m (%d variations)", pos, move, count_variations); else if (dcode == LOSS) gprintf("%1m can be defended with loss (loses %1m) at %1m (%d variations)", pos, kworm, move, count_variations); } else gprintf("%1m cannot be defended (%d variations)", pos, count_variations); if (result_certain) gprintf("\n"); else gprintf(" result uncertain\n"); sgffile_enddump(outfilename); count_variations = 0; } /* * decide_dragon_data prints the dragon data at (pos). */ void decide_dragon_data(int pos) { if (board[pos] == EMPTY) { fprintf(stderr, "gnugo: --decide-dragon-data called on an empty vertex\n"); return; } reset_engine(); silent_examine_position(FULL_EXAMINE_DRAGONS); gprintf("Dragon at %1m:\n", pos); report_dragon(stderr, pos); } /* Print the result of the semeai code on the semeai at apos/bpos, * optionally writing an sgf file. */ void decide_semeai(int apos, int bpos) { SGFTree tree; int resulta, resultb, move, result_certain; int color = board[apos]; if (color == EMPTY || board[bpos] != OTHER_COLOR(color)) { gprintf("gnugo: --decide-semeai called on invalid data\n"); return; } /* Prepare pattern matcher and reading code. */ reset_engine(); silent_examine_position(EXAMINE_DRAGONS_WITHOUT_OWL); gprintf("finished examine_position\n"); count_variations = 1; /* We want to see the reading performed, not just a result picked * from the cache. Thus we clear the cache here. */ reading_cache_clear(); if (*outfilename) sgffile_begindump(&tree); gprintf("Analyzing semeai between %1m and %1m, %C moves first\n", apos, bpos, board[apos]); owl_analyze_semeai(apos, bpos, &resulta, &resultb, &move, 1, &result_certain); gprintf("Semeai defense of %1m: result %s %1m\n", apos, result_to_string(resulta), move); gprintf("Semeai attack of %1m: result %s %1m\n", bpos, result_to_string(resultb), move); gprintf("%d nodes%s\n\n", count_variations, result_certain ? "" : ", uncertain result"); gprintf("Analyzing semeai between %1m and %1m, %C moves first\n", bpos, apos, board[bpos]); owl_analyze_semeai(bpos, apos, &resultb, &resulta, &move, 1, &result_certain); gprintf("Semeai defense of %1m: result %s %1m\n", bpos, result_to_string(resultb), move); gprintf("Semeai attack of %1m: result %s %1m\n", apos, result_to_string(resulta), move); gprintf("%d nodes%s\n", count_variations, result_certain ? "" : ", uncertain result"); sgffile_enddump(outfilename); count_variations = 0; } void decide_tactical_semeai(int apos, int bpos) { SGFTree tree; int resulta, resultb, move, dummy; int color = board[apos]; if (color == EMPTY || board[bpos] != OTHER_COLOR(color)) { gprintf("gnugo: --decide-semeai called on invalid data\n"); return; } /* Prepare pattern matcher and reading code. */ reset_engine(); silent_examine_position(EXAMINE_DRAGONS_WITHOUT_OWL); gprintf("finished examine_position\n"); count_variations = 1; /* We want to see the reading performed, not just a result picked * from the cache. Thus we clear the cache here. */ reading_cache_clear(); if (*outfilename) sgffile_begindump(&tree); /* FIXME: Calling status_to_string() with a result code as argument * doesn't make sense. It could be changed to result_to_string() but * the overall formatting needs change as well. */ owl_analyze_semeai(apos, bpos, &resulta, &resultb, &move, 0, &dummy); gprintf("After %s at %1m, %1m is %s, %1m is %s (%d nodes)\n", color_to_string(color), move, apos, status_to_string(resulta), bpos, status_to_string(resultb), count_variations); owl_analyze_semeai(bpos, apos, &resultb, &resulta, &move, 0, &dummy); gprintf("After %s at %1m, %1m is %s, %1m is %s (%d nodes)\n", color_to_string(color), move, apos, status_to_string(resulta), bpos, status_to_string(resultb), count_variations); sgffile_enddump(outfilename); count_variations = 0; } /* * decide_position tries to attack and defend every dragon with * dragon.escape<6 and writes the variations to an sgf file. */ void decide_position() { int pos; int move = NO_MOVE; int acode = 0, dcode = 0; int kworm; static const char *snames[] = {"dead", "alive", "critical", "unknown"}; SGFTree tree; /* Prepare pattern matcher and reading code. */ reset_engine(); silent_examine_position(EXAMINE_DRAGONS_WITHOUT_OWL); /* We want to see the reading performed, not just a result picked * from the cache. Thus we clear the cache here. */ reading_cache_clear(); if (*outfilename) sgffile_begindump(&tree); count_variations = 1; for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos) || dragon[pos].origin != pos || board[pos] == EMPTY || DRAGON2(pos).escape_route >= 6) continue; gprintf("\nanalyzing %1m\n", pos); gprintf("status=%s, escape=%d\n", snames[dragon[pos].crude_status], DRAGON2(pos).escape_route); acode = owl_attack(pos, &move, NULL, &kworm); if (acode) { if (acode == WIN) { if (move == NO_MOVE) gprintf("%1m is dead as it stands\n", pos); else gprintf("%1m can be attacked at %1m (%d variations)\n", pos, move, count_variations); } else if (acode == KO_A) gprintf("%1m can be attacked with ko (good) at %1m (%d variations)\n", pos, move, count_variations); else if (acode == KO_B) gprintf("%1m can be attacked with ko (bad) at %1m (%d variations)\n", pos, move, count_variations); else if (acode == GAIN) gprintf("%1m can be attacked with gain (captures %1m) at %1m (%d variations)", pos, kworm, move, count_variations); count_variations = 1; dcode = owl_defend(pos, &move, NULL, &kworm); if (dcode) { if (dcode == WIN) { if (move == NO_MOVE) gprintf("%1m is alive as it stands\n", pos); else gprintf("%1m can be defended at %1m (%d variations)\n", pos, move, count_variations); } else if (dcode == KO_A) gprintf("%1m can be defended with ko (good) at %1m (%d variations)\n", pos, move, count_variations); else if (dcode == KO_B) gprintf("%1m can be defended with ko (bad) at %1m (%d variations)\n", pos, move, count_variations); else if (dcode == LOSS) gprintf("%1m can be defended with loss (loses %1m) at %1m (%d variations)", pos, kworm, move, count_variations); } else gprintf("%1m cannot be defended (%d variations)\n", pos, count_variations); } else gprintf("%1m cannot be attacked (%d variations)\n", pos, count_variations); if (acode) { if (dcode) gprintf("status of %1m revised to CRITICAL\n", pos); else gprintf("status of %1m revised to DEAD\n", pos); } else gprintf("status of %1m revised to ALIVE\n", pos); } sgffile_enddump(outfilename); count_variations = 0; } /* * Evaluates the eyespace at (pos) and prints a report. You can get * more information by adding -d0x02 to the command line. */ void decide_eye(int pos) { int color; struct eyevalue value; int attack_point; int defense_point; int eyepos; SGFTree tree; reset_engine(); silent_examine_position(EXAMINE_DRAGONS_WITHOUT_OWL); color = black_eye[pos].color; if (!IS_STONE(color)) { gprintf("The eye at %1m is not of a single color.\n", pos); return; } if (printboard) showboard(0); /* Enable sgf output. */ if (*outfilename) sgffile_begindump(&tree); count_variations = 1; if (black_eye[pos].color == BLACK) { eyepos = black_eye[pos].origin; compute_eyes(eyepos, &value, &attack_point, &defense_point, black_eye, half_eye, 0); gprintf("Black eyespace at %1m: %s\n", eyepos, eyevalue_to_string(&value)); if (eye_move_urgency(&value) > 0) { gprintf(" vital points: %1m (attack) %1m (defense)\n", attack_point, defense_point); } } if (white_eye[pos].color == WHITE) { eyepos = white_eye[pos].origin; compute_eyes(eyepos, &value, &attack_point, &defense_point, white_eye, half_eye, 0); gprintf("White eyespace at %1m: %s\n", eyepos, eyevalue_to_string(&value)); if (eye_move_urgency(&value) > 0) { gprintf(" vital points: %1m (attack) %1m (defense)\n", attack_point, defense_point); } } /* Finish sgf output. */ sgffile_enddump(outfilename); count_variations = 0; } /* * decide_combination tries to find a combination attack for (color) by * calling atari_atari(). */ void decide_combination(int color) { int attack_move; signed char defense_moves[BOARDMAX]; SGFTree tree; int first = 1; int pos; /* Prepare pattern matcher and reading code. */ reset_engine(); silent_examine_position(EXAMINE_ALL); if (*outfilename) sgffile_begindump(&tree); count_variations = 1; if (atari_atari(color, &attack_move, defense_moves, verbose)) { gprintf("Combination attack for %C at %1m, defense at ", color, attack_move); for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (ON_BOARD(pos) && defense_moves[pos]) { if (first) first = 0; else gprintf(", "); gprintf("%1m", pos); } } gprintf("\n"); } else gprintf("No Combination attack for %C\n", color); sgffile_enddump(outfilename); count_variations = 0; } 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(EXAMINE_ALL); surround_status = compute_surroundings(pos, NO_MOVE, 1, NULL); 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); } #if ORACLE void decide_oracle(Gameinfo *gameinfo, char *infilename, char *untilstring) { SGFTree tree; reset_engine(); if (*outfilename) sgffile_begindump(&tree); count_variations = 1; summon_oracle(); oracle_loadsgf(infilename, untilstring); consult_oracle(gameinfo->to_move); sgffile_enddump(outfilename); dismiss_oracle(); count_variations = 0; } #endif /* * Local Variables: * tab-width: 8 * c-basic-offset: 2 * End: */