RCS file: /cvsroot/gnugo/gnugo/doc/gtp-commands.texi,v
retrieving revision 1.28
diff -u -r1.28 gtp-commands.texi
|
|
|
|
| 762 | 762 | @cindex analyze_eyegraph |
| 763 | 763 | @item analyze_eyegraph: Compute an eyevalue and vital points for an eye graph |
| 764 | 764 | @verbatim |
| 765 | | Arguments: Eyeshape encoded in string |
| | 765 | Arguments: Eyeshape encoded in string OR two integers followed by eyeshape |
| 766 | 766 | Fails: Bad eyeshape, analysis failed |
| 767 | 767 | Returns: Eyevalue, vital points |
| 768 | 768 | @end verbatim |
RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
retrieving revision 1.258
diff -u -r1.258 liberty.h
|
|
|
|
| 664 | 664 | int max_eye_value(int pos); |
| 665 | 665 | void test_eyeshape(int eyesize, int *eye_vertices); |
| 666 | 666 | int analyze_eyegraph(const char *coded_eyegraph, struct eyevalue *value, |
| 667 | | char *analyzed_eyegraph); |
| | 667 | char *analyzed_eyegraph, int outer_liberties, |
| | 668 | int ko_threats); |
| 668 | 669 | |
| 669 | 670 | |
| 670 | 671 | /* debugging support */ |
RCS file: /cvsroot/gnugo/gnugo/engine/optics.c,v
retrieving revision 1.105
diff -u -r1.105 optics.c
|
|
|
|
| 2657 | 2691 | * 3 - result has been computed and was a success (1) |
| 2658 | 2692 | */ |
| 2659 | 2693 | |
| | 2694 | /* Types of vertices under consideration. */ |
| | 2695 | #define REGULAR 0 |
| | 2696 | #define OUTER_LIBERTY 1 |
| | 2697 | #define EXTRA_EYE 2 |
| | 2698 | #define KO_THREAT 3 |
| | 2699 | |
| | 2700 | #define MAX_OUTER_LIBERTIES 4 |
| | 2701 | #define MAX_KO_THREATS 4 |
| | 2702 | |
| | 2703 | struct vertex_data { |
| | 2704 | int pos[MAX_BOARD]; |
| | 2705 | int type[MAX_BOARD]; |
| | 2706 | int num; |
| | 2707 | int ko_threat_pos[MAX_KO_THREATS]; |
| | 2708 | int num_ko_threats; |
| | 2709 | int num_ordinary; |
| | 2710 | int komaster; |
| | 2711 | int extra_eye_pos; |
| | 2712 | int string; |
| | 2713 | }; |
| | 2714 | |
| 2660 | 2715 | /* Like trymove() except that it does a superko check. This does, |
| 2661 | | * however, only disallow repetition (besides simple ko) if the move |
| 2662 | | * does not capture any stones. |
| | 2716 | * however, only disallow repetition (besides simple ko) for the |
| | 2717 | * attacker. |
| | 2718 | * |
| | 2719 | * In order to cope with bent four in the corner, white is given one |
| | 2720 | * free virtual ko threat, which black can eliminate by spending a |
| | 2721 | * move playing on the "ko threat vertex". This has the side effect |
| | 2722 | * that white wins all direct kos, which is mostly okay until ko |
| | 2723 | * dependent eye values are implemented. It can, however, cause attack |
| | 2724 | * and defense points dependent on ko to be recommended together with |
| | 2725 | * non-ko vital points. |
| 2663 | 2726 | */ |
| | 2727 | |
| | 2728 | static int forced_ko_threat_stackp[MAX_KO_THREATS]; |
| | 2729 | static int num_active_ko_threats = 0; |
| | 2730 | |
| 2664 | 2731 | static int |
| 2665 | | eyegraph_trymove(int pos, int color, const char *message, int str) |
| | 2732 | eyegraph_trymove(int pos, int color, const char *message, int str, |
| | 2733 | struct vertex_data *vertices) |
| 2666 | 2734 | { |
| 2667 | 2735 | static Hash_data remembered_board_hashes[MAXSTACK]; |
| 2668 | 2736 | int k; |
| 2669 | | int does_capture = does_capture_something(pos, color); |
| 2670 | 2737 | |
| 2671 | 2738 | remembered_board_hashes[stackp] = board_hash; |
| 2672 | | |
| 2673 | | if (!trymove(pos, color, message, str)) |
| 2674 | | return 0; |
| 2675 | 2739 | |
| 2676 | | if (does_capture) |
| | 2740 | if (!trymove(pos, color, message, str)) { |
| | 2741 | int ko_threat_pos = NO_MOVE; |
| | 2742 | |
| | 2743 | if (!vertices) |
| | 2744 | return 0; |
| | 2745 | |
| | 2746 | if (color != vertices->komaster |
| | 2747 | || is_suicide(pos, color)) |
| | 2748 | return 0; |
| | 2749 | |
| | 2750 | for (k = 0; k < vertices->num_ko_threats; k++) |
| | 2751 | if (board[vertices->ko_threat_pos[k]] == EMPTY) { |
| | 2752 | ko_threat_pos = vertices->ko_threat_pos[k]; |
| | 2753 | break; |
| | 2754 | } |
| | 2755 | |
| | 2756 | if (ko_threat_pos != NO_MOVE) { |
| | 2757 | trymove(ko_threat_pos, BLACK, "making/answering virtual ko threat", str); |
| | 2758 | forced_ko_threat_stackp[num_active_ko_threats++] = stackp; |
| | 2759 | trymove(pos, color, message, str); |
| | 2760 | } |
| | 2761 | else |
| | 2762 | return 0; |
| | 2763 | } |
| | 2764 | |
| | 2765 | if (color == WHITE) |
| 2677 | 2766 | return 1; |
| 2678 | 2767 | |
| 2679 | 2768 | for (k = 0; k < stackp; k++) |
| … |
… |
|
| 2685 | 2774 | return 1; |
| 2686 | 2775 | } |
| 2687 | 2776 | |
| | 2777 | static void |
| | 2778 | eyegraph_popgo(void) |
| | 2779 | { |
| | 2780 | popgo(); |
| | 2781 | |
| | 2782 | if (num_active_ko_threats > 0 |
| | 2783 | && forced_ko_threat_stackp[num_active_ko_threats - 1] == stackp) { |
| | 2784 | popgo(); |
| | 2785 | num_active_ko_threats--; |
| | 2786 | } |
| | 2787 | } |
| | 2788 | |
| | 2789 | /* Has the vertex a neighbor which is connected to an invincible black |
| | 2790 | * string? |
| | 2791 | */ |
| 2688 | 2792 | static int |
| 2689 | 2793 | eyegraph_is_margin_or_outer_liberty(int vertex) |
| 2690 | 2794 | { |
| … |
… |
|
| 2711 | 2815 | } |
| 2712 | 2816 | |
| 2713 | 2817 | static int |
| 2714 | | eyegraph_order_moves(int num_vertices, int *vertices, int color_to_move, int *moves) |
| | 2818 | eyegraph_order_moves(struct vertex_data *vertices, int color_to_move, |
| | 2819 | int *moves) |
| 2715 | 2820 | { |
| 2716 | 2821 | int num_moves = 0; |
| 2717 | 2822 | int scores[BOARDMAX]; |
| … |
… |
|
| 2720 | 2825 | int k; |
| 2721 | 2826 | int r; |
| 2722 | 2827 | |
| 2723 | | for (k = 0; k < num_vertices; k++) { |
| 2724 | | if (k >= num_vertices - 3) { |
| | 2828 | for (k = 0; k < vertices->num; k++) { |
| | 2829 | if (vertices->type[k] != REGULAR) { |
| 2725 | 2830 | /* Never useful for white to fill in outer liberties or a second eye. */ |
| 2726 | 2831 | if (color_to_move == WHITE) |
| 2727 | 2832 | break; |
| 2728 | | /* No use playing the second outer liberty before the first one. */ |
| 2729 | | if (k == num_vertices - 2 && board[vertices[num_vertices - 3]] == EMPTY) |
| | 2833 | /* No use playing a later outer liberty before the previous one. */ |
| | 2834 | if (vertices->type[k] == OUTER_LIBERTY |
| | 2835 | && vertices->type[k - 1] == OUTER_LIBERTY |
| | 2836 | && board[vertices->pos[k - 1]] == EMPTY) |
| 2730 | 2837 | continue; |
| 2731 | 2838 | } |
| 2732 | 2839 | |
| 2733 | | move = vertices[k]; |
| | 2840 | move = vertices->pos[k]; |
| 2734 | 2841 | score = 0; |
| 2735 | 2842 | |
| 2736 | 2843 | if (board[move] != EMPTY) |
| 2737 | 2844 | continue; |
| 2738 | 2845 | |
| 2739 | | if (eyegraph_is_margin_or_outer_liberty(move)) { |
| 2740 | | if (k < num_vertices - 3) |
| | 2846 | if (eyegraph_is_margin_or_outer_liberty(move)) |
| | 2847 | if (vertices->type[k] == REGULAR) |
| 2741 | 2848 | score = 5; /* margin */ |
| 2742 | | else |
| 2743 | | score = -10; /* outer liberty */ |
| 2744 | | } |
| 2745 | 2849 | |
| 2746 | 2850 | if (accuratelib(move, color_to_move, 2, NULL) == 1) |
| 2747 | 2851 | score -= 3; |
| … |
… |
|
| 2843 | 2947 | return (result); \ |
| 2844 | 2948 | } while (0); |
| 2845 | 2949 | |
| 2846 | | static int tactical_life_defend(int str, int num_vertices, int *vertices, |
| | 2950 | static int tactical_life_defend(int str, struct vertex_data *vertices, |
| 2847 | 2951 | unsigned char *results); |
| 2848 | 2952 | |
| 2849 | 2953 | /* Determine whether black can capture all white stones. */ |
| 2850 | 2954 | static int |
| 2851 | | tactical_life_attack(int str, int num_vertices, int *vertices, |
| | 2955 | tactical_life_attack(int str, struct vertex_data *vertices, |
| 2852 | 2956 | unsigned char *results) |
| 2853 | 2957 | { |
| 2854 | 2958 | int k; |
| … |
… |
|
| 2859 | 2963 | int moves[BOARDMAX]; |
| 2860 | 2964 | |
| 2861 | 2965 | /* Compute hash value to index the result cache with. */ |
| 2862 | | for (k = 0; k < num_vertices; k++) { |
| | 2966 | for (k = 0; k < vertices->num; k++) { |
| 2863 | 2967 | hash *= 3; |
| 2864 | | hash += board[vertices[k]]; |
| | 2968 | hash += board[vertices->pos[k]]; |
| 2865 | 2969 | } |
| 2866 | 2970 | hash *= 2; |
| 2867 | 2971 | hash += (board_ko_pos != NO_MOVE); |
| … |
… |
|
| 2885 | 2989 | results[hash] |= 1; |
| 2886 | 2990 | |
| 2887 | 2991 | /* Try to play on all relevant vertices. */ |
| 2888 | | num_moves = eyegraph_order_moves(num_vertices, vertices, |
| 2889 | | OTHER_COLOR(board[str]), moves); |
| | 2992 | num_moves = eyegraph_order_moves(vertices, OTHER_COLOR(board[str]), moves); |
| 2890 | 2993 | for (k = 0; k < num_moves; k++) { |
| 2891 | 2994 | int move = moves[k]; |
| 2892 | 2995 | if (eyegraph_trymove(move, OTHER_COLOR(board[str]), |
| 2893 | | "tactical_life_attack", str)) { |
| | 2996 | "tactical_life_attack", str, |
| | 2997 | vertices)) { |
| 2894 | 2998 | /* We were successful if the white stones were captured or if no |
| 2895 | 2999 | * defense can be found. |
| 2896 | 3000 | */ |
| 2897 | 3001 | if (board[str] == EMPTY) |
| 2898 | 3002 | result = 1; |
| 2899 | 3003 | else |
| 2900 | | result = !tactical_life_defend(str, num_vertices, vertices, results); |
| | 3004 | result = !tactical_life_defend(str, vertices, results); |
| 2901 | 3005 | |
| 2902 | | popgo(); |
| | 3006 | eyegraph_popgo(); |
| 2903 | 3007 | |
| 2904 | 3008 | if (result == 1) { |
| 2905 | 3009 | /* Store the result (success) in the cache. */ |
| … |
… |
|
| 2916 | 3020 | |
| 2917 | 3021 | /* Determine whether white can live with all stones. */ |
| 2918 | 3022 | static int |
| 2919 | | tactical_life_defend(int str, int num_vertices, int *vertices, |
| | 3023 | tactical_life_defend(int str, struct vertex_data *vertices, |
| 2920 | 3024 | unsigned char *results) |
| 2921 | 3025 | { |
| 2922 | 3026 | int k; |
| … |
… |
|
| 2927 | 3031 | int moves[BOARDMAX]; |
| 2928 | 3032 | |
| 2929 | 3033 | /* Compute hash value to index the result cache with. */ |
| 2930 | | for (k = 0; k < num_vertices; k++) { |
| | 3034 | for (k = 0; k < vertices->num; k++) { |
| 2931 | 3035 | hash *= 3; |
| 2932 | | ASSERT1(board[vertices[k]] <= 2, vertices[k]); |
| 2933 | | hash += board[vertices[k]]; |
| | 3036 | ASSERT1(board[vertices->pos[k]] <= 2, vertices->pos[k]); |
| | 3037 | hash += board[vertices->pos[k]]; |
| 2934 | 3038 | } |
| 2935 | 3039 | hash *= 2; |
| 2936 | 3040 | hash += (board_ko_pos != NO_MOVE); |
| … |
… |
|
| 2954 | 3058 | results[hash] |= (1 << 2); |
| 2955 | 3059 | |
| 2956 | 3060 | /* Try to play on all relevant vertices. */ |
| 2957 | | num_moves = eyegraph_order_moves(num_vertices, vertices, board[str], moves); |
| | 3061 | num_moves = eyegraph_order_moves(vertices, board[str], moves); |
| 2958 | 3062 | for (k = 0; k < num_moves; k++) { |
| 2959 | 3063 | int move = moves[k]; |
| 2960 | 3064 | if ((!is_suicide(move, OTHER_COLOR(board[str])) |
| 2961 | 3065 | || does_capture_something(move, board[str])) |
| 2962 | | && eyegraph_trymove(move, board[str], "tactical_life_defend", str)) { |
| | 3066 | && eyegraph_trymove(move, board[str], "tactical_life_defend", str, |
| | 3067 | vertices)) { |
| 2963 | 3068 | /* We were successful if no attack can be found. */ |
| 2964 | | result = !tactical_life_attack(str, num_vertices, vertices, results); |
| | 3069 | result = !tactical_life_attack(str, vertices, results); |
| 2965 | 3070 | |
| 2966 | | popgo(); |
| | 3071 | eyegraph_popgo(); |
| 2967 | 3072 | |
| 2968 | 3073 | if (result == 1) { |
| 2969 | 3074 | /* Store the result (success) in the cache. */ |
| … |
… |
|
| 2974 | 3079 | } |
| 2975 | 3080 | |
| 2976 | 3081 | /* If no move worked, also try passing. */ |
| 2977 | | if (!tactical_life_attack(str, num_vertices, vertices, results)) { |
| | 3082 | if (!tactical_life_attack(str, vertices, results)) { |
| 2978 | 3083 | /* Store the result (success) in the cache. */ |
| 2979 | 3084 | results[hash] = (results[hash] & (~12)) | (3 << 2); |
| 2980 | 3085 | EYEGRAPH_RETURN(1, "tactical_life_defend: win"); |
| … |
… |
|
| 2991 | 3096 | * used or filled in before starting reading. |
| 2992 | 3097 | */ |
| 2993 | 3098 | static void |
| 2994 | | tactical_life(int have_eye, int num_vertices, int *vertices, |
| | 3099 | tactical_life(int have_eye, struct vertex_data *vertices, |
| 2995 | 3100 | int *attack_code, int *num_attacks, int *attack_points, |
| 2996 | 3101 | int *defense_code, int *num_defenses, int *defense_points, |
| 2997 | 3102 | unsigned char *results) |
| … |
… |
|
| 3007 | 3112 | * vertex we test to determine whether the white stones have been |
| 3008 | 3113 | * captured. |
| 3009 | 3114 | */ |
| 3010 | | str = POS(1, 0); |
| | 3115 | str = vertices->string; |
| 3011 | 3116 | |
| 3012 | 3117 | if (board[str] == EMPTY) { |
| 3013 | 3118 | /* The stones have already been captured, too late to defend. */ |
| … |
… |
|
| 3020 | 3125 | * suicide the white stones can be considered dead. |
| 3021 | 3126 | */ |
| 3022 | 3127 | if (!have_eye) { |
| 3023 | | if (!eyegraph_trymove(POS(0, 0), WHITE, "tactical_life-A", NO_MOVE)) { |
| | 3128 | if (!eyegraph_trymove(vertices->extra_eye_pos, WHITE, "tactical_life-A", |
| | 3129 | NO_MOVE, NULL)) { |
| 3024 | 3130 | *attack_code = WIN; |
| 3025 | 3131 | *defense_code = 0; |
| 3026 | 3132 | return; |
| … |
… |
|
| 3033 | 3139 | /* Call tactical_life_attack() and tactical_life_defend() to |
| 3034 | 3140 | * determine status. |
| 3035 | 3141 | */ |
| 3036 | | if (tactical_life_attack(str, num_vertices, vertices, results)) { |
| | 3142 | if (tactical_life_attack(str, vertices, results)) { |
| 3037 | 3143 | *attack_code = WIN; |
| 3038 | | if (tactical_life_defend(str, num_vertices, vertices, results)) |
| | 3144 | if (tactical_life_defend(str, vertices, results)) |
| 3039 | 3145 | *defense_code = WIN; |
| 3040 | 3146 | } |
| 3041 | 3147 | else |
| … |
… |
|
| 3049 | 3155 | if (*attack_code != 0 && *defense_code != 0) { |
| 3050 | 3156 | if (num_attacks != NULL && attack_points != NULL) { |
| 3051 | 3157 | *num_attacks = 0; |
| 3052 | | num_moves = eyegraph_order_moves(num_vertices, vertices, |
| | 3158 | num_moves = eyegraph_order_moves(vertices, |
| 3053 | 3159 | OTHER_COLOR(board[str]), moves); |
| 3054 | 3160 | for (k = 0; k < num_moves; k++) { |
| 3055 | 3161 | int move = moves[k]; |
| 3056 | 3162 | if (eyegraph_trymove(move, OTHER_COLOR(board[str]), "tactical_life-B", |
| 3057 | | str)) { |
| | 3163 | str, vertices)) { |
| 3058 | 3164 | if (board[str] == EMPTY |
| 3059 | | || !tactical_life_defend(str, num_vertices, vertices, results)) |
| | 3165 | || !tactical_life_defend(str, vertices, results)) |
| 3060 | 3166 | attack_points[(*num_attacks)++] = move; |
| 3061 | | popgo(); |
| | 3167 | eyegraph_popgo(); |
| 3062 | 3168 | } |
| 3063 | 3169 | } |
| 3064 | 3170 | } |
| 3065 | 3171 | |
| 3066 | 3172 | if (num_defenses != NULL && defense_points != NULL) { |
| 3067 | 3173 | *num_defenses = 0; |
| 3068 | | num_moves = eyegraph_order_moves(num_vertices, vertices, board[str], |
| 3069 | | moves); |
| | 3174 | num_moves = eyegraph_order_moves(vertices, board[str], moves); |
| 3070 | 3175 | for (k = 0; k < num_moves; k++) { |
| 3071 | 3176 | int move = moves[k]; |
| 3072 | | if (eyegraph_trymove(move, board[str], "tactical_life-C", str)) { |
| 3073 | | if (!tactical_life_attack(str, num_vertices, vertices, results)) |
| | 3177 | if (eyegraph_trymove(move, board[str], "tactical_life-C", str, |
| | 3178 | vertices)) { |
| | 3179 | if (!tactical_life_attack(str, vertices, results)) |
| 3074 | 3180 | defense_points[(*num_defenses)++] = move; |
| 3075 | | popgo(); |
| | 3181 | eyegraph_popgo(); |
| 3076 | 3182 | } |
| 3077 | 3183 | } |
| 3078 | 3184 | } |
| … |
… |
|
| 3080 | 3186 | |
| 3081 | 3187 | /* Unfill the extra eye if we didn't use it. */ |
| 3082 | 3188 | if (!have_eye) |
| 3083 | | popgo(); |
| | 3189 | eyegraph_popgo(); |
| 3084 | 3190 | } |
| 3085 | 3191 | |
| 3086 | 3192 | /* Determine the eye value of the eyespace for the big white group on |
| … |
… |
|
| 3095 | 3201 | * need to recursively call ourselves after a move has been made. |
| 3096 | 3202 | */ |
| 3097 | 3203 | static void |
| 3098 | | evaluate_eyespace(struct eyevalue *result, int num_vertices, int *vertices, |
| | 3204 | evaluate_eyespace(struct eyevalue *result, struct vertex_data *vertices, |
| 3099 | 3205 | int *num_vital_attacks, int *vital_attacks, |
| 3100 | 3206 | int *num_vital_defenses, int *vital_defenses, |
| 3101 | 3207 | unsigned char *tactical_life_results) |
| … |
… |
|
| 3123 | 3229 | *num_vital_defenses = 0; |
| 3124 | 3230 | |
| 3125 | 3231 | /* Determine tactical life without an extra eye. */ |
| 3126 | | tactical_life(0, num_vertices, vertices, |
| | 3232 | tactical_life(0, vertices, |
| 3127 | 3233 | &attack_code, &num_attacks, attack_points, |
| 3128 | 3234 | &defense_code, &num_defenses, defense_points, |
| 3129 | 3235 | tactical_life_results); |
| … |
… |
|
| 3139 | 3245 | if (sgf_dumptree) |
| 3140 | 3246 | sgftreeAddComment(sgf_dumptree, "Alive without extra eye.\n"); |
| 3141 | 3247 | |
| 3142 | | num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves); |
| | 3248 | num_moves = eyegraph_order_moves(vertices, BLACK, moves); |
| 3143 | 3249 | for (k = 0; k < num_moves; k++) { |
| 3144 | 3250 | int acode, dcode; |
| 3145 | 3251 | int move = moves[k]; |
| 3146 | | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-A", NO_MOVE)) { |
| 3147 | | tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, |
| | 3252 | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-A", NO_MOVE, |
| | 3253 | vertices)) { |
| | 3254 | tactical_life(0, vertices, &acode, NULL, NULL, |
| 3148 | 3255 | &dcode, NULL, NULL, tactical_life_results); |
| 3149 | 3256 | if (acode != 0) { |
| 3150 | | tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, |
| | 3257 | tactical_life(1, vertices, &acode, NULL, NULL, |
| 3151 | 3258 | &dcode, NULL, NULL, tactical_life_results); |
| 3152 | 3259 | if (acode != 0) { |
| 3153 | 3260 | if (a == 1) |
| … |
… |
|
| 3167 | 3274 | sgftreeAddComment(sgf_dumptree, "Ko threat to remove one eye.\n"); |
| 3168 | 3275 | } |
| 3169 | 3276 | } |
| 3170 | | popgo(); |
| | 3277 | eyegraph_popgo(); |
| 3171 | 3278 | } |
| 3172 | 3279 | } |
| 3173 | 3280 | set_eyevalue(result, a, 2, 2, 2); |
| … |
… |
|
| 3186 | 3293 | */ |
| 3187 | 3294 | if (sgf_dumptree) |
| 3188 | 3295 | sgftreeAddComment(sgf_dumptree, "Critical without extra eye.\n"); |
| 3189 | | tactical_life(1, num_vertices, vertices, |
| | 3296 | tactical_life(1, vertices, |
| 3190 | 3297 | &attack_code2, &num_attacks2, attack_points2, |
| 3191 | 3298 | &defense_code2, NULL, NULL, tactical_life_results); |
| 3192 | 3299 | for (k = 0; k < num_defenses; k++) |
| … |
… |
|
| 3203 | 3310 | int a = 1; |
| 3204 | 3311 | for (k = 0; k < num_attacks; k++) { |
| 3205 | 3312 | int move = attack_points[k]; |
| 3206 | | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-B", NO_MOVE)) { |
| 3207 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3313 | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-B", NO_MOVE, |
| | 3314 | vertices)) { |
| | 3315 | evaluate_eyespace(&result2, vertices, |
| 3208 | 3316 | &num_vital_attacks2, vital_attacks2, |
| 3209 | 3317 | &num_vital_defenses2, vital_defenses2, |
| 3210 | 3318 | tactical_life_results); |
| … |
… |
|
| 3221 | 3329 | } |
| 3222 | 3330 | else if (a == 1) |
| 3223 | 3331 | vital_attacks[(*num_vital_attacks)++] = move; |
| 3224 | | popgo(); |
| | 3332 | eyegraph_popgo(); |
| 3225 | 3333 | } |
| 3226 | 3334 | } |
| 3227 | 3335 | set_eyevalue(result, a, 1, 2, 2); |
| … |
… |
|
| 3241 | 3349 | */ |
| 3242 | 3350 | if (sgf_dumptree) |
| 3243 | 3351 | sgftreeAddComment(sgf_dumptree, "Dead without extra eye.\n"); |
| 3244 | | tactical_life(1, num_vertices, vertices, |
| | 3352 | tactical_life(1, vertices, |
| 3245 | 3353 | &attack_code, &num_attacks, attack_points, |
| 3246 | 3354 | &defense_code, &num_defenses, defense_points, |
| 3247 | 3355 | tactical_life_results); |
| … |
… |
|
| 3253 | 3361 | int d = 1; |
| 3254 | 3362 | if (sgf_dumptree) |
| 3255 | 3363 | sgftreeAddComment(sgf_dumptree, "Alive with extra eye.\n"); |
| 3256 | | num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves); |
| | 3364 | num_moves = eyegraph_order_moves(vertices, BLACK, moves); |
| 3257 | 3365 | for (k = 0; k < num_moves; k++) { |
| 3258 | 3366 | int acode, dcode; |
| 3259 | 3367 | int move = moves[k]; |
| 3260 | | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-C", NO_MOVE)) { |
| 3261 | | tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, |
| | 3368 | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-C", NO_MOVE, |
| | 3369 | vertices)) { |
| | 3370 | tactical_life(1, vertices, &acode, NULL, NULL, |
| 3262 | 3371 | &dcode, NULL, NULL, tactical_life_results); |
| 3263 | 3372 | if (acode != 0) { |
| 3264 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3373 | evaluate_eyespace(&result2, vertices, |
| 3265 | 3374 | &num_vital_attacks2, vital_attacks2, |
| 3266 | 3375 | &num_vital_defenses2, vital_defenses2, |
| 3267 | 3376 | tactical_life_results); |
| … |
… |
|
| 3273 | 3382 | sgftreeAddComment(sgf_dumptree, "Attacking ko threat.\n"); |
| 3274 | 3383 | } |
| 3275 | 3384 | } |
| 3276 | | popgo(); |
| | 3385 | eyegraph_popgo(); |
| 3277 | 3386 | } |
| 3278 | 3387 | } |
| 3279 | 3388 | |
| 3280 | | num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves); |
| | 3389 | num_moves = eyegraph_order_moves(vertices, WHITE, moves); |
| 3281 | 3390 | for (k = 0; k < num_moves; k++) { |
| 3282 | 3391 | int acode, dcode; |
| 3283 | 3392 | int move = moves[k]; |
| 3284 | | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-D", NO_MOVE)) { |
| 3285 | | tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, |
| | 3393 | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-D", NO_MOVE, |
| | 3394 | vertices)) { |
| | 3395 | tactical_life(0, vertices, &acode, NULL, NULL, |
| 3286 | 3396 | &dcode, NULL, NULL, tactical_life_results); |
| 3287 | 3397 | if (dcode != 0) { |
| 3288 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3398 | evaluate_eyespace(&result2, vertices, |
| 3289 | 3399 | &num_vital_attacks2, vital_attacks2, |
| 3290 | 3400 | &num_vital_defenses2, vital_defenses2, |
| 3291 | 3401 | tactical_life_results); |
| … |
… |
|
| 3297 | 3407 | sgftreeAddComment(sgf_dumptree, "Defending ko threat.\n"); |
| 3298 | 3408 | } |
| 3299 | 3409 | } |
| 3300 | | popgo(); |
| | 3410 | eyegraph_popgo(); |
| 3301 | 3411 | } |
| 3302 | 3412 | } |
| 3303 | 3413 | set_eyevalue(result, a, 1, 1, d); |
| … |
… |
|
| 3323 | 3433 | vital_attacks[(*num_vital_attacks)++] = attack_points[k]; |
| 3324 | 3434 | for (k = 0; k < num_defenses; k++) { |
| 3325 | 3435 | int move = defense_points[k]; |
| 3326 | | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-E", NO_MOVE)) { |
| 3327 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3436 | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-E", NO_MOVE, |
| | 3437 | vertices)) { |
| | 3438 | evaluate_eyespace(&result2, vertices, |
| 3328 | 3439 | &num_vital_attacks2, vital_attacks2, |
| 3329 | 3440 | &num_vital_defenses2, vital_defenses2, |
| 3330 | 3441 | tactical_life_results); |
| … |
… |
|
| 3341 | 3452 | } |
| 3342 | 3453 | else if (d == 1) |
| 3343 | 3454 | vital_defenses[(*num_vital_defenses)++] = move; |
| 3344 | | popgo(); |
| | 3455 | eyegraph_popgo(); |
| 3345 | 3456 | } |
| 3346 | 3457 | } |
| 3347 | 3458 | set_eyevalue(result, 0, 0, 1, d); |
| … |
… |
|
| 3361 | 3472 | int d = 0; |
| 3362 | 3473 | if (sgf_dumptree) |
| 3363 | 3474 | sgftreeAddComment(sgf_dumptree, "Dead with extra eye.\n"); |
| 3364 | | num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves); |
| | 3475 | num_moves = eyegraph_order_moves(vertices, WHITE, moves); |
| 3365 | 3476 | for (k = 0; k < num_moves; k++) { |
| 3366 | 3477 | int acode, dcode; |
| 3367 | 3478 | int move = moves[k]; |
| 3368 | | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-F", NO_MOVE)) { |
| 3369 | | tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, |
| | 3479 | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-F", NO_MOVE, |
| | 3480 | vertices)) { |
| | 3481 | tactical_life(1, vertices, &acode, NULL, NULL, |
| 3370 | 3482 | &dcode, NULL, NULL, tactical_life_results); |
| 3371 | 3483 | if (dcode != 0) { |
| 3372 | | tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, |
| | 3484 | tactical_life(0, vertices, &acode, NULL, NULL, |
| 3373 | 3485 | &dcode, NULL, NULL, tactical_life_results); |
| 3374 | 3486 | if (dcode != 0) { |
| 3375 | 3487 | if (d == 1) |
| … |
… |
|
| 3390 | 3502 | "Ko threat to make one eye.\n"); |
| 3391 | 3503 | } |
| 3392 | 3504 | } |
| 3393 | | popgo(); |
| | 3505 | eyegraph_popgo(); |
| 3394 | 3506 | } |
| 3395 | 3507 | } |
| 3396 | 3508 | set_eyevalue(result, 0, 0, 0, d); |
| … |
… |
|
| 3477 | 3589 | * !.*. |
| 3478 | 3590 | * |
| 3479 | 3591 | * If the eye graph cannot be realized, 0 is returned, 1 otherwise. |
| | 3592 | * |
| | 3593 | * The parameter outer_liberties determines how many external |
| | 3594 | * liberties will be attached, excluding the one which is sometimes |
| | 3595 | * provided by a second eye. Up to five outer liberties can be provided. |
| | 3596 | * |
| | 3597 | * The parameter ko_threats tells how many ko_threats one of the |
| | 3598 | * players is allowed to ignore. Positive values mean that the |
| | 3599 | * defender is allowed to ignore ko threats and negative that the |
| | 3600 | * attacker can do so. The other player is allowed to spend a move to |
| | 3601 | * reduce this number, which is usually not the best thing to do with |
| | 3602 | * a move but allows a correct understanding of the bent four in the |
| | 3603 | * corner shapes. At most 4 ignored ko threats are considered. |
| 3480 | 3604 | */ |
| 3481 | 3605 | int |
| 3482 | 3606 | analyze_eyegraph(const char *coded_eyegraph, struct eyevalue *value, |
| 3483 | | char *analyzed_eyegraph) |
| | 3607 | char *analyzed_eyegraph, int outer_liberties, |
| | 3608 | int ko_threats) |
| 3484 | 3609 | { |
| 3485 | 3610 | int k; |
| 3486 | 3611 | int i, j; |
| … |
… |
|
| 3488 | 3613 | int mx[BOARDMAX]; |
| 3489 | 3614 | char mg[BOARDMAX]; |
| 3490 | 3615 | int pos; |
| | 3616 | int corner; |
| | 3617 | int up; |
| | 3618 | int right; |
| 3491 | 3619 | |
| 3492 | 3620 | int num_vital_attacks; |
| 3493 | 3621 | int vital_attacks[BOARDMAX]; /* Way larger than necessary. */ |
| … |
… |
|
| 3503 | 3631 | int num_margins; |
| 3504 | 3632 | int margins[BOARDMAX]; /* Way larger than necessary. */ |
| 3505 | 3633 | |
| 3506 | | int num_vertices; |
| 3507 | | int vertices[BOARDMAX]; /* Way larger than necessary. */ |
| 3508 | | |
| | 3634 | struct vertex_data vertices; |
| | 3635 | |
| 3509 | 3636 | int table_size; |
| 3510 | 3637 | unsigned char *tactical_life_results; |
| 3511 | 3638 | |
| 3512 | 3639 | if (0) |
| 3513 | 3640 | gprintf("Analyze eyegraph %s\n", coded_eyegraph); |
| | 3641 | |
| | 3642 | gg_assert(outer_liberties >= 0 && outer_liberties <= 5); |
| | 3643 | gg_assert(ko_threats >= -4 && ko_threats <= 4); |
| | 3644 | |
| | 3645 | if (ko_threats > 0) |
| | 3646 | vertices.komaster = WHITE; |
| | 3647 | else if (ko_threats == 0) |
| | 3648 | vertices.komaster = EMPTY; |
| | 3649 | else { |
| | 3650 | vertices.komaster = BLACK; |
| | 3651 | ko_threats = -ko_threats; |
| | 3652 | } |
| 3514 | 3653 | |
| 3515 | 3654 | /* Mark the eyespace in the mx array. We construct the position in |
| 3516 | 3655 | * the mx array and copy it to the actual board later. |
| … |
… |
|
| 3530 | 3669 | for (k = 0; k < (int) strlen(coded_eyegraph); k++) { |
| 3531 | 3670 | if (coded_eyegraph[k] == '\n') |
| 3532 | 3671 | continue; |
| | 3672 | if (coded_eyegraph[k] == ' ') |
| | 3673 | |