- get_influence() revised - list_move_reasons() revised and made global - new functions print_all_move_values() and prepare_move_influence_debugging() - delta_territory cache can be disabled in estimate_territorial_value() - new GTP commands all_move_values, eye_data, half_eye_data, move_reasons - GTP command influence replaced by initial_influence, move_influence, and followup_influence - GTP command clear_cache now also clears the non-persistent cache Index: doc/gtp-commands.texi =================================================================== RCS file: /cvsroot/gnugo/gnugo/doc/gtp-commands.texi,v retrieving revision 1.18 diff -u -r1.18 gtp-commands.texi --- doc/gtp-commands.texi 24 Aug 2003 02:57:09 -0000 1.18 +++ doc/gtp-commands.texi 18 Nov 2003 08:51:20 -0000 @@ -1211,42 +1211,39 @@ @end example -@cindex influence -@item influence +@cindex initial_influence +@item initial_influence @example - Function: Return information about the influence function. - Arguments: color to move + Function: Return information about the initial influence function. + Arguments: color to move, what information Fails: never Returns: Influence data formatted like: - white: 0.51 1.34 3.20 6.60 9.09 8.06 1.96 0.00 0.00 0.45 1.65 4.92 12.19 17.47 15.92 4.03 0.00 0.00 . . . 0.00 0.00 0.00 0.00 0.00 100.00 75.53 41.47 23.41 - black: - 1.57 2.51 4.10 3.10 3.60 4.54 8.32 4.15 2.71 - 2.96 4.62 9.18 5.47 5.89 10.88 20.54 10.19 4.08 - . - . - . - 100.00 139.39 100.00 139.39 100.00 0.00 0.00 0.00 0.00 - territory value: - . - . - . - regions: - -1 0 0 1 1 0 -1 -3 -3 - . - . - . - -3 -3 -3 -3 -3 3 3 3 3 - The encoding of the regions is as follows: + The available choices of information are: + + white_influence (float) + black_influence (float) + white_strength (float) + black_strength (float) + white_attenuation (float) + black_attenuation (float) + white_permeability (float) + black_permeability (float) + territory_value (float) + influence_regions (int) + non_territory (int) + + The encoding of influence_regions is as follows: + 4 white stone 3 white territory 2 white moyo 1 white area @@ -1254,6 +1251,31 @@ -1 black area -2 black moyo -3 black territory + -4 black stone + +@end example + +@cindex move_influence +@item move_influence + +@example + + Function: Return information about the influence function after a move. + Arguments: move, what information + Fails: never + Returns: Influence data formatted like for initial_influence. + +@end example + +@cindex followup_influence +@item followup_influence + +@example + + Function: Return information about the followup influence after a move. + Arguments: move, what information + Fails: never + Returns: Influence data formatted like for initial_influence. @end example @@ -1343,6 +1365,30 @@ Arguments: the location Fails: if called on an empty or off-board location Returns: list of stones + +@end example + +@cindex eye_data +@item eye_data + +@example + + Function: Return the information in the eye data structure. + Arguments: color, vertex + Fails: never + Returns: eye data fields and values, one pair per row + +@end example + +@cindex half_eye_data +@item half_eye_data + +@example + + Function: Return the information in the half eye data structure. + Arguments: vertex + Fails: never + Returns: half eye data fields and values, one pair per row @end example Index: engine/influence.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/influence.c,v retrieving revision 1.97 diff -u -r1.97 influence.c --- engine/influence.c 13 Nov 2003 22:48:41 -0000 1.97 +++ engine/influence.c 18 Nov 2003 08:51:22 -0000 @@ -2121,14 +2121,29 @@ get_influence(const struct influence_data *q, float white_influence[BOARDMAX], float black_influence[BOARDMAX], + float white_strength[BOARDMAX], + float black_strength[BOARDMAX], + float white_attenuation[BOARDMAX], + float black_attenuation[BOARDMAX], + float white_permeability[BOARDMAX], + float black_permeability[BOARDMAX], float territory_value[BOARDMAX], - int influence_regions[BOARDMAX]) + int influence_regions[BOARDMAX], + int non_territory[BOARDMAX]) { int ii; + for (ii = BOARDMIN; ii < BOARDMAX; ii++) { white_influence[ii] = q->white_influence[ii]; black_influence[ii] = q->black_influence[ii]; + white_strength[ii] = q->white_strength[ii]; + black_strength[ii] = q->black_strength[ii]; + white_attenuation[ii] = q->white_attenuation[ii]; + black_attenuation[ii] = q->black_attenuation[ii]; + white_permeability[ii] = q->white_permeability[ii]; + black_permeability[ii] = q->black_permeability[ii]; territory_value[ii] = q->territory_value[ii]; + non_territory[ii] = q->non_territory[ii]; if (board[ii] == EMPTY) { if (whose_territory(q, ii) == WHITE) Index: engine/liberty.h =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v retrieving revision 1.204 diff -u -r1.204 liberty.h --- engine/liberty.h 13 Nov 2003 22:48:41 -0000 1.204 +++ engine/liberty.h 18 Nov 2003 08:51:23 -0000 @@ -366,6 +366,8 @@ void add_shape_value(int pos, float value); void add_followup_value(int pos, float value); void add_reverse_followup_value(int pos, float value); +int list_move_reasons(FILE *out, int pos); +void print_all_move_values(void); void record_top_move(int move, float val); void remove_top_move(int move); void scale_randomness(int pos, float scaling); @@ -449,6 +451,7 @@ int review_move_reasons(int *move, float *val, int color, float pure_threat_value, float our_score, int allowed_moves[BOARDMAX]); +void prepare_move_influence_debugging(int pos, int color); int fill_liberty(int *move, int color); int aftermath_genmove(int *aftermath_move, int color, int under_control[BOARDMAX], @@ -603,8 +606,15 @@ void get_influence(const struct influence_data *q, float white_influence[BOARDMAX], float black_influence[BOARDMAX], + float white_strength[BOARDMAX], + float black_strength[BOARDMAX], + float white_attenuation[BOARDMAX], + float black_attenuation[BOARDMAX], + float white_permeability[BOARDMAX], + float black_permeability[BOARDMAX], float territory_value[BOARDMAX], - int regions[BOARDMAX]); + int influence_regions[BOARDMAX], + int non_territory[BOARDMAX]); float influence_score(const struct influence_data *q); float game_status(int color); void resegment_initial_influence(void); Index: engine/move_reasons.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/move_reasons.c,v retrieving revision 1.118 diff -u -r1.118 move_reasons.c --- engine/move_reasons.c 11 Nov 2003 21:48:55 -0000 1.118 +++ engine/move_reasons.c 18 Nov 2003 08:51:23 -0000 @@ -1633,9 +1633,11 @@ } -/* List the move reasons for (color). */ -void -list_move_reasons(int color) +/* List the move reasons for (color)'s move at (pos). Return the + * number of move reasons. + */ +int +list_move_reasons(FILE *out, int move_pos) { int m; int n; @@ -1648,47 +1650,50 @@ int worm1 = -1; int worm2 = -1; int ecolor = 0; - + gprintf("\nMove reasons:\n"); for (n = 0; n < board_size; n++) for (m = board_size-1; m >= 0; m--) { pos = POS(m, n); + if (move_pos != NO_MOVE && move_pos != pos) + continue; + for (k = 0; k < MAX_REASONS; k++) { int r = move[pos].reason[k]; if (r < 0) break; - + switch (move_reasons[r].type) { case ATTACK_MOVE: aa = move_reasons[r].what; - gprintf("Move at %1m attacks %1m%s\n", pos, aa, - (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : ""); + gfprintf(out, "Move at %1m attacks %1m%s\n", pos, aa, + (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : ""); break; case ATTACK_MOVE_GOOD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m attacks %1m%s with good ko\n", pos, aa, - (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : ""); + gfprintf(out, "Move at %1m attacks %1m%s with good ko\n", pos, aa, + (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : ""); break; case ATTACK_MOVE_BAD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m attacks %1m%s with bad ko\n", pos, aa, - (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : ""); + gfprintf(out, "Move at %1m attacks %1m%s with bad ko\n", pos, aa, + (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : ""); break; case DEFEND_MOVE: aa = move_reasons[r].what; - gprintf("Move at %1m defends %1m\n", pos, aa); + gfprintf(out, "Move at %1m defends %1m\n", pos, aa); break; case DEFEND_MOVE_GOOD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m defends %1m with good ko\n", pos, aa); + gfprintf(out, "Move at %1m defends %1m with good ko\n", pos, aa); break; case DEFEND_MOVE_BAD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m defends %1m with bad ko\n", pos, aa); + gfprintf(out, "Move at %1m defends %1m with bad ko\n", pos, aa); break; case ATTACK_THREAT: @@ -1696,19 +1701,19 @@ aa = move_reasons[r].what; if (move_reasons[r].type == ATTACK_THREAT) - gprintf("Move at %1m threatens to attack %1m\n", pos, aa); + gfprintf(out, "Move at %1m threatens to attack %1m\n", pos, aa); else if (move_reasons[r].type == DEFEND_THREAT) - gprintf("Move at %1m threatens to defend %1m\n", pos, aa); + gfprintf(out, "Move at %1m threatens to defend %1m\n", pos, aa); break; case UNCERTAIN_OWL_DEFENSE: aa = move_reasons[r].what; - if (board[aa] == color) - gprintf("%1m found alive but not certainly, %1m defends it again\n", - aa, pos); + if (board[aa] == current_color) + gfprintf(out, "%1m found alive but not certainly, %1m defends it again\n", + aa, pos); else - gprintf("%1m found dead but not certainly, %1m attacks it again\n", - aa, pos); + gfprintf(out, "%1m found dead but not certainly, %1m attacks it again\n", + aa, pos); break; case CONNECT_MOVE: @@ -1716,32 +1721,36 @@ worm1 = conn_worm1[move_reasons[r].what]; worm2 = conn_worm2[move_reasons[r].what]; if (move_reasons[r].type == CONNECT_MOVE) - gprintf("Move at %1m connects %1m and %1m\n", pos, worm1, worm2); + gfprintf(out, "Move at %1m connects %1m and %1m\n", + pos, worm1, worm2); else - gprintf("Move at %1m cuts %1m and %1m\n", pos, worm1, worm2); + gfprintf(out, "Move at %1m cuts %1m and %1m\n", pos, worm1, worm2); break; case ANTISUJI_MOVE: - gprintf("Move at %1m is an antisuji\n", pos); + gfprintf(out, "Move at %1m is an antisuji\n", pos); break; case SEMEAI_MOVE: aa = move_reasons[r].what; - gprintf("Move at %1m wins semeai for %1m\n", pos, aa); + gfprintf(out, "Move at %1m wins semeai for %1m\n", pos, aa); break; case SEMEAI_THREAT: aa = move_reasons[r].what; - gprintf("Move at %1m threatens to win semeai for %1m\n", pos, aa); + gfprintf(out, "Move at %1m threatens to win semeai for %1m\n", + pos, aa); break; case VITAL_EYE_MOVE: aa = eyes[move_reasons[r].what]; ecolor = eyecolor[move_reasons[r].what]; if (ecolor == WHITE) - gprintf("Move at %1m vital eye point for eye %1m\n", pos, aa); + gfprintf(out, "Move at %1m vital eye point for eye %1m\n", + pos, aa); else - gprintf("Move at %1m vital eye point for eye %1m\n", pos, aa); + gfprintf(out, "Move at %1m vital eye point for eye %1m\n", + pos, aa); break; case EITHER_MOVE: @@ -1749,9 +1758,9 @@ reason2 = either_data[move_reasons[r].what].reason2; worm1 = either_data[move_reasons[r].what].what1; worm2 = either_data[move_reasons[r].what].what2; - gprintf("Move at %1m either %s %1m or %s %1m\n", pos, - reason1 == ATTACK_STRING ? "attacks" : "defends", worm1, - reason2 == ATTACK_STRING ? "attacks" : "defends", worm2); + gfprintf(out, "Move at %1m either %s %1m or %s %1m\n", pos, + reason1 == ATTACK_STRING ? "attacks" : "defends", worm1, + reason2 == ATTACK_STRING ? "attacks" : "defends", worm2); break; case ALL_MOVE: @@ -1759,73 +1768,75 @@ reason2 = all_data[move_reasons[r].what].reason2; worm1 = all_data[move_reasons[r].what].what1; worm2 = all_data[move_reasons[r].what].what2; - gprintf("Move at %1m both %s %1m and %s %1m\n", pos, - reason1 == ATTACK_STRING ? "attacks" : "defends", worm1, - reason2 == ATTACK_STRING ? "attacks" : "defends", worm2); + gfprintf(out, "Move at %1m both %s %1m and %s %1m\n", pos, + reason1 == ATTACK_STRING ? "attacks" : "defends", worm1, + reason2 == ATTACK_STRING ? "attacks" : "defends", worm2); break; case OWL_ATTACK_MOVE: aa = move_reasons[r].what; - gprintf("Move at %1m owl-attacks %1m\n", pos, aa); + gfprintf(out, "Move at %1m owl-attacks %1m\n", pos, aa); break; case OWL_ATTACK_MOVE_GOOD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m owl-attacks %1m with good ko\n", pos, aa); + gfprintf(out, "Move at %1m owl-attacks %1m with good ko\n", pos, aa); break; case OWL_ATTACK_MOVE_BAD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m owl-attacks %1m with bad ko\n", pos, aa); + gfprintf(out, "Move at %1m owl-attacks %1m with bad ko\n", pos, aa); break; case OWL_ATTACK_MOVE_GAIN: aa = either_data[move_reasons[r].what].what1; bb = either_data[move_reasons[r].what].what2; - gprintf("Move at %1m owl-attacks %1m (captures %1m)\n", pos, aa, bb); + gfprintf(out, "Move at %1m owl-attacks %1m (captures %1m)\n", + pos, aa, bb); break; case OWL_DEFEND_MOVE: aa = move_reasons[r].what; - gprintf("Move at %1m owl-defends %1m\n", pos, aa); + gfprintf(out, "Move at %1m owl-defends %1m\n", pos, aa); break; case OWL_DEFEND_MOVE_GOOD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m owl-defends %1m with good ko\n", pos, aa); + gfprintf(out, "Move at %1m owl-defends %1m with good ko\n", pos, aa); break; case OWL_DEFEND_MOVE_BAD_KO: aa = move_reasons[r].what; - gprintf("Move at %1m owl-defends %1m with bad ko\n", pos, aa); + gfprintf(out, "Move at %1m owl-defends %1m with bad ko\n", pos, aa); break; case OWL_DEFEND_MOVE_LOSS: aa = either_data[move_reasons[r].what].what1; bb = either_data[move_reasons[r].what].what2; - gprintf("Move at %1m owl-defends %1m (loses %1m)\n", pos, aa, bb); + gfprintf(out, "Move at %1m owl-defends %1m (loses %1m)\n", + pos, aa, bb); break; case OWL_ATTACK_THREAT: aa = move_reasons[r].what; - gprintf("Move at %1m owl-threatens to attack %1m\n", pos, aa); + gfprintf(out, "Move at %1m owl-threatens to attack %1m\n", pos, aa); break; case OWL_DEFEND_THREAT: aa = move_reasons[r].what; - gprintf("Move at %1m owl-threatens to defend %1m\n", pos, aa); + gfprintf(out, "Move at %1m owl-threatens to defend %1m\n", pos, aa); break; case OWL_PREVENT_THREAT: aa = move_reasons[r].what; - gprintf("Move at %1m owl-prevents a threat to attack or defend %1m\n", - pos, aa); + gfprintf(out, "Move at %1m owl-prevents a threat to attack or defend %1m\n", + pos, aa); break; case EXPAND_TERRITORY_MOVE: - gprintf("Move at %1m expands territory\n", pos); + gfprintf(out, "Move at %1m expands territory\n", pos); break; case EXPAND_MOYO_MOVE: - gprintf("Move at %1m expands moyo\n", pos); + gfprintf(out, "Move at %1m expands moyo\n", pos); break; case INVASION_MOVE: - gprintf("Move at %1m is an invasion\n", pos); + gfprintf(out, "Move at %1m is an invasion\n", pos); break; case STRATEGIC_ATTACK_MOVE: @@ -1833,21 +1844,24 @@ aa = move_reasons[r].what; if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE) - gprintf("Move at %1m strategically attacks %1m\n", pos, aa); + gfprintf(out, "Move at %1m strategically attacks %1m\n", pos, aa); else - gprintf("Move at %1m strategically defends %1m\n", pos, aa); + gfprintf(out, "Move at %1m strategically defends %1m\n", pos, aa); break; case MY_ATARI_ATARI_MOVE: - gprintf("Move at %1m captures something\n", pos); + gfprintf(out, "Move at %1m captures something\n", pos); case YOUR_ATARI_ATARI_MOVE: - gprintf("Move at %1m defends against combination attack\n", pos); + gfprintf(out, "Move at %1m defends against combination attack\n", + pos); } } if (k > 0 && move[pos].move_safety == 0) - gprintf("Move at %1m strategically or tactically unsafe\n", pos); + gfprintf(out, "Move at %1m strategically or tactically unsafe\n", pos); } + + return k; } Index: engine/move_reasons.h =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/move_reasons.h,v retrieving revision 1.36 diff -u -r1.36 move_reasons.h --- engine/move_reasons.h 11 Nov 2003 21:48:57 -0000 1.36 +++ engine/move_reasons.h 18 Nov 2003 08:51:24 -0000 @@ -193,7 +193,6 @@ int is_antisuji_move(int pos); void discard_redundant_move_reasons(int pos); -void list_move_reasons(int color); void mark_changed_dragon(int pos, int color, int affected, int affected2, int move_reason_type, char safe_stones[BOARDMAX], Index: engine/value_moves.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v retrieving revision 1.112 diff -u -r1.112 value_moves.c --- engine/value_moves.c 13 Nov 2003 22:48:42 -0000 1.112 +++ engine/value_moves.c 18 Nov 2003 08:51:26 -0000 @@ -1346,7 +1346,8 @@ * Estimate the direct territorial value of a move at (pos). */ static void -estimate_territorial_value(int pos, int color, float our_score) +estimate_territorial_value(int pos, int color, float our_score, + int disable_delta_territory_cache) { int other = OTHER_COLOR(color); int k; @@ -1944,10 +1945,11 @@ if (does_block && tryko(pos, color, "estimate_territorial_value", EMPTY, NO_MOVE)) { Hash_data safety_hash = goal_to_hashvalue(safe_stones); - if (!retrieve_delta_territory_cache(pos, color, &this_value, - &move[pos].influence_followup_value, - OPPOSITE_INFLUENCE(color), - safety_hash)) { + if (disable_delta_territory_cache + || !retrieve_delta_territory_cache(pos, color, &this_value, + &move[pos].influence_followup_value, + OPPOSITE_INFLUENCE(color), + safety_hash)) { int saved_optimistic_territory; saved_optimistic_territory = use_optimistic_territory; @@ -2579,7 +2581,7 @@ * is significant. Territorial value must be computed before * strategical value. See connection_value(). */ - estimate_territorial_value(pos, color, our_score); + estimate_territorial_value(pos, color, our_score, 0); estimate_strategical_value(pos, color, our_score); } @@ -2828,6 +2830,21 @@ } +/* Print the values of all moves with values bigger than zero. */ + +void +print_all_move_values() +{ + int pos; + + for (pos = BOARDMIN; pos < BOARDMAX; pos++) { + if (!ON_BOARD(pos) || move[pos].final_value <= 0.0) + continue; + + mprintf("%1M %f\n", pos, move[pos].final_value); + } +} + /* Search through all board positions for the 10 highest valued * moves and print them. */ @@ -2861,7 +2878,7 @@ /* Add a move to the list of top moves (if it is among the top ten) */ void -record_top_move(int move, float val) +record_top_move(int pos, float val) { int k; for (k = 9; k >= 0; k--) @@ -2871,8 +2888,10 @@ best_moves[k+1] = best_moves[k]; } best_move_values[k] = val; - best_moves[k] = move; + best_moves[k] = pos; } + + move[pos].final_value = val; } /* remove a rejected move from the list of top moves */ @@ -3265,7 +3284,7 @@ time_report(2, " induce_secondary_move_reasons", NO_MOVE, 1.0); if (printworms || verbose) - list_move_reasons(color); + list_move_reasons(stderr, NO_MOVE); /* Evaluate all moves with move reasons. */ value_moves(color, pure_threat_value, our_score); @@ -3341,6 +3360,26 @@ } } +/* In order to get valid influence data after a move, we need to rerun + * estimate_territorial_value() for that move. A prerequisite for + * using this function is that move reasons have already been collected. + * + * This function should only be used for debugging purposes. + */ +void +prepare_move_influence_debugging(int pos, int color) +{ + float lower_bound, upper_bound; + float our_score; + + estimate_score(&upper_bound, &lower_bound); + if (color == WHITE) + our_score = lower_bound; + else + our_score = -upper_bound; + + estimate_territorial_value(pos, color, our_score, 1); +} /* * Local Variables: Index: interface/play_gtp.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/interface/play_gtp.c,v retrieving revision 1.135 diff -u -r1.135 play_gtp.c --- interface/play_gtp.c 13 Nov 2003 22:48:42 -0000 1.135 +++ interface/play_gtp.c 18 Nov 2003 08:51:27 -0000 @@ -56,10 +56,6 @@ int *time_for_last_move, int *time_left, int *stones_left); static void adjust_level_offset(int color); -static void print_influence(float white_influence[BOARDMAX], - float black_influence[BOARDMAX], - float territory_value[BOARDMAX], - int influence_regions[BOARDMAX]); static void gtp_print_code(int c); static void gtp_print_vertices2(int n, int *moves); static void rotate_on_input(int ai, int aj, int *bi, int *bj); @@ -72,6 +68,7 @@ DECLARE(gtp_accurate_approxlib); DECLARE(gtp_accuratelib); DECLARE(gtp_all_legal); +DECLARE(gtp_all_move_values); DECLARE(gtp_analyze_eyegraph); DECLARE(gtp_analyze_semeai); DECLARE(gtp_analyze_semeai_after_move); @@ -102,12 +99,14 @@ DECLARE(gtp_estimate_score); DECLARE(gtp_eval_eye); DECLARE(gtp_experimental_score); +DECLARE(gtp_eye_data); DECLARE(gtp_final_score); DECLARE(gtp_final_status); DECLARE(gtp_final_status_list); DECLARE(gtp_findlib); DECLARE(gtp_finish_sgftrace); DECLARE(gtp_fixed_handicap); +DECLARE(gtp_followup_influence); DECLARE(gtp_genmove); DECLARE(gtp_genmove_black); DECLARE(gtp_genmove_white); @@ -121,8 +120,9 @@ DECLARE(gtp_get_trymove_counter); DECLARE(gtp_gg_genmove); DECLARE(gtp_gg_undo); +DECLARE(gtp_half_eye_data); DECLARE(gtp_increase_depths); -DECLARE(gtp_influence); +DECLARE(gtp_initial_influence); DECLARE(gtp_is_legal); DECLARE(gtp_is_surrounded); DECLARE(gtp_known_command); @@ -132,6 +132,8 @@ DECLARE(gtp_list_commands); DECLARE(gtp_list_stones); DECLARE(gtp_loadsgf); +DECLARE(gtp_move_influence); +DECLARE(gtp_move_reasons); DECLARE(gtp_name); DECLARE(gtp_owl_attack); DECLARE(gtp_owl_connection_defends); @@ -195,6 +197,7 @@ {"accurate_approxlib", gtp_accurate_approxlib}, {"accuratelib", gtp_accuratelib}, {"all_legal", gtp_all_legal}, + {"all_move_values", gtp_all_move_values}, {"analyze_eyegraph", gtp_analyze_eyegraph}, {"analyze_semeai", gtp_analyze_semeai}, {"analyze_semeai_after_move", gtp_analyze_semeai_after_move}, @@ -228,12 +231,14 @@ {"estimate_score", gtp_estimate_score}, {"eval_eye", gtp_eval_eye}, {"experimental_score", gtp_experimental_score}, + {"eye_data", gtp_eye_data}, {"final_score", gtp_final_score}, {"final_status", gtp_final_status}, {"final_status_list", gtp_final_status_list}, {"findlib", gtp_findlib}, {"finish_sgftrace", gtp_finish_sgftrace}, {"fixed_handicap", gtp_fixed_handicap}, + {"followup_influence", gtp_followup_influence}, {"genmove", gtp_genmove}, {"genmove_black", gtp_genmove_black}, {"genmove_white", gtp_genmove_white}, @@ -247,9 +252,10 @@ {"get_trymove_counter", gtp_get_trymove_counter}, {"gg-undo", gtp_gg_undo}, {"gg_genmove", gtp_gg_genmove}, + {"half_eye_data", gtp_half_eye_data}, {"help", gtp_list_commands}, {"increase_depths", gtp_increase_depths}, - {"influence", gtp_influence}, + {"initial_influence", gtp_initial_influence}, {"is_legal", gtp_is_legal}, {"is_surrounded", gtp_is_surrounded}, {"known_command", gtp_known_command}, @@ -262,6 +268,8 @@ {"list_commands", gtp_list_commands}, {"list_stones", gtp_list_stones}, {"loadsgf", gtp_loadsgf}, + {"move_influence", gtp_move_influence}, + {"move_reasons", gtp_move_reasons}, {"name", gtp_name}, {"new_score", gtp_estimate_score}, {"orientation", gtp_set_orientation}, @@ -1174,6 +1182,7 @@ clear_persistent_owl_cache(); clear_persistent_connection_cache(); clear_persistent_breakin_cache(); + reading_cache_clear(); return gtp_success(""); } @@ -2519,8 +2528,50 @@ } -/* Function : Generate a list of the best moves in the previous genmove - * command (either of genmove_black, genmove_white, gg_genmove). +/* Function : List the move reasons for a move. + * Arguments: vertex + * Fails: : invalid vertex, occupied vertex + * Returns : list of move reasons (may be empty) + */ + +static int +gtp_move_reasons(char *s) +{ + int i, j; + if (!gtp_decode_coord(s, &i, &j)) + return gtp_failure("invalid coordinate"); + + if (BOARD(i, j) != EMPTY) + return gtp_failure("vertex must not be occupied"); + + gtp_start_response(GTP_SUCCESS); + if (list_move_reasons(stdout, POS(i, j)) == 0) + gtp_printf("\n"); + gtp_printf("\n"); + return GTP_OK; +} + +/* Function : Generate a list of all moves with values larger than zero in + * the previous genmove command. + * If no previous genmove command has been issued, the result + * of this command will be meaningless. + * Arguments: none + * Fails: : never + * Returns : list of moves with values + */ + +static int +gtp_all_move_values(char *s) +{ + UNUSED(s); + gtp_start_response(GTP_SUCCESS); + print_all_move_values(); + gtp_printf("\n"); + return GTP_OK; +} + +/* Function : Generate a sorted list of the best moves in the previous genmove + * command. * If no previous genmove command has been issued, the result * of this command will be meaningless. * Arguments: none @@ -3441,38 +3492,110 @@ return gtp_success(""); } +/* Determine whether a string starts with a specific substring. */ +static int +has_prefix(const char *s, const char *prefix) +{ + return strncmp(s, prefix, strlen(prefix)) == 0; +} -/* Function: Return information about the influence function. - * Arguments: color to move +static int +print_influence_data(struct influence_data *q, char *what_data) +{ + float white_influence[BOARDMAX]; + float black_influence[BOARDMAX]; + float white_strength[BOARDMAX]; + float black_strength[BOARDMAX]; + float white_attenuation[BOARDMAX]; + float black_attenuation[BOARDMAX]; + float white_permeability[BOARDMAX]; + float black_permeability[BOARDMAX]; + float territory_value[BOARDMAX]; + int influence_regions[BOARDMAX]; + int non_territory[BOARDMAX]; + int m, n; + + float *float_pointer = NULL; + int *int_pointer = NULL; + + while (*what_data == ' ') + what_data++; + + get_influence(q, white_influence, black_influence, + white_strength, black_strength, + white_attenuation, black_attenuation, + white_permeability, black_permeability, + territory_value, influence_regions, non_territory); + + if (has_prefix(what_data, "white_influence")) + float_pointer = white_influence; + else if (has_prefix(what_data, "black_influence")) + float_pointer = black_influence; + else if (has_prefix(what_data, "white_strength")) + float_pointer = white_strength; + else if (has_prefix(what_data, "black_strength")) + float_pointer = black_strength; + else if (has_prefix(what_data, "white_attenuation")) + float_pointer = white_attenuation; + else if (has_prefix(what_data, "black_attenuation")) + float_pointer = black_attenuation; + else if (has_prefix(what_data, "white_permeability")) + float_pointer = white_permeability; + else if (has_prefix(what_data, "black_permeability")) + float_pointer = black_permeability; + else if (has_prefix(what_data, "territory_value")) + float_pointer = territory_value; + else if (has_prefix(what_data, "influence_regions")) + int_pointer = influence_regions; + else if (has_prefix(what_data, "non_territory")) + int_pointer = non_territory; + else + return gtp_failure("unknown influence data"); + + gtp_start_response(GTP_SUCCESS); + for (m = 0; m < board_size; m++) { + for (n = 0; n < board_size; n++) { + if (float_pointer) + gtp_printf("%6.2f ", float_pointer[POS(m, n)]); + else + gtp_printf("%2d ", int_pointer[POS(m, n)]); + } + gtp_printf("\n"); + } + + /* We already have one newline and thus can't use gtp_finish_response(). */ + gtp_printf("\n"); + return GTP_OK; +} + +/* Function: Return information about the initial influence function. + * Arguments: color to move, what information * Fails: never * Returns: Influence data formatted like: * - * white: * 0.51 1.34 3.20 6.60 9.09 8.06 1.96 0.00 0.00 * 0.45 1.65 4.92 12.19 17.47 15.92 4.03 0.00 0.00 * . * . * . * 0.00 0.00 0.00 0.00 0.00 100.00 75.53 41.47 23.41 - * black: - * 1.57 2.51 4.10 3.10 3.60 4.54 8.32 4.15 2.71 - * 2.96 4.62 9.18 5.47 5.89 10.88 20.54 10.19 4.08 - * . - * . - * . - * 100.00 139.39 100.00 139.39 100.00 0.00 0.00 0.00 0.00 - * territory value: - * . - * . - * . - * regions: - * -1 0 0 1 1 0 -1 -3 -3 - * . - * . - * . - * -3 -3 -3 -3 -3 3 3 3 3 * - * The encoding of the regions is as follows: + * The available choices of information are: + * + * white_influence (float) + * black_influence (float) + * white_strength (float) + * black_strength (float) + * white_attenuation (float) + * black_attenuation (float) + * white_permeability (float) + * black_permeability (float) + * territory_value (float) + * influence_regions (int) + * non_territory (int) + * + * The encoding of influence_regions is as follows: + * 4 white stone * 3 white territory * 2 white moyo * 1 white area @@ -3480,76 +3603,68 @@ * -1 black area * -2 black moyo * -3 black territory + * -4 black stone */ static int -gtp_influence(char *s) +gtp_initial_influence(char *s) { int color; - float white_influence[BOARDMAX]; - float black_influence[BOARDMAX]; - float territory_value[BOARDMAX]; - int influence_regions[BOARDMAX]; - - if (!gtp_decode_color(s, &color)) + struct influence_data *q; + int n; + + n = gtp_decode_color(s, &color); + if (n == 0) return gtp_failure("invalid color"); + q = INITIAL_INFLUENCE(color); + silent_examine_position(color, EXAMINE_ALL); - gtp_start_response(GTP_SUCCESS); - get_influence(OPPOSITE_INFLUENCE(color), white_influence, - black_influence, territory_value, influence_regions); - print_influence(white_influence, black_influence, territory_value, - influence_regions); - - /* We already have one newline and thus can't use gtp_finish_response(). */ - gtp_printf("\n"); - return GTP_OK; + return print_influence_data(q, s + n); } -static void -print_influence(float white_influence[BOARDMAX], - float black_influence[BOARDMAX], - float territory_value[BOARDMAX], - int influence_regions[BOARDMAX]) +/* Function: Return information about the influence function after a move. + * Arguments: move, what information + * Fails: never + * Returns: Influence data formatted like for initial_influence. + */ +static int +gtp_move_influence(char *s) { - int m, n; - gtp_printf("white:\n"); - for (m = 0; m < board_size; m++) { - for (n = 0; n < board_size; n++) { - gtp_printf("%6.2f ", white_influence[POS(m, n)]); - } - gtp_printf("\n"); - } + int color; + int i, j; + int n; - gtp_printf("black:\n"); - for (m = 0; m < board_size; m++) { - for (n = 0; n < board_size; n++) { - gtp_printf("%6.2f ", black_influence[POS(m, n)]); - } - gtp_printf("\n"); - } + n = gtp_decode_move(s, &color, &i, &j); + if (n == 0) + return gtp_failure("invalid move"); - gtp_printf("territory value:\n"); - for (m = 0; m < board_size; m++) { - for (n = 0; n < board_size; n++) - gtp_printf("%+6.2f ", territory_value[POS(m, n)]); + prepare_move_influence_debugging(POS(i, j), color); + + return print_influence_data(&move_influence, s + n); +} - gtp_printf("\n"); - } - gtp_printf("regions:\n"); - for (m = 0; m < board_size; m++) { - for (n = 0; n < board_size; n++) { - if (influence_regions[POS(m, n)] == 4) - gtp_printf(" @ "); /* 'O' looks too much like '0'. */ - else if (influence_regions[POS(m, n)] == -4) - gtp_printf(" X "); - else - gtp_printf("%2d ", influence_regions[POS(m, n)]); - } - gtp_printf("\n"); - } +/* Function: Return information about the followup influence after a move. + * Arguments: move, what information + * Fails: never + * Returns: Influence data formatted like for initial_influence. + */ +static int +gtp_followup_influence(char *s) +{ + int color; + int i, j; + int n; + + n = gtp_decode_move(s, &color, &i, &j); + if (n == 0) + return gtp_failure("invalid move"); + + prepare_move_influence_debugging(POS(i, j), color); + + return print_influence_data(&followup_influence, s + n); } @@ -3607,8 +3722,7 @@ struct worm_data *w = &worm[POS(m, n)]; gtp_print_vertex(m, n); gtp_printf(":\n"); - gtp_mprintf("origin %m\n", - I(w->origin), J(w->origin)); + gtp_mprintf("origin %m\n", I(w->origin), J(w->origin)); gtp_mprintf("color %C\n", w->color); gtp_printf("size %d\n", w->size); gtp_printf("effective_size %.2f\n", w->effective_size); @@ -3794,6 +3908,99 @@ gtp_mprintf("%m ", m, n); gtp_printf("\n"); } + + gtp_printf("\n"); + return GTP_OK; +} + +/* Function: Return the information in the eye data structure. + * Arguments: color, vertex + * Fails: never + * Returns: eye data fields and values, one pair per row + */ +static int +gtp_eye_data(char *s) +{ + int color = EMPTY; + int i = -1; + int j = -1; + struct eye_data *e; + + if (!gtp_decode_move(s, &color, &i, &j)) + return gtp_failure("invalid color or coordinate"); + + if (stackp > 0) + return gtp_failure("eye data unavailable when stackp > 0"); + + examine_position(EMPTY, EXAMINE_DRAGONS_WITHOUT_OWL); + + gtp_start_response(GTP_SUCCESS); + + if (color == BLACK) + e = &black_eye[POS(i, j)]; + else + e = &white_eye[POS(i, j)]; + + gtp_mprintf("origin %m\n", I(e->origin), J(e->origin)); + gtp_mprintf("color %C\n", e->color); + gtp_printf("esize %d\n", e->esize); + gtp_printf("msize %d\n", e->msize); + gtp_printf("value %s\n", eyevalue_to_string(&e->value)); + gtp_mprintf("attack_point %m\n", + I(e->attack_point), J(e->attack_point)); + gtp_mprintf("defense_point %m\n", + I(e->defense_point), J(e->defense_point)); + gtp_printf("marginal %d\n", e->marginal); + gtp_printf("type %d\n", e->type); + gtp_printf("neighbors %d\n", e->neighbors); + gtp_printf("marginal_neighbors %d\n", e->marginal_neighbors); + gtp_printf("cut %d\n", e->cut); + + gtp_printf("\n"); + return GTP_OK; +} + + +/* Function: Return the information in the half eye data structure. + * Arguments: vertex + * Fails: never + * Returns: half eye data fields and values, one pair per row + */ +static int +gtp_half_eye_data(char *s) +{ + int i = -1; + int j = -1; + struct half_eye_data *h; + int k; + + if (!gtp_decode_coord(s, &i, &j)) + return gtp_failure("invalid coordinate"); + + if (stackp > 0) + return gtp_failure("half eye data unavailable when stackp > 0"); + + examine_position(EMPTY, EXAMINE_DRAGONS_WITHOUT_OWL); + + gtp_start_response(GTP_SUCCESS); + + h = &half_eye[POS(i, j)]; + + gtp_printf("value %.2f\n", h->value); + if (h->type == HALF_EYE) + gtp_printf("type HALF_EYE\n"); + else if (h->type == FALSE_EYE) + gtp_printf("type FALSE_EYE\n"); + else + gtp_printf("type %d\n", h->type); + gtp_printf("num_attacks %d\n", h->num_attacks); + for (k = 0; k < h->num_attacks; k++) + gtp_mprintf("attack_point[%d] %m\n", k, I(h->attack_point[k]), + J(h->attack_point[k])); + gtp_printf("num_defenses %d\n", h->num_defenses); + for (k = 0; k < h->num_defenses; k++) + gtp_mprintf("defense_point[%d] %m\n", k, I(h->defense_point[k]), + J(h->defense_point[k])); gtp_printf("\n"); return GTP_OK;