RCS file: /cvsroot/gnugo/gnugo/engine/optics.c,v
retrieving revision 1.101
diff -u -r1.101 optics.c
|
|
|
|
| 2675 | 2675 | * 3 - result has been computed and was a success (1) |
| 2676 | 2676 | */ |
| 2677 | 2677 | |
| | 2678 | /* Types of vertices under consideration. */ |
| | 2679 | #define REGULAR 0 |
| | 2680 | #define OUTER_LIBERTY 1 |
| | 2681 | #define EXTRA_EYE 2 |
| | 2682 | #define KO_THREAT 3 |
| | 2683 | |
| | 2684 | struct vertex_data { |
| | 2685 | int pos[MAX_BOARD]; |
| | 2686 | int type[MAX_BOARD]; |
| | 2687 | int num; |
| | 2688 | int ko_threat_pos; |
| | 2689 | }; |
| | 2690 | |
| 2678 | 2691 | /* Like trymove() except that it does a superko check. This does, |
| 2679 | 2692 | * however, only disallow repetition (besides simple ko) if the move |
| 2680 | 2693 | * does not capture any stones. |
| | 2694 | * |
| | 2695 | * In order to cope with bent four in the corner, white is given one |
| | 2696 | * free virtual ko threat, which black can eliminate by spending a |
| | 2697 | * move playing on the "ko threat vertex". This has the side effect |
| | 2698 | * that white wins all direct kos, which is mostly okay until ko |
| | 2699 | * dependent eye values are implemented. It can, however, cause attack |
| | 2700 | * and defense points dependent on ko to be recommended together with |
| | 2701 | * non-ko vital points. |
| 2681 | 2702 | */ |
| | 2703 | |
| | 2704 | static int forced_ko_threat_stackp = -1; |
| | 2705 | |
| 2682 | 2706 | static int |
| 2683 | | eyegraph_trymove(int pos, int color, const char *message, int str) |
| | 2707 | eyegraph_trymove(int pos, int color, const char *message, int str, |
| | 2708 | int ko_threat_pos) |
| 2684 | 2709 | { |
| 2685 | 2710 | static Hash_data remembered_board_hashes[MAXSTACK]; |
| 2686 | 2711 | int k; |
| 2687 | 2712 | int does_capture = does_capture_something(pos, color); |
| 2688 | 2713 | |
| 2689 | 2714 | remembered_board_hashes[stackp] = board_hash; |
| 2690 | | |
| 2691 | | if (!trymove(pos, color, message, str)) |
| 2692 | | return 0; |
| | 2715 | |
| | 2716 | if (!trymove(pos, color, message, str)) { |
| | 2717 | if (color == WHITE |
| | 2718 | && !is_suicide(pos, color) |
| | 2719 | && board[ko_threat_pos] == EMPTY) { |
| | 2720 | trymove(ko_threat_pos, BLACK, "answering virtual ko threat", str); |
| | 2721 | forced_ko_threat_stackp = stackp; |
| | 2722 | trymove(pos, color, message, str); |
| | 2723 | } |
| | 2724 | else |
| | 2725 | return 0; |
| | 2726 | } |
| 2693 | 2727 | |
| 2694 | 2728 | if (does_capture) |
| 2695 | 2729 | return 1; |
| … |
… |
|
| 2700 | 2734 | return 0; |
| 2701 | 2735 | } |
| 2702 | 2736 | |
| | 2737 | |
| 2703 | 2738 | return 1; |
| 2704 | 2739 | } |
| 2705 | 2740 | |
| | 2741 | static void |
| | 2742 | eyegraph_popgo(void) |
| | 2743 | { |
| | 2744 | popgo(); |
| | 2745 | |
| | 2746 | if (forced_ko_threat_stackp == stackp) { |
| | 2747 | popgo(); |
| | 2748 | forced_ko_threat_stackp = -1; |
| | 2749 | } |
| | 2750 | } |
| | 2751 | |
| | 2752 | /* Has the vertex a neighbor which is connected to an invincible black |
| | 2753 | * string? |
| | 2754 | */ |
| 2706 | 2755 | static int |
| 2707 | 2756 | eyegraph_is_margin_or_outer_liberty(int vertex) |
| 2708 | 2757 | { |
| … |
… |
|
| 2729 | 2778 | } |
| 2730 | 2779 | |
| 2731 | 2780 | static int |
| 2732 | | eyegraph_order_moves(int num_vertices, int *vertices, int color_to_move, int *moves) |
| | 2781 | eyegraph_order_moves(struct vertex_data *vertices, int color_to_move, |
| | 2782 | int *moves) |
| 2733 | 2783 | { |
| 2734 | 2784 | int num_moves = 0; |
| 2735 | 2785 | int scores[BOARDMAX]; |
| … |
… |
|
| 2738 | 2788 | int k; |
| 2739 | 2789 | int r; |
| 2740 | 2790 | |
| 2741 | | for (k = 0; k < num_vertices; k++) { |
| 2742 | | if (k >= num_vertices - 3) { |
| | 2791 | for (k = 0; k < vertices->num; k++) { |
| | 2792 | if (vertices->type[k] != REGULAR) { |
| 2743 | 2793 | /* Never useful for white to fill in outer liberties or a second eye. */ |
| 2744 | 2794 | if (color_to_move == WHITE) |
| 2745 | 2795 | break; |
| 2746 | | /* No use playing the second outer liberty before the first one. */ |
| 2747 | | if (k == num_vertices - 2 && board[vertices[num_vertices - 3]] == EMPTY) |
| | 2796 | /* No use playing a later outer liberty before the previous one. */ |
| | 2797 | if (vertices->type[k] == OUTER_LIBERTY |
| | 2798 | && vertices->type[k - 1] == OUTER_LIBERTY |
| | 2799 | && board[vertices->pos[k - 1]] == EMPTY) |
| 2748 | 2800 | continue; |
| 2749 | 2801 | } |
| 2750 | 2802 | |
| 2751 | | move = vertices[k]; |
| | 2803 | move = vertices->pos[k]; |
| 2752 | 2804 | score = 0; |
| 2753 | 2805 | |
| 2754 | 2806 | if (board[move] != EMPTY) |
| 2755 | 2807 | continue; |
| 2756 | 2808 | |
| 2757 | | if (eyegraph_is_margin_or_outer_liberty(move)) { |
| 2758 | | if (k < num_vertices - 3) |
| | 2809 | if (eyegraph_is_margin_or_outer_liberty(move)) |
| | 2810 | if (vertices->type[k] == REGULAR) |
| 2759 | 2811 | score = 5; /* margin */ |
| 2760 | | else |
| 2761 | | score = -10; /* outer liberty */ |
| 2762 | | } |
| 2763 | 2812 | |
| 2764 | 2813 | if (accuratelib(move, color_to_move, 2, NULL) == 1) |
| 2765 | 2814 | score -= 3; |
| … |
… |
|
| 2861 | 2910 | return (result); \ |
| 2862 | 2911 | } while (0); |
| 2863 | 2912 | |
| 2864 | | static int tactical_life_defend(int str, int num_vertices, int *vertices, |
| | 2913 | static int tactical_life_defend(int str, struct vertex_data *vertices, |
| 2865 | 2914 | unsigned char *results); |
| 2866 | 2915 | |
| 2867 | 2916 | /* Determine whether black can capture all white stones. */ |
| 2868 | 2917 | static int |
| 2869 | | tactical_life_attack(int str, int num_vertices, int *vertices, |
| | 2918 | tactical_life_attack(int str, struct vertex_data *vertices, |
| 2870 | 2919 | unsigned char *results) |
| 2871 | 2920 | { |
| 2872 | 2921 | int k; |
| … |
… |
|
| 2877 | 2926 | int moves[BOARDMAX]; |
| 2878 | 2927 | |
| 2879 | 2928 | /* Compute hash value to index the result cache with. */ |
| 2880 | | for (k = 0; k < num_vertices; k++) { |
| | 2929 | for (k = 0; k < vertices->num; k++) { |
| 2881 | 2930 | hash *= 3; |
| 2882 | | hash += board[vertices[k]]; |
| | 2931 | hash += board[vertices->pos[k]]; |
| 2883 | 2932 | } |
| 2884 | 2933 | hash *= 2; |
| 2885 | 2934 | hash += (board_ko_pos != NO_MOVE); |
| … |
… |
|
| 2903 | 2952 | results[hash] |= 1; |
| 2904 | 2953 | |
| 2905 | 2954 | /* Try to play on all relevant vertices. */ |
| 2906 | | num_moves = eyegraph_order_moves(num_vertices, vertices, |
| 2907 | | OTHER_COLOR(board[str]), moves); |
| | 2955 | num_moves = eyegraph_order_moves(vertices, OTHER_COLOR(board[str]), moves); |
| 2908 | 2956 | for (k = 0; k < num_moves; k++) { |
| 2909 | 2957 | int move = moves[k]; |
| 2910 | 2958 | if (eyegraph_trymove(move, OTHER_COLOR(board[str]), |
| 2911 | | "tactical_life_attack", str)) { |
| | 2959 | "tactical_life_attack", str, |
| | 2960 | vertices->ko_threat_pos)) { |
| 2912 | 2961 | /* We were successful if the white stones were captured or if no |
| 2913 | 2962 | * defense can be found. |
| 2914 | 2963 | */ |
| 2915 | 2964 | if (board[str] == EMPTY) |
| 2916 | 2965 | result = 1; |
| 2917 | 2966 | else |
| 2918 | | result = !tactical_life_defend(str, num_vertices, vertices, results); |
| | 2967 | result = !tactical_life_defend(str, vertices, results); |
| 2919 | 2968 | |
| 2920 | | popgo(); |
| | 2969 | eyegraph_popgo(); |
| 2921 | 2970 | |
| 2922 | 2971 | if (result == 1) { |
| 2923 | 2972 | /* Store the result (success) in the cache. */ |
| … |
… |
|
| 2934 | 2983 | |
| 2935 | 2984 | /* Determine whether white can live with all stones. */ |
| 2936 | 2985 | static int |
| 2937 | | tactical_life_defend(int str, int num_vertices, int *vertices, |
| | 2986 | tactical_life_defend(int str, struct vertex_data *vertices, |
| 2938 | 2987 | unsigned char *results) |
| 2939 | 2988 | { |
| 2940 | 2989 | int k; |
| … |
… |
|
| 2945 | 2994 | int moves[BOARDMAX]; |
| 2946 | 2995 | |
| 2947 | 2996 | /* Compute hash value to index the result cache with. */ |
| 2948 | | for (k = 0; k < num_vertices; k++) { |
| | 2997 | for (k = 0; k < vertices->num; k++) { |
| 2949 | 2998 | hash *= 3; |
| 2950 | | ASSERT1(board[vertices[k]] <= 2, vertices[k]); |
| 2951 | | hash += board[vertices[k]]; |
| | 2999 | ASSERT1(board[vertices->pos[k]] <= 2, vertices->pos[k]); |
| | 3000 | hash += board[vertices->pos[k]]; |
| 2952 | 3001 | } |
| 2953 | 3002 | hash *= 2; |
| 2954 | 3003 | hash += (board_ko_pos != NO_MOVE); |
| … |
… |
|
| 2972 | 3021 | results[hash] |= (1 << 2); |
| 2973 | 3022 | |
| 2974 | 3023 | /* Try to play on all relevant vertices. */ |
| 2975 | | num_moves = eyegraph_order_moves(num_vertices, vertices, board[str], moves); |
| | 3024 | num_moves = eyegraph_order_moves(vertices, board[str], moves); |
| 2976 | 3025 | for (k = 0; k < num_moves; k++) { |
| 2977 | 3026 | int move = moves[k]; |
| 2978 | 3027 | if ((!is_suicide(move, OTHER_COLOR(board[str])) |
| 2979 | 3028 | || does_capture_something(move, board[str])) |
| 2980 | | && eyegraph_trymove(move, board[str], "tactical_life_defend", str)) { |
| | 3029 | && eyegraph_trymove(move, board[str], "tactical_life_defend", str, |
| | 3030 | vertices->ko_threat_pos)) { |
| 2981 | 3031 | /* We were successful if no attack can be found. */ |
| 2982 | | result = !tactical_life_attack(str, num_vertices, vertices, results); |
| | 3032 | result = !tactical_life_attack(str, vertices, results); |
| 2983 | 3033 | |
| 2984 | | popgo(); |
| | 3034 | eyegraph_popgo(); |
| 2985 | 3035 | |
| 2986 | 3036 | if (result == 1) { |
| 2987 | 3037 | /* Store the result (success) in the cache. */ |
| … |
… |
|
| 2992 | 3042 | } |
| 2993 | 3043 | |
| 2994 | 3044 | /* If no move worked, also try passing. */ |
| 2995 | | if (!tactical_life_attack(str, num_vertices, vertices, results)) { |
| | 3045 | if (!tactical_life_attack(str, vertices, results)) { |
| 2996 | 3046 | /* Store the result (success) in the cache. */ |
| 2997 | 3047 | results[hash] = (results[hash] & (~12)) | (3 << 2); |
| 2998 | 3048 | EYEGRAPH_RETURN(1, "tactical_life_defend: win"); |
| … |
… |
|
| 3009 | 3059 | * used or filled in before starting reading. |
| 3010 | 3060 | */ |
| 3011 | 3061 | static void |
| 3012 | | tactical_life(int have_eye, int num_vertices, int *vertices, |
| | 3062 | tactical_life(int have_eye, struct vertex_data *vertices, |
| 3013 | 3063 | int *attack_code, int *num_attacks, int *attack_points, |
| 3014 | 3064 | int *defense_code, int *num_defenses, int *defense_points, |
| 3015 | 3065 | unsigned char *results) |
| … |
… |
|
| 3038 | 3088 | * suicide the white stones can be considered dead. |
| 3039 | 3089 | */ |
| 3040 | 3090 | if (!have_eye) { |
| 3041 | | if (!eyegraph_trymove(POS(0, 0), WHITE, "tactical_life-A", NO_MOVE)) { |
| | 3091 | if (!eyegraph_trymove(POS(0, 0), WHITE, "tactical_life-A", NO_MOVE, |
| | 3092 | NO_MOVE)) { |
| 3042 | 3093 | *attack_code = WIN; |
| 3043 | 3094 | *defense_code = 0; |
| 3044 | 3095 | return; |
| … |
… |
|
| 3051 | 3102 | /* Call tactical_life_attack() and tactical_life_defend() to |
| 3052 | 3103 | * determine status. |
| 3053 | 3104 | */ |
| 3054 | | if (tactical_life_attack(str, num_vertices, vertices, results)) { |
| | 3105 | if (tactical_life_attack(str, vertices, results)) { |
| 3055 | 3106 | *attack_code = WIN; |
| 3056 | | if (tactical_life_defend(str, num_vertices, vertices, results)) |
| | 3107 | if (tactical_life_defend(str, vertices, results)) |
| 3057 | 3108 | *defense_code = WIN; |
| 3058 | 3109 | } |
| 3059 | 3110 | else |
| … |
… |
|
| 3067 | 3118 | if (*attack_code != 0 && *defense_code != 0) { |
| 3068 | 3119 | if (num_attacks != NULL && attack_points != NULL) { |
| 3069 | 3120 | *num_attacks = 0; |
| 3070 | | num_moves = eyegraph_order_moves(num_vertices, vertices, |
| | 3121 | num_moves = eyegraph_order_moves(vertices, |
| 3071 | 3122 | OTHER_COLOR(board[str]), moves); |
| 3072 | 3123 | for (k = 0; k < num_moves; k++) { |
| 3073 | 3124 | int move = moves[k]; |
| 3074 | 3125 | if (eyegraph_trymove(move, OTHER_COLOR(board[str]), "tactical_life-B", |
| 3075 | | str)) { |
| | 3126 | str, vertices->ko_threat_pos)) { |
| 3076 | 3127 | if (board[str] == EMPTY |
| 3077 | | || !tactical_life_defend(str, num_vertices, vertices, results)) |
| | 3128 | || !tactical_life_defend(str, vertices, results)) |
| 3078 | 3129 | attack_points[(*num_attacks)++] = move; |
| 3079 | | popgo(); |
| | 3130 | eyegraph_popgo(); |
| 3080 | 3131 | } |
| 3081 | 3132 | } |
| 3082 | 3133 | } |
| 3083 | 3134 | |
| 3084 | 3135 | if (num_defenses != NULL && defense_points != NULL) { |
| 3085 | 3136 | *num_defenses = 0; |
| 3086 | | num_moves = eyegraph_order_moves(num_vertices, vertices, board[str], |
| 3087 | | moves); |
| | 3137 | num_moves = eyegraph_order_moves(vertices, board[str], moves); |
| 3088 | 3138 | for (k = 0; k < num_moves; k++) { |
| 3089 | 3139 | int move = moves[k]; |
| 3090 | | if (eyegraph_trymove(move, board[str], "tactical_life-C", str)) { |
| 3091 | | if (!tactical_life_attack(str, num_vertices, vertices, results)) |
| | 3140 | if (eyegraph_trymove(move, board[str], "tactical_life-C", str, |
| | 3141 | vertices->ko_threat_pos)) { |
| | 3142 | if (!tactical_life_attack(str, vertices, results)) |
| 3092 | 3143 | defense_points[(*num_defenses)++] = move; |
| 3093 | | popgo(); |
| | 3144 | eyegraph_popgo(); |
| 3094 | 3145 | } |
| 3095 | 3146 | } |
| 3096 | 3147 | } |
| … |
… |
|
| 3098 | 3149 | |
| 3099 | 3150 | /* Unfill the extra eye if we didn't use it. */ |
| 3100 | 3151 | if (!have_eye) |
| 3101 | | popgo(); |
| | 3152 | eyegraph_popgo(); |
| 3102 | 3153 | } |
| 3103 | 3154 | |
| 3104 | 3155 | /* Determine the eye value of the eyespace for the big white group on |
| … |
… |
|
| 3113 | 3164 | * need to recursively call ourselves after a move has been made. |
| 3114 | 3165 | */ |
| 3115 | 3166 | static void |
| 3116 | | evaluate_eyespace(struct eyevalue *result, int num_vertices, int *vertices, |
| | 3167 | evaluate_eyespace(struct eyevalue *result, struct vertex_data *vertices, |
| 3117 | 3168 | int *num_vital_attacks, int *vital_attacks, |
| 3118 | 3169 | int *num_vital_defenses, int *vital_defenses, |
| 3119 | 3170 | unsigned char *tactical_life_results) |
| … |
… |
|
| 3141 | 3192 | *num_vital_defenses = 0; |
| 3142 | 3193 | |
| 3143 | 3194 | /* Determine tactical life without an extra eye. */ |
| 3144 | | tactical_life(0, num_vertices, vertices, |
| | 3195 | tactical_life(0, vertices, |
| 3145 | 3196 | &attack_code, &num_attacks, attack_points, |
| 3146 | 3197 | &defense_code, &num_defenses, defense_points, |
| 3147 | 3198 | tactical_life_results); |
| … |
… |
|
| 3157 | 3208 | if (sgf_dumptree) |
| 3158 | 3209 | sgftreeAddComment(sgf_dumptree, "Alive without extra eye.\n"); |
| 3159 | 3210 | |
| 3160 | | num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves); |
| | 3211 | num_moves = eyegraph_order_moves(vertices, BLACK, moves); |
| 3161 | 3212 | for (k = 0; k < num_moves; k++) { |
| 3162 | 3213 | int acode, dcode; |
| 3163 | 3214 | int move = moves[k]; |
| 3164 | | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-A", NO_MOVE)) { |
| 3165 | | tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, |
| | 3215 | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-A", NO_MOVE, |
| | 3216 | vertices->ko_threat_pos)) { |
| | 3217 | tactical_life(0, vertices, &acode, NULL, NULL, |
| 3166 | 3218 | &dcode, NULL, NULL, tactical_life_results); |
| 3167 | 3219 | if (acode != 0) { |
| 3168 | | tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, |
| | 3220 | tactical_life(1, vertices, &acode, NULL, NULL, |
| 3169 | 3221 | &dcode, NULL, NULL, tactical_life_results); |
| 3170 | 3222 | if (acode != 0) { |
| 3171 | 3223 | if (a == 1) |
| … |
… |
|
| 3185 | 3237 | sgftreeAddComment(sgf_dumptree, "Ko threat to remove one eye.\n"); |
| 3186 | 3238 | } |
| 3187 | 3239 | } |
| 3188 | | popgo(); |
| | 3240 | eyegraph_popgo(); |
| 3189 | 3241 | } |
| 3190 | 3242 | } |
| 3191 | 3243 | set_eyevalue(result, a, 2, 2, 2); |
| … |
… |
|
| 3204 | 3256 | */ |
| 3205 | 3257 | if (sgf_dumptree) |
| 3206 | 3258 | sgftreeAddComment(sgf_dumptree, "Critical without extra eye.\n"); |
| 3207 | | tactical_life(1, num_vertices, vertices, |
| | 3259 | tactical_life(1, vertices, |
| 3208 | 3260 | &attack_code2, &num_attacks2, attack_points2, |
| 3209 | 3261 | &defense_code2, NULL, NULL, tactical_life_results); |
| 3210 | 3262 | for (k = 0; k < num_defenses; k++) |
| … |
… |
|
| 3221 | 3273 | int a = 1; |
| 3222 | 3274 | for (k = 0; k < num_attacks; k++) { |
| 3223 | 3275 | int move = attack_points[k]; |
| 3224 | | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-B", NO_MOVE)) { |
| 3225 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3276 | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-B", NO_MOVE, |
| | 3277 | vertices->ko_threat_pos)) { |
| | 3278 | evaluate_eyespace(&result2, vertices, |
| 3226 | 3279 | &num_vital_attacks2, vital_attacks2, |
| 3227 | 3280 | &num_vital_defenses2, vital_defenses2, |
| 3228 | 3281 | tactical_life_results); |
| … |
… |
|
| 3239 | 3292 | } |
| 3240 | 3293 | else if (a == 1) |
| 3241 | 3294 | vital_attacks[(*num_vital_attacks)++] = move; |
| 3242 | | popgo(); |
| | 3295 | eyegraph_popgo(); |
| 3243 | 3296 | } |
| 3244 | 3297 | } |
| 3245 | 3298 | set_eyevalue(result, a, 1, 2, 2); |
| … |
… |
|
| 3259 | 3312 | */ |
| 3260 | 3313 | if (sgf_dumptree) |
| 3261 | 3314 | sgftreeAddComment(sgf_dumptree, "Dead without extra eye.\n"); |
| 3262 | | tactical_life(1, num_vertices, vertices, |
| | 3315 | tactical_life(1, vertices, |
| 3263 | 3316 | &attack_code, &num_attacks, attack_points, |
| 3264 | 3317 | &defense_code, &num_defenses, defense_points, |
| 3265 | 3318 | tactical_life_results); |
| … |
… |
|
| 3271 | 3324 | int d = 1; |
| 3272 | 3325 | if (sgf_dumptree) |
| 3273 | 3326 | sgftreeAddComment(sgf_dumptree, "Alive with extra eye.\n"); |
| 3274 | | num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves); |
| | 3327 | num_moves = eyegraph_order_moves(vertices, BLACK, moves); |
| 3275 | 3328 | for (k = 0; k < num_moves; k++) { |
| 3276 | 3329 | int acode, dcode; |
| 3277 | 3330 | int move = moves[k]; |
| 3278 | | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-C", NO_MOVE)) { |
| 3279 | | tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, |
| | 3331 | if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-C", NO_MOVE, |
| | 3332 | vertices->ko_threat_pos)) { |
| | 3333 | tactical_life(1, vertices, &acode, NULL, NULL, |
| 3280 | 3334 | &dcode, NULL, NULL, tactical_life_results); |
| 3281 | 3335 | if (acode != 0) { |
| 3282 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3336 | evaluate_eyespace(&result2, vertices, |
| 3283 | 3337 | &num_vital_attacks2, vital_attacks2, |
| 3284 | 3338 | &num_vital_defenses2, vital_defenses2, |
| 3285 | 3339 | tactical_life_results); |
| … |
… |
|
| 3291 | 3345 | sgftreeAddComment(sgf_dumptree, "Attacking ko threat.\n"); |
| 3292 | 3346 | } |
| 3293 | 3347 | } |
| 3294 | | popgo(); |
| | 3348 | eyegraph_popgo(); |
| 3295 | 3349 | } |
| 3296 | 3350 | } |
| 3297 | 3351 | |
| 3298 | | num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves); |
| | 3352 | num_moves = eyegraph_order_moves(vertices, WHITE, moves); |
| 3299 | 3353 | for (k = 0; k < num_moves; k++) { |
| 3300 | 3354 | int acode, dcode; |
| 3301 | 3355 | int move = moves[k]; |
| 3302 | | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-D", NO_MOVE)) { |
| 3303 | | tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, |
| | 3356 | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-D", NO_MOVE, |
| | 3357 | vertices->ko_threat_pos)) { |
| | 3358 | tactical_life(0, vertices, &acode, NULL, NULL, |
| 3304 | 3359 | &dcode, NULL, NULL, tactical_life_results); |
| 3305 | 3360 | if (dcode != 0) { |
| 3306 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3361 | evaluate_eyespace(&result2, vertices, |
| 3307 | 3362 | &num_vital_attacks2, vital_attacks2, |
| 3308 | 3363 | &num_vital_defenses2, vital_defenses2, |
| 3309 | 3364 | tactical_life_results); |
| … |
… |
|
| 3315 | 3370 | sgftreeAddComment(sgf_dumptree, "Defending ko threat.\n"); |
| 3316 | 3371 | } |
| 3317 | 3372 | } |
| 3318 | | popgo(); |
| | 3373 | eyegraph_popgo(); |
| 3319 | 3374 | } |
| 3320 | 3375 | } |
| 3321 | 3376 | set_eyevalue(result, a, 1, 1, d); |
| … |
… |
|
| 3341 | 3396 | vital_attacks[(*num_vital_attacks)++] = attack_points[k]; |
| 3342 | 3397 | for (k = 0; k < num_defenses; k++) { |
| 3343 | 3398 | int move = defense_points[k]; |
| 3344 | | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-E", NO_MOVE)) { |
| 3345 | | evaluate_eyespace(&result2, num_vertices, vertices, |
| | 3399 | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-E", NO_MOVE, |
| | 3400 | vertices->ko_threat_pos)) { |
| | 3401 | evaluate_eyespace(&result2, vertices, |
| 3346 | 3402 | &num_vital_attacks2, vital_attacks2, |
| 3347 | 3403 | &num_vital_defenses2, vital_defenses2, |
| 3348 | 3404 | tactical_life_results); |
| … |
… |
|
| 3359 | 3415 | } |
| 3360 | 3416 | else if (d == 1) |
| 3361 | 3417 | vital_defenses[(*num_vital_defenses)++] = move; |
| 3362 | | popgo(); |
| | 3418 | eyegraph_popgo(); |
| 3363 | 3419 | } |
| 3364 | 3420 | } |
| 3365 | 3421 | set_eyevalue(result, 0, 0, 1, d); |
| … |
… |
|
| 3379 | 3435 | int d = 0; |
| 3380 | 3436 | if (sgf_dumptree) |
| 3381 | 3437 | sgftreeAddComment(sgf_dumptree, "Dead with extra eye.\n"); |
| 3382 | | num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves); |
| | 3438 | num_moves = eyegraph_order_moves(vertices, WHITE, moves); |
| 3383 | 3439 | for (k = 0; k < num_moves; k++) { |
| 3384 | 3440 | int acode, dcode; |
| 3385 | 3441 | int move = moves[k]; |
| 3386 | | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-F", NO_MOVE)) { |
| 3387 | | tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, |
| | 3442 | if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-F", NO_MOVE, |
| | 3443 | vertices->ko_threat_pos)) { |
| | 3444 | tactical_life(1, vertices, &acode, NULL, NULL, |
| 3388 | 3445 | &dcode, NULL, NULL, tactical_life_results); |
| 3389 | 3446 | if (dcode != 0) { |
| 3390 | | tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, |
| | 3447 | tactical_life(0, vertices, &acode, NULL, NULL, |
| 3391 | 3448 | &dcode, NULL, NULL, tactical_life_results); |
| 3392 | 3449 | if (dcode != 0) { |
| 3393 | 3450 | if (d == 1) |
| … |
… |
|
| 3408 | 3465 | "Ko threat to make one eye.\n"); |
| 3409 | 3466 | } |
| 3410 | 3467 | } |
| 3411 | | popgo(); |
| | 3468 | eyegraph_popgo(); |
| 3412 | 3469 | } |
| 3413 | 3470 | } |
| 3414 | 3471 | set_eyevalue(result, 0, 0, 0, d); |
| … |
… |
|
| 3521 | 3578 | int num_margins; |
| 3522 | 3579 | int margins[BOARDMAX]; /* Way larger than necessary. */ |
| 3523 | 3580 | |
| 3524 | | int num_vertices; |
| 3525 | | int vertices[BOARDMAX]; /* Way larger than necessary. */ |
| 3526 | | |
| | 3581 | struct vertex_data vertices; |
| | 3582 | |
| 3527 | 3583 | int table_size; |
| 3528 | 3584 | unsigned char *tactical_life_results; |
| 3529 | 3585 | |
| … |
… |
|
| 3567 | 3623 | |
| 3568 | 3624 | /* Cut out the eyespace from the solid white string. */ |
| 3569 | 3625 | num_margins = 0; |
| 3570 | | num_vertices = 0; |
| | 3626 | vertices.num = 0; |
| 3571 | 3627 | |
| 3572 | 3628 | if (horizontal_edge == 0) |
| 3573 | 3629 | mini = -1; |
| … |
… |
|
| 3601 | 3657 | if (c == '!' || c == '@' || c == '(' || c == ')' || c == '$') |
| 3602 | 3658 | margins[num_margins++] = POS(i, j); |
| 3603 | 3659 | if (c != '|' && c != '-' && c != '+' && c != '%' |
| 3604 | | && ON_BOARD(POS(i, j)) && mx[POS(i, j)] != WHITE) |
| 3605 | | vertices[num_vertices++] = POS(i, j); |
| | 3660 | && ON_BOARD(POS(i, j)) && mx[POS(i, j)] != WHITE) { |
| | 3661 | vertices.type[vertices.num] = REGULAR; |
| | 3662 | vertices.pos[vertices.num++] = POS(i, j); |
| | 3663 | } |
| 3606 | 3664 | j++; |
| 3607 | 3665 | } |
| 3608 | 3666 | |
| … |
… |
|
| 3624 | 3682 | mx[SW(pos)] = EMPTY; |
| 3625 | 3683 | mx[SOUTH(pos)] = BLACK; |
| 3626 | 3684 | mx[SE(pos)] = BLACK; |
| 3627 | | if (ON_BOARD(NN(pos))) |
| | 3685 | if (ON_BOARD(NN(pos))) { |
| 3628 | 3686 | mx[NN(pos)] = EMPTY; |
| 3629 | | else |
| | 3687 | mx[EE(pos)] = EMPTY; |
| | 3688 | mx[WEST(NN(pos))] = EMPTY; |
| | 3689 | } |
| | 3690 | else { |
| 3630 | 3691 | mx[SS(pos)] = EMPTY; |
| | 3692 | mx[WW(pos)] = EMPTY; |
| | 3693 | mx[EAST(SS(pos))] = EMPTY; |
| | 3694 | } |
| 3631 | 3695 | |
| 3632 | | /* Add the two outer liberties in the lower left or upper right to |
| | 3696 | /* Use one of the liberties of this invincible group to mark ko |
| | 3697 | * threat status. Playing there obviously destroys the |
| | 3698 | * invincibility, but that doesn't actually matter as nobody is |
| | 3699 | * going to play on the other liberty anyway. |
| | 3700 | */ |
| | 3701 | vertices.type[vertices.num] = KO_THREAT; |
| | 3702 | vertices.pos[vertices.num++] = pos; |
| | 3703 | vertices.ko_threat_pos = pos; |
| | 3704 | |
| | 3705 | |
| | 3706 | /* Add the three outer liberties in the lower left or upper right to |
| 3633 | 3707 | * the list of vertices. |
| 3634 | 3708 | */ |
| 3635 | 3709 | if (ON_BOARD(NN(pos))) { |
| 3636 | | vertices[num_vertices++] = NE(pos); |
| 3637 | | vertices[num_vertices++] = NN(pos); |
| | 3710 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3711 | vertices.pos[vertices.num++] = NE(pos); |
| | 3712 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3713 | vertices.pos[vertices.num++] = NN(pos); |
| | 3714 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3715 | vertices.pos[vertices.num++] = EE(pos); |
| | 3716 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3717 | vertices.pos[vertices.num++] = WEST(NN(pos)); |
| 3638 | 3718 | } |
| 3639 | 3719 | else { |
| 3640 | | vertices[num_vertices++] = SW(pos); |
| 3641 | | vertices[num_vertices++] = SS(pos); |
| | 3720 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3721 | vertices.pos[vertices.num++] = SW(pos); |
| | 3722 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3723 | vertices.pos[vertices.num++] = SS(pos); |
| | 3724 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3725 | vertices.pos[vertices.num++] = WW(pos); |
| | 3726 | vertices.type[vertices.num] = OUTER_LIBERTY; |
| | 3727 | vertices.pos[vertices.num++] = EAST(SS(pos)); |
| 3642 | 3728 | } |
| 3643 | 3729 | |
| 3644 | 3730 | /* Add an extra eye in the upper left corner. */ |
| 3645 | 3731 | mx[POS(0, 0)] = EMPTY; |
| 3646 | | vertices[num_vertices++] = POS(0, 0); |
| | 3732 | vertices.type[vertices.num] = EXTRA_EYE; |
| | 3733 | vertices.pos[vertices.num++] = POS(0, 0); |
| 3647 | 3734 | |
| 3648 | 3735 | if (!add_margins(num_margins, margins, mx)) |
| 3649 | 3736 | return 0; |
| … |
… |
|
| 3666 | 3753 | */ |
| 3667 | 3754 | for (pos = BOARDMIN; pos < BOARDMAX; pos++) |
| 3668 | 3755 | if (board[pos] == WHITE && !same_string(pos, POS(1, 0))) { |
| 3669 | | vertices[num_vertices] = vertices[num_vertices - 1]; |
| 3670 | | vertices[num_vertices - 1] = vertices[num_vertices - 2]; |
| 3671 | | vertices[num_vertices - 2] = vertices[num_vertices - 3]; |
| 3672 | | vertices[num_vertices - 3] = pos; |
| 3673 | | num_vertices++; |
| | 3756 | int k; |
| | 3757 | for (k = vertices.num; vertices.type[k - 1] != REGULAR; k--) { |
| | 3758 | vertices.type[k] = vertices.type[k - 1]; |
| | 3759 | vertices.pos[k] = vertices.pos[k - 1]; |
| | 3760 | } |
| | 3761 | vertices.type[k] = REGULAR; |
| | 3762 | vertices.pos[k] = pos; |
| | 3763 | vertices.num++; |
| 3674 | 3764 | } |
| 3675 | 3765 | |
| 3676 | 3766 | if (verbose) { |
| 3677 | 3767 | int k; |
| 3678 | 3768 | gprintf("\nPlayable vertices:\n"); |
| 3679 | | for (k = 0; k < num_vertices; k++) |
| 3680 | | gprintf("%1m ", vertices[k]); |
| | 3769 | for (k = 0; k < vertices.num; k++) |
| | 3770 | gprintf("%1m(%d) ", vertices.pos[k], vertices.type[k]); |