Ticket #107: gunnar_7_9.14.diff

File gunnar_7_9.14.diff, 22.6 kB (added by gunnar, 2 years ago)

analyze_eyegraph improvements

  • engine/optics.c

    RCS file: /cvsroot/gnugo/gnugo/engine/optics.c,v
    retrieving revision 1.101
    diff -u -r1.101 optics.c
     
    26752675 * 3 - result has been computed and was a success (1) 
    26762676 */ 
    26772677 
     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 
     2684struct vertex_data { 
     2685  int pos[MAX_BOARD]; 
     2686  int type[MAX_BOARD]; 
     2687  int num; 
     2688  int ko_threat_pos; 
     2689}; 
     2690 
    26782691/* Like trymove() except that it does a superko check. This does, 
    26792692 * however, only disallow repetition (besides simple ko) if the move 
    26802693 * 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. 
    26812702 */ 
     2703 
     2704static int forced_ko_threat_stackp = -1; 
     2705 
    26822706static int 
    2683 eyegraph_trymove(int pos, int color, const char *message, int str) 
     2707eyegraph_trymove(int pos, int color, const char *message, int str, 
     2708                 int ko_threat_pos) 
    26842709{ 
    26852710  static Hash_data remembered_board_hashes[MAXSTACK]; 
    26862711  int k; 
    26872712  int does_capture = does_capture_something(pos, color); 
    26882713   
    26892714  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  } 
    26932727 
    26942728  if (does_capture) 
    26952729    return 1; 
     
    27002734      return 0; 
    27012735    } 
    27022736 
     2737   
    27032738  return 1; 
    27042739} 
    27052740 
     2741static void 
     2742eyegraph_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 */ 
    27062755static int 
    27072756eyegraph_is_margin_or_outer_liberty(int vertex) 
    27082757{ 
     
    27292778} 
    27302779 
    27312780static int 
    2732 eyegraph_order_moves(int num_vertices, int *vertices, int color_to_move, int *moves) 
     2781eyegraph_order_moves(struct vertex_data *vertices, int color_to_move, 
     2782                     int *moves) 
    27332783{ 
    27342784  int num_moves = 0; 
    27352785  int scores[BOARDMAX]; 
     
    27382788  int k; 
    27392789  int r; 
    27402790 
    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) { 
    27432793      /* Never useful for white to fill in outer liberties or a second eye. */ 
    27442794      if (color_to_move == WHITE) 
    27452795        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) 
    27482800        continue; 
    27492801    } 
    27502802     
    2751     move = vertices[k]; 
     2803    move = vertices->pos[k]; 
    27522804    score = 0; 
    27532805 
    27542806    if (board[move] != EMPTY) 
    27552807      continue; 
    27562808     
    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) 
    27592811        score = 5; /* margin */ 
    2760       else 
    2761         score = -10; /* outer liberty */ 
    2762     } 
    27632812 
    27642813    if (accuratelib(move, color_to_move, 2, NULL) == 1) 
    27652814      score -= 3; 
     
    28612910    return (result); \ 
    28622911  } while (0); 
    28632912 
    2864 static int tactical_life_defend(int str, int num_vertices, int *vertices, 
     2913static int tactical_life_defend(int str, struct vertex_data *vertices, 
    28652914                                unsigned char *results); 
    28662915 
    28672916/* Determine whether black can capture all white stones. */ 
    28682917static int 
    2869 tactical_life_attack(int str, int num_vertices, int *vertices, 
     2918tactical_life_attack(int str, struct vertex_data *vertices, 
    28702919                     unsigned char *results) 
    28712920{ 
    28722921  int k; 
     
    28772926  int moves[BOARDMAX]; 
    28782927 
    28792928  /* 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++) { 
    28812930    hash *= 3; 
    2882     hash += board[vertices[k]]; 
     2931    hash += board[vertices->pos[k]]; 
    28832932  } 
    28842933  hash *= 2; 
    28852934  hash += (board_ko_pos != NO_MOVE); 
     
    29032952  results[hash] |= 1; 
    29042953 
    29052954  /* 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); 
    29082956  for (k = 0; k < num_moves; k++) { 
    29092957    int move = moves[k]; 
    29102958    if (eyegraph_trymove(move, OTHER_COLOR(board[str]), 
    2911                          "tactical_life_attack", str)) { 
     2959                         "tactical_life_attack", str, 
     2960                         vertices->ko_threat_pos)) { 
    29122961      /* We were successful if the white stones were captured or if no 
    29132962       * defense can be found. 
    29142963       */ 
    29152964      if (board[str] == EMPTY) 
    29162965        result = 1; 
    29172966      else 
    2918         result = !tactical_life_defend(str, num_vertices, vertices, results); 
     2967        result = !tactical_life_defend(str, vertices, results); 
    29192968       
    2920       popgo(); 
     2969      eyegraph_popgo(); 
    29212970 
    29222971      if (result == 1) { 
    29232972        /* Store the result (success) in the cache. */ 
     
    29342983 
    29352984/* Determine whether white can live with all stones. */ 
    29362985static int 
    2937 tactical_life_defend(int str, int num_vertices, int *vertices, 
     2986tactical_life_defend(int str, struct vertex_data *vertices, 
    29382987                     unsigned char *results) 
    29392988{ 
    29402989  int k; 
     
    29452994  int moves[BOARDMAX]; 
    29462995   
    29472996  /* 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++) { 
    29492998    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]]; 
    29523001  } 
    29533002  hash *= 2; 
    29543003  hash += (board_ko_pos != NO_MOVE); 
     
    29723021  results[hash] |= (1 << 2); 
    29733022 
    29743023  /* 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); 
    29763025  for (k = 0; k < num_moves; k++) { 
    29773026    int move = moves[k]; 
    29783027    if ((!is_suicide(move, OTHER_COLOR(board[str])) 
    29793028         || 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)) { 
    29813031      /* 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); 
    29833033       
    2984       popgo(); 
     3034      eyegraph_popgo(); 
    29853035 
    29863036      if (result == 1) { 
    29873037        /* Store the result (success) in the cache. */ 
     
    29923042  } 
    29933043 
    29943044  /* 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)) { 
    29963046    /* Store the result (success) in the cache. */ 
    29973047    results[hash] = (results[hash] & (~12)) | (3 << 2); 
    29983048    EYEGRAPH_RETURN(1, "tactical_life_defend: win"); 
     
    30093059 * used or filled in before starting reading. 
    30103060 */ 
    30113061static void 
    3012 tactical_life(int have_eye, int num_vertices, int *vertices, 
     3062tactical_life(int have_eye, struct vertex_data *vertices, 
    30133063              int *attack_code, int *num_attacks, int *attack_points, 
    30143064              int *defense_code, int *num_defenses, int *defense_points, 
    30153065              unsigned char *results) 
     
    30383088   * suicide the white stones can be considered dead. 
    30393089   */ 
    30403090  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)) { 
    30423093      *attack_code = WIN; 
    30433094      *defense_code = 0; 
    30443095      return; 
     
    30513102  /* Call tactical_life_attack() and tactical_life_defend() to 
    30523103   * determine status. 
    30533104   */ 
    3054   if (tactical_life_attack(str, num_vertices, vertices, results)) { 
     3105  if (tactical_life_attack(str, vertices, results)) { 
    30553106    *attack_code = WIN; 
    3056     if (tactical_life_defend(str, num_vertices, vertices, results)) 
     3107    if (tactical_life_defend(str, vertices, results)) 
    30573108      *defense_code = WIN; 
    30583109  } 
    30593110  else 
     
    30673118  if (*attack_code != 0 && *defense_code != 0) { 
    30683119    if (num_attacks != NULL && attack_points != NULL) { 
    30693120      *num_attacks = 0; 
    3070       num_moves = eyegraph_order_moves(num_vertices, vertices, 
     3121      num_moves = eyegraph_order_moves(vertices, 
    30713122                                       OTHER_COLOR(board[str]), moves); 
    30723123      for (k = 0; k < num_moves; k++) { 
    30733124        int move = moves[k]; 
    30743125        if (eyegraph_trymove(move, OTHER_COLOR(board[str]), "tactical_life-B", 
    3075                              str)) { 
     3126                             str, vertices->ko_threat_pos)) { 
    30763127          if (board[str] == EMPTY 
    3077               || !tactical_life_defend(str, num_vertices, vertices, results)) 
     3128              || !tactical_life_defend(str, vertices, results)) 
    30783129            attack_points[(*num_attacks)++] = move; 
    3079           popgo(); 
     3130          eyegraph_popgo(); 
    30803131        } 
    30813132      } 
    30823133    } 
    30833134 
    30843135    if (num_defenses != NULL && defense_points != NULL) { 
    30853136      *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); 
    30883138      for (k = 0; k < num_moves; k++) { 
    30893139        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)) 
    30923143            defense_points[(*num_defenses)++] = move; 
    3093           popgo(); 
     3144          eyegraph_popgo(); 
    30943145        } 
    30953146      } 
    30963147    } 
     
    30983149 
    30993150  /* Unfill the extra eye if we didn't use it. */ 
    31003151  if (!have_eye) 
    3101     popgo(); 
     3152    eyegraph_popgo(); 
    31023153} 
    31033154 
    31043155/* Determine the eye value of the eyespace for the big white group on 
     
    31133164 * need to recursively call ourselves after a move has been made. 
    31143165 */ 
    31153166static void 
    3116 evaluate_eyespace(struct eyevalue *result, int num_vertices, int *vertices, 
     3167evaluate_eyespace(struct eyevalue *result, struct vertex_data *vertices, 
    31173168                  int *num_vital_attacks, int *vital_attacks, 
    31183169                  int *num_vital_defenses, int *vital_defenses, 
    31193170                  unsigned char *tactical_life_results) 
     
    31413192  *num_vital_defenses = 0; 
    31423193 
    31433194  /* Determine tactical life without an extra eye. */ 
    3144   tactical_life(0, num_vertices, vertices, 
     3195  tactical_life(0, vertices, 
    31453196                &attack_code, &num_attacks, attack_points, 
    31463197                &defense_code, &num_defenses, defense_points, 
    31473198                tactical_life_results); 
     
    31573208    if (sgf_dumptree) 
    31583209      sgftreeAddComment(sgf_dumptree, "Alive without extra eye.\n"); 
    31593210     
    3160     num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves); 
     3211    num_moves = eyegraph_order_moves(vertices, BLACK, moves); 
    31613212    for (k = 0; k < num_moves; k++) { 
    31623213      int acode, dcode; 
    31633214      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, 
    31663218                      &dcode, NULL, NULL, tactical_life_results); 
    31673219        if (acode != 0) { 
    3168           tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, 
     3220          tactical_life(1, vertices, &acode, NULL, NULL, 
    31693221                        &dcode, NULL, NULL, tactical_life_results); 
    31703222          if (acode != 0) { 
    31713223            if (a == 1) 
     
    31853237              sgftreeAddComment(sgf_dumptree, "Ko threat to remove one eye.\n"); 
    31863238          } 
    31873239        } 
    3188         popgo(); 
     3240        eyegraph_popgo(); 
    31893241      } 
    31903242    } 
    31913243    set_eyevalue(result, a, 2, 2, 2); 
     
    32043256     */ 
    32053257    if (sgf_dumptree) 
    32063258      sgftreeAddComment(sgf_dumptree, "Critical without extra eye.\n"); 
    3207     tactical_life(1, num_vertices, vertices, 
     3259    tactical_life(1, vertices, 
    32083260                  &attack_code2, &num_attacks2, attack_points2, 
    32093261                  &defense_code2, NULL, NULL, tactical_life_results); 
    32103262    for (k = 0; k < num_defenses; k++) 
     
    32213273      int a = 1; 
    32223274      for (k = 0; k < num_attacks; k++) { 
    32233275        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, 
    32263279                            &num_vital_attacks2, vital_attacks2, 
    32273280                            &num_vital_defenses2, vital_defenses2, 
    32283281                            tactical_life_results); 
     
    32393292          } 
    32403293          else if (a == 1) 
    32413294            vital_attacks[(*num_vital_attacks)++] = move; 
    3242           popgo(); 
     3295          eyegraph_popgo(); 
    32433296        } 
    32443297      } 
    32453298      set_eyevalue(result, a, 1, 2, 2); 
     
    32593312     */ 
    32603313    if (sgf_dumptree) 
    32613314      sgftreeAddComment(sgf_dumptree, "Dead without extra eye.\n"); 
    3262     tactical_life(1, num_vertices, vertices, 
     3315    tactical_life(1, vertices, 
    32633316                  &attack_code, &num_attacks, attack_points, 
    32643317                  &defense_code, &num_defenses, defense_points, 
    32653318                  tactical_life_results); 
     
    32713324      int d = 1; 
    32723325      if (sgf_dumptree) 
    32733326        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); 
    32753328      for (k = 0; k < num_moves; k++) { 
    32763329        int acode, dcode; 
    32773330        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, 
    32803334                        &dcode, NULL, NULL, tactical_life_results); 
    32813335          if (acode != 0) { 
    3282             evaluate_eyespace(&result2, num_vertices, vertices, 
     3336            evaluate_eyespace(&result2, vertices, 
    32833337                              &num_vital_attacks2, vital_attacks2, 
    32843338                              &num_vital_defenses2, vital_defenses2, 
    32853339                              tactical_life_results); 
     
    32913345                sgftreeAddComment(sgf_dumptree, "Attacking ko threat.\n"); 
    32923346            } 
    32933347          } 
    3294           popgo(); 
     3348          eyegraph_popgo(); 
    32953349        } 
    32963350      } 
    32973351       
    3298       num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves); 
     3352      num_moves = eyegraph_order_moves(vertices, WHITE, moves); 
    32993353      for (k = 0; k < num_moves; k++) { 
    33003354        int acode, dcode; 
    33013355        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, 
    33043359                        &dcode, NULL, NULL, tactical_life_results); 
    33053360          if (dcode != 0) { 
    3306             evaluate_eyespace(&result2, num_vertices, vertices, 
     3361            evaluate_eyespace(&result2, vertices, 
    33073362                              &num_vital_attacks2, vital_attacks2, 
    33083363                              &num_vital_defenses2, vital_defenses2, 
    33093364                              tactical_life_results); 
     
    33153370                sgftreeAddComment(sgf_dumptree, "Defending ko threat.\n"); 
    33163371            } 
    33173372          } 
    3318           popgo(); 
     3373          eyegraph_popgo(); 
    33193374        } 
    33203375      } 
    33213376      set_eyevalue(result, a, 1, 1, d); 
     
    33413396        vital_attacks[(*num_vital_attacks)++] = attack_points[k]; 
    33423397      for (k = 0; k < num_defenses; k++) { 
    33433398        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, 
    33463402                            &num_vital_attacks2, vital_attacks2, 
    33473403                            &num_vital_defenses2, vital_defenses2, 
    33483404                            tactical_life_results); 
     
    33593415          } 
    33603416          else if (d == 1) 
    33613417            vital_defenses[(*num_vital_defenses)++] = move; 
    3362           popgo(); 
     3418          eyegraph_popgo(); 
    33633419        } 
    33643420      } 
    33653421      set_eyevalue(result, 0, 0, 1, d); 
     
    33793435      int d = 0; 
    33803436      if (sgf_dumptree) 
    33813437        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); 
    33833439      for (k = 0; k < num_moves; k++) { 
    33843440        int acode, dcode; 
    33853441        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, 
    33883445                        &dcode, NULL, NULL, tactical_life_results); 
    33893446          if (dcode != 0) { 
    3390             tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, 
     3447            tactical_life(0, vertices, &acode, NULL, NULL, 
    33913448                          &dcode, NULL, NULL, tactical_life_results); 
    33923449            if (dcode != 0) { 
    33933450              if (d == 1) 
     
    34083465                                  "Ko threat to make one eye.\n"); 
    34093466            } 
    34103467          } 
    3411           popgo(); 
     3468          eyegraph_popgo(); 
    34123469        } 
    34133470      } 
    34143471      set_eyevalue(result, 0, 0, 0, d); 
     
    35213578  int num_margins; 
    35223579  int margins[BOARDMAX]; /* Way larger than necessary. */ 
    35233580 
    3524   int num_vertices; 
    3525   int vertices[BOARDMAX]; /* Way larger than necessary. */ 
    3526  
     3581  struct vertex_data vertices; 
     3582   
    35273583  int table_size; 
    35283584  unsigned char *tactical_life_results; 
    35293585 
     
    35673623 
    35683624  /* Cut out the eyespace from the solid white string. */ 
    35693625  num_margins = 0; 
    3570   num_vertices = 0; 
     3626  vertices.num = 0; 
    35713627   
    35723628  if (horizontal_edge == 0) 
    35733629    mini = -1; 
     
    36013657    if (c == '!' || c == '@' || c == '(' || c == ')' || c == '$') 
    36023658      margins[num_margins++] = POS(i, j); 
    36033659    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    } 
    36063664    j++; 
    36073665  } 
    36083666 
     
    36243682  mx[SW(pos)] = EMPTY; 
    36253683  mx[SOUTH(pos)] = BLACK; 
    36263684  mx[SE(pos)] = BLACK; 
    3627   if (ON_BOARD(NN(pos))) 
     3685  if (ON_BOARD(NN(pos))) { 
    36283686    mx[NN(pos)] = EMPTY; 
    3629   else 
     3687    mx[EE(pos)] = EMPTY; 
     3688    mx[WEST(NN(pos))] = EMPTY; 
     3689  } 
     3690  else { 
    36303691    mx[SS(pos)] = EMPTY; 
     3692    mx[WW(pos)] = EMPTY; 
     3693    mx[EAST(SS(pos))] = EMPTY; 
     3694  } 
    36313695 
    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 
    36333707   * the list of vertices. 
    36343708   */ 
    36353709  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)); 
    36383718  } 
    36393719  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)); 
    36423728  } 
    36433729 
    36443730  /* Add an extra eye in the upper left corner. */ 
    36453731  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); 
    36473734 
    36483735  if (!add_margins(num_margins, margins, mx)) 
    36493736    return 0; 
     
    36663753   */ 
    36673754  for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
    36683755    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++; 
    36743764    } 
    36753765 
    36763766  if (verbose) { 
    36773767    int k; 
    36783768    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]);