Ticket #107: gunnar_7_9.14b.diff

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

further analyze_eyegraph improvements

  • doc/gtp-commands.texi

    RCS file: /cvsroot/gnugo/gnugo/doc/gtp-commands.texi,v
    retrieving revision 1.28
    diff -u -r1.28 gtp-commands.texi
     
    762762@cindex analyze_eyegraph 
    763763@item analyze_eyegraph: Compute an eyevalue and vital points for an eye graph 
    764764@verbatim 
    765 Arguments: Eyeshape encoded in string 
     765Arguments: Eyeshape encoded in string OR two integers followed by eyeshape 
    766766Fails:     Bad eyeshape, analysis failed 
    767767Returns:   Eyevalue, vital points 
    768768@end verbatim 
  • engine/liberty.h

    RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
    retrieving revision 1.258
    diff -u -r1.258 liberty.h
     
    664664int max_eye_value(int pos); 
    665665void test_eyeshape(int eyesize, int *eye_vertices); 
    666666int analyze_eyegraph(const char *coded_eyegraph, struct eyevalue *value, 
    667                      char *analyzed_eyegraph); 
     667                     char *analyzed_eyegraph, int outer_liberties, 
     668                     int ko_threats); 
    668669 
    669670 
    670671/* debugging support */ 
  • engine/optics.c

    RCS file: /cvsroot/gnugo/gnugo/engine/optics.c,v
    retrieving revision 1.105
    diff -u -r1.105 optics.c
     
    26572691 * 3 - result has been computed and was a success (1) 
    26582692 */ 
    26592693 
     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 
     2703struct 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 
    26602715/* 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. 
    26632726 */ 
     2727 
     2728static int forced_ko_threat_stackp[MAX_KO_THREATS]; 
     2729static int num_active_ko_threats = 0; 
     2730 
    26642731static int 
    2665 eyegraph_trymove(int pos, int color, const char *message, int str) 
     2732eyegraph_trymove(int pos, int color, const char *message, int str, 
     2733                 struct vertex_data *vertices) 
    26662734{ 
    26672735  static Hash_data remembered_board_hashes[MAXSTACK]; 
    26682736  int k; 
    2669   int does_capture = does_capture_something(pos, color); 
    26702737   
    26712738  remembered_board_hashes[stackp] = board_hash; 
    2672    
    2673   if (!trymove(pos, color, message, str)) 
    2674     return 0; 
    26752739 
    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) 
    26772766    return 1; 
    26782767 
    26792768  for (k = 0; k < stackp; k++) 
     
    26852774  return 1; 
    26862775} 
    26872776 
     2777static void 
     2778eyegraph_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 */ 
    26882792static int 
    26892793eyegraph_is_margin_or_outer_liberty(int vertex) 
    26902794{ 
     
    27112815} 
    27122816 
    27132817static int 
    2714 eyegraph_order_moves(int num_vertices, int *vertices, int color_to_move, int *moves) 
     2818eyegraph_order_moves(struct vertex_data *vertices, int color_to_move, 
     2819                     int *moves) 
    27152820{ 
    27162821  int num_moves = 0; 
    27172822  int scores[BOARDMAX]; 
     
    27202825  int k; 
    27212826  int r; 
    27222827 
    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) { 
    27252830      /* Never useful for white to fill in outer liberties or a second eye. */ 
    27262831      if (color_to_move == WHITE) 
    27272832        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) 
    27302837        continue; 
    27312838    } 
    27322839     
    2733     move = vertices[k]; 
     2840    move = vertices->pos[k]; 
    27342841    score = 0; 
    27352842 
    27362843    if (board[move] != EMPTY) 
    27372844      continue; 
    27382845     
    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) 
    27412848        score = 5; /* margin */ 
    2742       else 
    2743         score = -10; /* outer liberty */ 
    2744     } 
    27452849 
    27462850    if (accuratelib(move, color_to_move, 2, NULL) == 1) 
    27472851      score -= 3; 
     
    28432947    return (result); \ 
    28442948  } while (0); 
    28452949 
    2846 static int tactical_life_defend(int str, int num_vertices, int *vertices, 
     2950static int tactical_life_defend(int str, struct vertex_data *vertices, 
    28472951                                unsigned char *results); 
    28482952 
    28492953/* Determine whether black can capture all white stones. */ 
    28502954static int 
    2851 tactical_life_attack(int str, int num_vertices, int *vertices, 
     2955tactical_life_attack(int str, struct vertex_data *vertices, 
    28522956                     unsigned char *results) 
    28532957{ 
    28542958  int k; 
     
    28592963  int moves[BOARDMAX]; 
    28602964 
    28612965  /* 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++) { 
    28632967    hash *= 3; 
    2864     hash += board[vertices[k]]; 
     2968    hash += board[vertices->pos[k]]; 
    28652969  } 
    28662970  hash *= 2; 
    28672971  hash += (board_ko_pos != NO_MOVE); 
     
    28852989  results[hash] |= 1; 
    28862990 
    28872991  /* 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); 
    28902993  for (k = 0; k < num_moves; k++) { 
    28912994    int move = moves[k]; 
    28922995    if (eyegraph_trymove(move, OTHER_COLOR(board[str]), 
    2893                          "tactical_life_attack", str)) { 
     2996                         "tactical_life_attack", str, 
     2997                         vertices)) { 
    28942998      /* We were successful if the white stones were captured or if no 
    28952999       * defense can be found. 
    28963000       */ 
    28973001      if (board[str] == EMPTY) 
    28983002        result = 1; 
    28993003      else 
    2900         result = !tactical_life_defend(str, num_vertices, vertices, results); 
     3004        result = !tactical_life_defend(str, vertices, results); 
    29013005       
    2902       popgo(); 
     3006      eyegraph_popgo(); 
    29033007 
    29043008      if (result == 1) { 
    29053009        /* Store the result (success) in the cache. */ 
     
    29163020 
    29173021/* Determine whether white can live with all stones. */ 
    29183022static int 
    2919 tactical_life_defend(int str, int num_vertices, int *vertices, 
     3023tactical_life_defend(int str, struct vertex_data *vertices, 
    29203024                     unsigned char *results) 
    29213025{ 
    29223026  int k; 
     
    29273031  int moves[BOARDMAX]; 
    29283032   
    29293033  /* 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++) { 
    29313035    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]]; 
    29343038  } 
    29353039  hash *= 2; 
    29363040  hash += (board_ko_pos != NO_MOVE); 
     
    29543058  results[hash] |= (1 << 2); 
    29553059 
    29563060  /* 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); 
    29583062  for (k = 0; k < num_moves; k++) { 
    29593063    int move = moves[k]; 
    29603064    if ((!is_suicide(move, OTHER_COLOR(board[str])) 
    29613065         || 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)) { 
    29633068      /* 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); 
    29653070       
    2966       popgo(); 
     3071      eyegraph_popgo(); 
    29673072 
    29683073      if (result == 1) { 
    29693074        /* Store the result (success) in the cache. */ 
     
    29743079  } 
    29753080 
    29763081  /* 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)) { 
    29783083    /* Store the result (success) in the cache. */ 
    29793084    results[hash] = (results[hash] & (~12)) | (3 << 2); 
    29803085    EYEGRAPH_RETURN(1, "tactical_life_defend: win"); 
     
    29913096 * used or filled in before starting reading. 
    29923097 */ 
    29933098static void 
    2994 tactical_life(int have_eye, int num_vertices, int *vertices, 
     3099tactical_life(int have_eye, struct vertex_data *vertices, 
    29953100              int *attack_code, int *num_attacks, int *attack_points, 
    29963101              int *defense_code, int *num_defenses, int *defense_points, 
    29973102              unsigned char *results) 
     
    30073112   * vertex we test to determine whether the white stones have been 
    30083113   * captured. 
    30093114   */ 
    3010   str = POS(1, 0); 
     3115  str = vertices->string; 
    30113116 
    30123117  if (board[str] == EMPTY) { 
    30133118    /* The stones have already been captured, too late to defend. */ 
     
    30203125   * suicide the white stones can be considered dead. 
    30213126   */ 
    30223127  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)) { 
    30243130      *attack_code = WIN; 
    30253131      *defense_code = 0; 
    30263132      return; 
     
    30333139  /* Call tactical_life_attack() and tactical_life_defend() to 
    30343140   * determine status. 
    30353141   */ 
    3036   if (tactical_life_attack(str, num_vertices, vertices, results)) { 
     3142  if (tactical_life_attack(str, vertices, results)) { 
    30373143    *attack_code = WIN; 
    3038     if (tactical_life_defend(str, num_vertices, vertices, results)) 
     3144    if (tactical_life_defend(str, vertices, results)) 
    30393145      *defense_code = WIN; 
    30403146  } 
    30413147  else 
     
    30493155  if (*attack_code != 0 && *defense_code != 0) { 
    30503156    if (num_attacks != NULL && attack_points != NULL) { 
    30513157      *num_attacks = 0; 
    3052       num_moves = eyegraph_order_moves(num_vertices, vertices, 
     3158      num_moves = eyegraph_order_moves(vertices, 
    30533159                                       OTHER_COLOR(board[str]), moves); 
    30543160      for (k = 0; k < num_moves; k++) { 
    30553161        int move = moves[k]; 
    30563162        if (eyegraph_trymove(move, OTHER_COLOR(board[str]), "tactical_life-B", 
    3057                              str)) { 
     3163                             str, vertices)) { 
    30583164          if (board[str] == EMPTY 
    3059               || !tactical_life_defend(str, num_vertices, vertices, results)) 
     3165              || !tactical_life_defend(str, vertices, results)) 
    30603166            attack_points[(*num_attacks)++] = move; 
    3061           popgo(); 
     3167          eyegraph_popgo(); 
    30623168        } 
    30633169      } 
    30643170    } 
    30653171 
    30663172    if (num_defenses != NULL && defense_points != NULL) { 
    30673173      *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); 
    30703175      for (k = 0; k < num_moves; k++) { 
    30713176        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)) 
    30743180            defense_points[(*num_defenses)++] = move; 
    3075           popgo(); 
     3181          eyegraph_popgo(); 
    30763182        } 
    30773183      } 
    30783184    } 
     
    30803186 
    30813187  /* Unfill the extra eye if we didn't use it. */ 
    30823188  if (!have_eye) 
    3083     popgo(); 
     3189    eyegraph_popgo(); 
    30843190} 
    30853191 
    30863192/* Determine the eye value of the eyespace for the big white group on 
     
    30953201 * need to recursively call ourselves after a move has been made. 
    30963202 */ 
    30973203static void 
    3098 evaluate_eyespace(struct eyevalue *result, int num_vertices, int *vertices, 
     3204evaluate_eyespace(struct eyevalue *result, struct vertex_data *vertices, 
    30993205                  int *num_vital_attacks, int *vital_attacks, 
    31003206                  int *num_vital_defenses, int *vital_defenses, 
    31013207                  unsigned char *tactical_life_results) 
     
    31233229  *num_vital_defenses = 0; 
    31243230 
    31253231  /* Determine tactical life without an extra eye. */ 
    3126   tactical_life(0, num_vertices, vertices, 
     3232  tactical_life(0, vertices, 
    31273233                &attack_code, &num_attacks, attack_points, 
    31283234                &defense_code, &num_defenses, defense_points, 
    31293235                tactical_life_results); 
     
    31393245    if (sgf_dumptree) 
    31403246      sgftreeAddComment(sgf_dumptree, "Alive without extra eye.\n"); 
    31413247     
    3142     num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves); 
     3248    num_moves = eyegraph_order_moves(vertices, BLACK, moves); 
    31433249    for (k = 0; k < num_moves; k++) { 
    31443250      int acode, dcode; 
    31453251      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, 
    31483255                      &dcode, NULL, NULL, tactical_life_results); 
    31493256        if (acode != 0) { 
    3150           tactical_life(1, num_vertices, vertices, &acode, NULL, NULL, 
     3257          tactical_life(1, vertices, &acode, NULL, NULL, 
    31513258                        &dcode, NULL, NULL, tactical_life_results); 
    31523259          if (acode != 0) { 
    31533260            if (a == 1) 
     
    31673274              sgftreeAddComment(sgf_dumptree, "Ko threat to remove one eye.\n"); 
    31683275          } 
    31693276        } 
    3170         popgo(); 
     3277        eyegraph_popgo(); 
    31713278      } 
    31723279    } 
    31733280    set_eyevalue(result, a, 2, 2, 2); 
     
    31863293     */ 
    31873294    if (sgf_dumptree) 
    31883295      sgftreeAddComment(sgf_dumptree, "Critical without extra eye.\n"); 
    3189     tactical_life(1, num_vertices, vertices, 
     3296    tactical_life(1, vertices, 
    31903297                  &attack_code2, &num_attacks2, attack_points2, 
    31913298                  &defense_code2, NULL, NULL, tactical_life_results); 
    31923299    for (k = 0; k < num_defenses; k++) 
     
    32033310      int a = 1; 
    32043311      for (k = 0; k < num_attacks; k++) { 
    32053312        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, 
    32083316                            &num_vital_attacks2, vital_attacks2, 
    32093317                            &num_vital_defenses2, vital_defenses2, 
    32103318                            tactical_life_results); 
     
    32213329          } 
    32223330          else if (a == 1) 
    32233331            vital_attacks[(*num_vital_attacks)++] = move; 
    3224           popgo(); 
     3332          eyegraph_popgo(); 
    32253333        } 
    32263334      } 
    32273335      set_eyevalue(result, a, 1, 2, 2); 
     
    32413349     */ 
    32423350    if (sgf_dumptree) 
    32433351      sgftreeAddComment(sgf_dumptree, "Dead without extra eye.\n"); 
    3244     tactical_life(1, num_vertices, vertices, 
     3352    tactical_life(1, vertices, 
    32453353                  &attack_code, &num_attacks, attack_points, 
    32463354                  &defense_code, &num_defenses, defense_points, 
    32473355                  tactical_life_results); 
     
    32533361      int d = 1; 
    32543362      if (sgf_dumptree) 
    32553363        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); 
    32573365      for (k = 0; k < num_moves; k++) { 
    32583366        int acode, dcode; 
    32593367        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, 
    32623371                        &dcode, NULL, NULL, tactical_life_results); 
    32633372          if (acode != 0) { 
    3264             evaluate_eyespace(&result2, num_vertices, vertices, 
     3373            evaluate_eyespace(&result2, vertices, 
    32653374                              &num_vital_attacks2, vital_attacks2, 
    32663375                              &num_vital_defenses2, vital_defenses2, 
    32673376                              tactical_life_results); 
     
    32733382                sgftreeAddComment(sgf_dumptree, "Attacking ko threat.\n"); 
    32743383            } 
    32753384          } 
    3276           popgo(); 
     3385          eyegraph_popgo(); 
    32773386        } 
    32783387      } 
    32793388       
    3280       num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves); 
     3389      num_moves = eyegraph_order_moves(vertices, WHITE, moves); 
    32813390      for (k = 0; k < num_moves; k++) { 
    32823391        int acode, dcode; 
    32833392        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, 
    32863396                        &dcode, NULL, NULL, tactical_life_results); 
    32873397          if (dcode != 0) { 
    3288             evaluate_eyespace(&result2, num_vertices, vertices, 
     3398            evaluate_eyespace(&result2, vertices, 
    32893399                              &num_vital_attacks2, vital_attacks2, 
    32903400                              &num_vital_defenses2, vital_defenses2, 
    32913401                              tactical_life_results); 
     
    32973407                sgftreeAddComment(sgf_dumptree, "Defending ko threat.\n"); 
    32983408            } 
    32993409          } 
    3300           popgo(); 
     3410          eyegraph_popgo(); 
    33013411        } 
    33023412      } 
    33033413      set_eyevalue(result, a, 1, 1, d); 
     
    33233433        vital_attacks[(*num_vital_attacks)++] = attack_points[k]; 
    33243434      for (k = 0; k < num_defenses; k++) { 
    33253435        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, 
    33283439                            &num_vital_attacks2, vital_attacks2, 
    33293440                            &num_vital_defenses2, vital_defenses2, 
    33303441                            tactical_life_results); 
     
    33413452          } 
    33423453          else if (d == 1) 
    33433454            vital_defenses[(*num_vital_defenses)++] = move; 
    3344           popgo(); 
     3455          eyegraph_popgo(); 
    33453456        } 
    33463457      } 
    33473458      set_eyevalue(result, 0, 0, 1, d); 
     
    33613472      int d = 0; 
    33623473      if (sgf_dumptree) 
    33633474        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); 
    33653476      for (k = 0; k < num_moves; k++) { 
    33663477        int acode, dcode; 
    33673478        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, 
    33703482                        &dcode, NULL, NULL, tactical_life_results); 
    33713483          if (dcode != 0) { 
    3372             tactical_life(0, num_vertices, vertices, &acode, NULL, NULL, 
     3484            tactical_life(0, vertices, &acode, NULL, NULL, 
    33733485                          &dcode, NULL, NULL, tactical_life_results); 
    33743486            if (dcode != 0) { 
    33753487              if (d == 1) 
     
    33903502                                  "Ko threat to make one eye.\n"); 
    33913503            } 
    33923504          } 
    3393           popgo(); 
     3505          eyegraph_popgo(); 
    33943506        } 
    33953507      } 
    33963508      set_eyevalue(result, 0, 0, 0, d); 
     
    34773589 * !.*. 
    34783590 * 
    34793591 * 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. 
    34803604 */ 
    34813605int 
    34823606analyze_eyegraph(const char *coded_eyegraph, struct eyevalue *value, 
    3483                  char *analyzed_eyegraph) 
     3607                 char *analyzed_eyegraph, int outer_liberties, 
     3608                 int ko_threats) 
    34843609{ 
    34853610  int k; 
    34863611  int i, j; 
     
    34883613  int mx[BOARDMAX]; 
    34893614  char mg[BOARDMAX]; 
    34903615  int pos; 
     3616  int corner; 
     3617  int up; 
     3618  int right; 
    34913619 
    34923620  int num_vital_attacks; 
    34933621  int vital_attacks[BOARDMAX]; /* Way larger than necessary. */ 
     
    35033631  int num_margins; 
    35043632  int margins[BOARDMAX]; /* Way larger than necessary. */ 
    35053633 
    3506   int num_vertices; 
    3507   int vertices[BOARDMAX]; /* Way larger than necessary. */ 
    3508  
     3634  struct vertex_data vertices; 
     3635   
    35093636  int table_size; 
    35103637  unsigned char *tactical_life_results; 
    35113638 
    35123639  if (0) 
    35133640    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  } 
    35143653   
    35153654  /* Mark the eyespace in the mx array. We construct the position in 
    35163655   * the mx array and copy it to the actual board later. 
     
    35303669  for (k = 0; k < (int) strlen(coded_eyegraph); k++) { 
    35313670    if (coded_eyegraph[k] == '\n') 
    35323671      continue; 
     3672    if (coded_eyegraph[k] == ' ') 
     3673