Ticket #107: gunnar_7_9.14b.diff

File gunnar_7_9.14b.diff, 29.7 KB (added by gunnar, 4 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      continue; 
     3674    if (coded_eyegraph[k] == '\t') 
     3675      continue; 
    35333676    if (coded_eyegraph[k] == '%') { 
    35343677      num_rows++; 
    35353678      if (current_width > maxwidth) 
     
    35493692 
    35503693  /* Cut out the eyespace from the solid white string. */ 
    35513694  num_margins = 0; 
    3552   num_vertices = 0; 
     3695  vertices.num = 0; 
    35533696   
    35543697  if (horizontal_edge == 0) 
    35553698    mini = -1; 
     
    35713714    char c = coded_eyegraph[k]; 
    35723715    if (c == '\n') 
    35733716      continue; 
     3717    if (c == ' ') 
     3718      continue; 
     3719    if (c == '\t') 
     3720      continue; 
    35743721    if (c == '%') { 
    35753722      i++; 
    35763723      j = minj - 1; 
     
    35833730    if (c == '!' || c == '@' || c == '(' || c == ')' || c == '$') 
    35843731      margins[num_margins++] = POS(i, j); 
    35853732    if (c != '|' && c != '-' && c != '+' && c != '%' 
    3586         && ON_BOARD(POS(i, j)) && mx[POS(i, j)] != WHITE) 
    3587       vertices[num_vertices++] = POS(i, j); 
     3733        && ON_BOARD(POS(i, j)) && mx[POS(i, j)] != WHITE) { 
     3734      vertices.type[vertices.num] = REGULAR; 
     3735      vertices.pos[vertices.num++] = POS(i, j); 
     3736    } 
    35883737    j++; 
    35893738  } 
    35903739 
    3591   /* Add an invincible black group in the lower left plus two outer 
    3592    * liberties for the white string. However, if the eyespace is 
    3593    * placed in or near the lower left corner, we put this group in the 
    3594    * upper right instead. 
     3740  vertices.num_ordinary = vertices.num; 
     3741 
     3742  /* Add an invincible black group in the lower left corner plus outer 
     3743   * liberties for the white string and space for virtual ko threats. 
     3744   * However, if the eyespace is placed in or near the lower left 
     3745   * corner, we put this group in the upper right instead. 
     3746   * 
     3747   * |aaaaa 
     3748   * |XXXXX 
     3749   * |.X.X 
     3750   * |XXXXX 
     3751   * |bbbbX 
     3752   * +----- 
     3753   * 
     3754   * a - up to five outer liberties (empty if active, otherwise O) 
     3755   * b - up to four virtual ko threats (always empty) 
    35953756   */ 
    3596   pos = POS(board_size - 2, 1); 
     3757  corner = POS(board_size - 1, 0); 
     3758  up = DELTA(-1, 0); 
     3759  right = DELTA(0, 1); 
    35973760  if ((vertical_edge == 0 && horizontal_edge != 0) 
    3598       || (horizontal_edge > 0 && vertical_edge <= 0)) 
    3599     pos = POS(1, board_size - 2); 
    3600   mx[pos] = EMPTY; 
    3601   mx[NORTH(pos)] = BLACK; 
    3602   mx[NW(pos)] = BLACK; 
    3603   mx[NE(pos)] = EMPTY; 
    3604   mx[WEST(pos)] = BLACK; 
    3605   mx[EAST(pos)] = BLACK; 
    3606   mx[SW(pos)] = EMPTY; 
    3607   mx[SOUTH(pos)] = BLACK; 
    3608   mx[SE(pos)] = BLACK; 
    3609   if (ON_BOARD(NN(pos))) 
    3610     mx[NN(pos)] = EMPTY; 
    3611   else 
    3612     mx[SS(pos)] = EMPTY; 
    3613  
    3614   /* Add the two outer liberties in the lower left or upper right to 
    3615    * the list of vertices. 
     3761      || (horizontal_edge > 0 && vertical_edge <= 0)) { 
     3762    corner = POS(0, board_size - 1); 
     3763    up = DELTA(1, 0); 
     3764    right = DELTA(0, -1); 
     3765  } 
     3766   
     3767#define LOCAL_COORD(i, j) corner + i * up + j * right 
     3768   
     3769  mx[LOCAL_COORD(0, 4)] = BLACK; 
     3770  mx[LOCAL_COORD(1, 0)] = BLACK; 
     3771  mx[LOCAL_COORD(1, 1)] = BLACK; 
     3772  mx[LOCAL_COORD(1, 2)] = BLACK; 
     3773  mx[LOCAL_COORD(1, 3)] = BLACK; 
     3774  mx[LOCAL_COORD(1, 4)] = BLACK; 
     3775  mx[LOCAL_COORD(2, 1)] = BLACK; 
     3776  mx[LOCAL_COORD(2, 3)] = BLACK; 
     3777  mx[LOCAL_COORD(3, 0)] = BLACK; 
     3778  mx[LOCAL_COORD(3, 1)] = BLACK; 
     3779  mx[LOCAL_COORD(3, 2)] = BLACK; 
     3780  mx[LOCAL_COORD(3, 3)] = BLACK; 
     3781  mx[LOCAL_COORD(3, 4)] = BLACK; 
     3782  mx[LOCAL_COORD(2, 0)] = EMPTY; 
     3783  mx[LOCAL_COORD(2, 2)] = EMPTY; 
     3784 
     3785  /* Virtual ko threat points. */ 
     3786  mx[LOCAL_COORD(0, 0)] = EMPTY; 
     3787  mx[LOCAL_COORD(0, 1)] = EMPTY; 
     3788  mx[LOCAL_COORD(0, 2)] = EMPTY; 
     3789  mx[LOCAL_COORD(0, 3)] = EMPTY; 
     3790 
     3791  vertices.num_ko_threats = 0; 
     3792  for (k = 0; k < ko_threats; k++) { 
     3793    vertices.type[vertices.num] = KO_THREAT; 
     3794    vertices.pos[vertices.num++] = LOCAL_COORD(0, k); 
     3795    vertices.ko_threat_pos[vertices.num_ko_threats++] = LOCAL_COORD(0, k); 
     3796  } 
     3797 
     3798  /* Outer liberties. */ 
     3799  for (k = 0; k < outer_liberties; k++) { 
     3800    vertices.type[vertices.num] = OUTER_LIBERTY; 
     3801    vertices.pos[vertices.num++] = LOCAL_COORD(4, k); 
     3802    mx[LOCAL_COORD(4, k)] = EMPTY; 
     3803  } 
     3804 
     3805  /* Add an extra eye in the upper left corner unless it is occupied. 
     3806   * In that case place the extra eye in the lower right instead. 
     3807   * Also pick up a vertex belonging to the large white string. 
    36163808   */ 
    3617   if (ON_BOARD(NN(pos))) { 
    3618     vertices[num_vertices++] = NE(pos); 
    3619     vertices[num_vertices++] = NN(pos); 
     3809  if (vertical_edge != 0 || horizontal_edge != 0) { 
     3810    vertices.extra_eye_pos = POS(0, 0); 
     3811    vertices.string = POS(1, 0); 
    36203812  } 
    36213813  else { 
    3622     vertices[num_vertices++] = SW(pos); 
    3623     vertices[num_vertices++] = SS(pos); 
     3814    vertices.extra_eye_pos = POS(board_size - 1, board_size - 1); 
     3815    vertices.string = POS(board_size - 2, board_size - 1); 
    36243816  } 
    3625  
    3626   /* Add an extra eye in the upper left corner. */ 
    3627   mx[POS(0, 0)] = EMPTY; 
    3628   vertices[num_vertices++] = POS(0, 0); 
     3817     
     3818  mx[vertices.extra_eye_pos] = EMPTY; 
     3819  vertices.type[vertices.num] = EXTRA_EYE; 
     3820  vertices.pos[vertices.num++] = vertices.extra_eye_pos; 
    36293821 
    36303822  if (!add_margins(num_margins, margins, mx)) 
    36313823    return 0; 
     
    36473839   * the playable vertices. 
    36483840   */ 
    36493841  for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
    3650     if (board[pos] == WHITE && !same_string(pos, POS(1, 0))) { 
    3651       vertices[num_vertices] = vertices[num_vertices - 1]; 
    3652       vertices[num_vertices - 1] = vertices[num_vertices - 2]; 
    3653       vertices[num_vertices - 2] = vertices[num_vertices - 3]; 
    3654       vertices[num_vertices - 3] = pos; 
    3655       num_vertices++; 
     3842    if (board[pos] == WHITE && !same_string(pos, vertices.string)) { 
     3843      int k; 
     3844      for (k = vertices.num; vertices.type[k - 1] != REGULAR; k--) { 
     3845        vertices.type[k] = vertices.type[k - 1]; 
     3846        vertices.pos[k] = vertices.pos[k - 1]; 
     3847      } 
     3848      vertices.type[k] = REGULAR; 
     3849      vertices.pos[k] = pos; 
     3850      vertices.num++; 
    36563851    } 
    36573852 
    36583853  if (verbose) { 
    36593854    int k; 
    36603855    gprintf("\nPlayable vertices:\n"); 
    3661     for (k = 0; k < num_vertices; k++) 
    3662       gprintf("%1m ", vertices[k]); 
     3856    for (k = 0; k < vertices.num; k++) 
     3857      gprintf("%1m(%d) ", vertices.pos[k], vertices.type[k]); 
    36633858    gprintf("\n\n"); 
    36643859  } 
    36653860   
    36663861  /* Disable this test if you need to evaluate larger eyespaces, have 
    36673862   * no shortage of memory, and know what you're doing. 
    36683863   */ 
    3669   if (num_vertices > 17) { 
     3864  if (vertices.num > 17) { 
    36703865    gprintf("analyze_eyegraph: too large eyespace, %d vertices\n", 
    3671             num_vertices); 
    3672     gg_assert(num_vertices <= 17); 
     3866            vertices.num); 
     3867    gg_assert(vertices.num <= 17); 
    36733868  } 
    36743869 
    3675   /* The cache must have 2*3^num_vertices entries. */ 
     3870  /* The cache must have 2*3^vertices.num entries. */ 
    36763871  table_size = 2; 
    3677   for (k = 0; k < num_vertices; k++) 
     3872  for (k = 0; k < vertices.num; k++) 
    36783873    table_size *= 3; 
    36793874 
    36803875  /* Allocate memory for the cache. */ 
     
    36893884    sgffile_printboard(sgf_dumptree); 
    36903885   
    36913886  /* Evaluate the eyespace on the board. */ 
    3692   evaluate_eyespace(value, num_vertices, vertices, 
     3887  evaluate_eyespace(value, &vertices, 
    36933888                    &num_vital_attacks, vital_attacks, 
    36943889                    &num_vital_defenses, vital_defenses, 
    36953890                    tactical_life_results); 
     
    37083903  /* Encode the attack and defense points with symbols in the mg[] array. */ 
    37093904  memset(mg, ' ', sizeof(mg)); 
    37103905 
    3711   for (k = 0; k < num_vertices - 2; k++) 
    3712     mg[vertices[k]] = (board[vertices[k]] == BLACK ? 'X' : '.'); 
     3906  for (k = 0; k < vertices.num_ordinary; k++) 
     3907    mg[vertices.pos[k]] = (board[vertices.pos[k]] == BLACK ? 'X' : '.'); 
    37133908 
    37143909  for (k = 0; k < num_margins; k++) 
    37153910    mg[margins[k]] = (mg[margins[k]] == 'X' ? '$' : '!'); 
  • interface/play_gtp.c

    RCS file: /cvsroot/gnugo/gnugo/interface/play_gtp.c,v
    retrieving revision 1.181
    diff -u -r1.181 play_gtp.c
     
    34553455 
    34563456 
    34573457/* Function:  Compute an eyevalue and vital points for an eye graph 
    3458  * Arguments: Eyeshape encoded in string 
     3458 * Arguments: Eyeshape encoded in string OR two integers followed by eyeshape 
    34593459 * Fails:     Bad eyeshape, analysis failed 
    34603460 * Returns:   Eyevalue, vital points 
    34613461 */ 
     
    34633463gtp_analyze_eyegraph(char *s) 
    34643464{ 
    34653465  struct eyevalue value; 
     3466  int outer_liberties; 
     3467  int ko_threats; 
     3468  int n = 0; 
    34663469  char analyzed_eyegraph[1024]; 
    3467   int result = analyze_eyegraph(s, &value, analyzed_eyegraph); 
     3470  int result; 
     3471 
     3472  if (sscanf(s, "%d %d %n", &outer_liberties, &ko_threats, &n) < 2) { 
     3473    outer_liberties = 4; 
     3474    ko_threats = 1; 
     3475  } 
     3476   
     3477  result = analyze_eyegraph(s + n, &value, analyzed_eyegraph, 
     3478                            outer_liberties, ko_threats); 
    34683479 
    34693480  if (result == 0) 
    34703481    return gtp_failure("failed to analyze");