Ticket #97: new_amalgamation_7_9.1.diff

File new_amalgamation_7_9.1.diff, 38.3 KB (added by gunnar, 4 years ago)

new dragon amalgamation algorithm

  • engine/dragon.c

    RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v
    retrieving revision 1.160
    diff -u -r1.160 dragon.c
     
    4949 
    5050#include "liberty.h" 
    5151#include "gg_utils.h" 
     52#include "readconnect.h" 
    5253 
    5354static void initialize_supplementary_dragon_data(void); 
     55static void amalgamate_dragons(int color); 
     56static void build_dragon(int w, int amalgamated[BOARDMAX], 
     57                         float effective_sizes[BOARDMAX]); 
    5458static void find_lunches(void); 
    5559static void eye_computations(void); 
    5660static void revise_inessentiality(void); 
     
    113117   * involved dragons. 
    114118   */ 
    115119  memset(cutting_points, 0, sizeof(cutting_points)); 
     120  if (experimental_connections) 
     121    initialize_static_worm_connections(); 
    116122  find_cuts(); 
    117123  find_connections(); 
     124  if (experimental_connections) { 
     125    analyze_worm_connections(); 
     126    amalgamate_dragons(BLACK); 
     127    amalgamate_dragons(WHITE); 
     128  } 
    118129 
    119130  /* At this time, all dragons have been finalized and we can 
    120131   * initialize the dragon2[] array. After that we can no longer allow 
     
    744755} 
    745756  
    746757 
     758static void 
     759amalgamate_dragons(int color) 
     760{ 
     761  int amalgamated[BOARDMAX]; 
     762  int pos; 
     763  float effective_sizes[BOARDMAX]; 
     764 
     765  if (stackp == 0) { 
     766    for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     767      if (IS_STONE(board[pos])) 
     768        effective_sizes[pos] = worm[pos].effective_size; 
     769  } 
     770  else { 
     771    compute_effective_string_sizes(effective_sizes); 
     772    for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     773      if (IS_STONE(board[pos])) 
     774        effective_sizes[pos] = effective_sizes[find_origin(pos)]; 
     775  } 
     776 
     777  memset(amalgamated, 0, sizeof(amalgamated)); 
     778  while (1) { 
     779    int biggest_remaining_string = NO_MOVE; 
     780    float biggest_remaining_string_size = 0.0; 
     781    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     782      if (board[pos] == color 
     783          && find_origin(pos) == pos 
     784          && !amalgamated[pos] 
     785          && effective_sizes[pos] > biggest_remaining_string_size) { 
     786        biggest_remaining_string = pos; 
     787        biggest_remaining_string_size = effective_sizes[pos]; 
     788      } 
     789    } 
     790    if (biggest_remaining_string == NO_MOVE) 
     791      break; 
     792 
     793    build_dragon(biggest_remaining_string, amalgamated, effective_sizes); 
     794  } 
     795} 
     796 
     797static void 
     798build_dragon(int starting_worm, int amalgamated[BOARDMAX], 
     799             float effective_sizes[BOARDMAX]) 
     800{ 
     801  int color = board[starting_worm]; 
     802  int worms_in_this_dragon[BOARDMAX]; 
     803  int num_worms; 
     804  int aspiring_worms[BOARDMAX]; 
     805  int num_aspiring; 
     806  int considered[BOARDMAX]; 
     807  int k; 
     808  int pos; 
     809 
     810  DEBUG(DEBUG_DRAGONS, "Build dragon starting at %1m.\n", starting_worm); 
     811   
     812  amalgamated[starting_worm] = 1; 
     813  worms_in_this_dragon[0] = starting_worm; 
     814  num_worms = 1; 
     815  num_aspiring = 0; 
     816  memset(considered, 0, sizeof(considered)); 
     817 
     818  for (k = 0; k < num_worms; k++) { 
     819    int this_worm = worms_in_this_dragon[k]; 
     820    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     821      if (board[pos] != color || find_origin(pos) != pos 
     822          || amalgamated[pos] || considered[pos] 
     823          || !worms_are_connected(this_worm, pos)) 
     824        continue; 
     825 
     826      DEBUG(DEBUG_DRAGONS, "  queueing %1m.\n", pos); 
     827      considered[pos] = 1; 
     828      aspiring_worms[num_aspiring] = pos; 
     829      num_aspiring++; 
     830    } 
     831     
     832    while (num_aspiring > 0) { 
     833      int j; 
     834      int w; 
     835      int largest_worm = -1; 
     836      float largest_size = 0.0; 
     837       
     838      for (j = 0; j < num_aspiring; j++) { 
     839        if (effective_sizes[aspiring_worms[j]] > largest_size) { 
     840          largest_worm = j; 
     841          largest_size = effective_sizes[aspiring_worms[j]]; 
     842        } 
     843      } 
     844 
     845      w = aspiring_worms[largest_worm]; 
     846      num_aspiring--; 
     847      aspiring_worms[largest_worm] = aspiring_worms[num_aspiring]; 
     848       
     849      for (j = 0; j < num_worms; j++) { 
     850        if (worms_are_intransitively_connected(w, worms_in_this_dragon[j])) { 
     851          DEBUG(DEBUG_DRAGONS, 
     852                "  intransitive connection to %1m, discarding %1m.\n", 
     853                worms_in_this_dragon[j], w); 
     854          break; 
     855        } 
     856      } 
     857       
     858      if (j == num_worms) { 
     859        worms_in_this_dragon[num_worms] = w; 
     860        num_worms++; 
     861        amalgamated[w] = 1; 
     862        join_dragons(starting_worm, w); 
     863        break; 
     864      } 
     865    } 
     866  } 
     867} 
     868 
    747869/* Examine which dragons are adjacent to each other. This is 
    748870 * complicated by the fact that adjacency may involve a certain 
    749871 * amount of empty space. 
     
    16011723  int pos; 
    16021724  int saved_cutting_points[BOARDMAX]; 
    16031725 
    1604   /* This is currently necessary in order not to mess up the 
    1605    * worm[].cutstone2 field. See cutstone2_helper in 
    1606    * patterns/helpers.c. On the other hand it shouldn't be very 
     1726  /* This is currently necessary in order not to mess up various 
     1727   * information such as the worm[].cutstone2 field (see 
     1728   * cutstone2_helper in patterns/helpers.c) and the static worm 
     1729   * connection analysis. On the other hand it shouldn't be very 
    16071730   * interesting to recompute dragons in the original position. 
    16081731   */ 
    16091732  gg_assert(stackp > 0); 
     
    16181741        new_dragon_origins[pos] = find_origin(pos); 
    16191742    } 
    16201743   
     1744  if (experimental_connections) 
     1745    initialize_static_worm_connections(); 
    16211746  find_cuts(); 
    16221747  find_connections(); 
     1748  if (experimental_connections) { 
     1749    analyze_worm_connections(); 
     1750    amalgamate_dragons(BLACK); 
     1751    amalgamate_dragons(WHITE); 
     1752  } 
    16231753 
    16241754  memcpy(cutting_points, saved_cutting_points, sizeof(cutting_points)); 
    16251755  memcpy(dragon_origins, new_dragon_origins, sizeof(new_dragon_origins)); 
  • engine/liberty.h

    RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
    retrieving revision 1.255
    diff -u -r1.255 liberty.h
     
    325325void mark_inessential_stones(int color, signed char safe_stones[BOARDMAX]); 
    326326 
    327327void get_lively_stones(int color, signed char safe_stones[BOARDMAX]); 
     328void compute_effective_string_sizes(float effective_sizes[BOARDMAX]); 
    328329int is_same_worm(int w1, int w2); 
    329330int is_worm_origin(int w, int pos); 
    330331void propagate_worm(int pos); 
    331332void find_cuts(void); 
    332333void find_connections(void); 
    333334 
     335void initialize_static_worm_connections(void); 
     336void analyze_worm_connections(void); 
     337void register_potential_worm_connection(int w1, int w2); 
     338int worms_are_connected(int w1, int w2); 
     339int worms_are_connected_with_ko(int w1, int w2); 
     340int worms_are_close(int w1, int w2); 
     341int worms_are_intransitively_connected(int w1, int w2); 
     342 
    334343/* movelist.c */ 
    335344int movelist_move_known(int move, int max_points, int points[], int codes[]); 
    336345void movelist_change_point(int move, int code, int max_points,  
  • engine/owl.c

    RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
    retrieving revision 1.246
    diff -u -r1.246 owl.c
     
    7272  /* Same as goal, except never anything is removed from it. */ 
    7373  signed char cumulative_goal[BOARDMAX]; 
    7474 
     75  int original_goal_strings[MAX_GOAL_WORMS]; 
     76  int num_original_goal_strings; 
     77   
    7578  /* FIXME: neighbors[] and escape_values[] are never recomputed. 
    7679   *        Consider moving these arrays from stack to a static or 
    7780   *        dynamic variable so it is not copied around in 
     
    18391842  int value1; 
    18401843  int value2; 
    18411844  int this_variation_number = count_variations - 1; 
     1845  int all_original_strings_tactically_unstable; 
     1846  SGFTree *save_sgf_dumptree; 
     1847  int save_count_variations; 
    18421848   
    18431849  SETUP_TRACE_INFO("owl_attack", str); 
    18441850 
     
    18801886    READ_RETURN(OWL_ATTACK, str, depth - stackp, move, 0, 0); 
    18811887  } 
    18821888 
     1889  /* Do not give up if all original strings are tactically unstable. 
     1890   */ 
     1891  save_sgf_dumptree = sgf_dumptree; 
     1892  save_count_variations = count_variations; 
     1893  sgf_dumptree = NULL; 
     1894  count_variations = 0; 
     1895  all_original_strings_tactically_unstable = 1; 
     1896  for (k = 0; k < owl->num_original_goal_strings; k++) { 
     1897    if (!attack(owl->original_goal_strings[k], NULL)) { 
     1898      all_original_strings_tactically_unstable = 0; 
     1899      break; 
     1900    } 
     1901  } 
     1902  sgf_dumptree = save_sgf_dumptree; 
     1903  count_variations = save_count_variations; 
     1904   
    18831905  memset(mw, 0, sizeof(mw)); 
    18841906  global_owl_node_counter++; 
    18851907  local_owl_node_counter++; 
     
    18891911 
    18901912  /* First see whether there is any chance to kill. */ 
    18911913  if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 1, 
    1892                         &probable_eyes, &eyemin, &eyemax)) { 
     1914                        &probable_eyes, &eyemin, &eyemax) 
     1915      && !all_original_strings_tactically_unstable) { 
    18931916    /* 
    18941917     * We need to check here if there's a worm under atari. If yes, 
    18951918     * locate it and report a (gote) GAIN. 
     
    19311954 
    19321955  /* We try moves in five passes. 
    19331956   *                                stackp==0   stackp>0 
    1934    * 0. Vital moves in the interval  [70..]      [45..] 
    1935    * 1. Shape moves 
    1936    * 2. Vital moves in the interval  [..69]      [..44] 
    1937    * 3. Tactical attack moves (except certain kos) 
    1938    * 4. Moves found by the defender 
    1939    * 5. Tactical ko attack moves which were not tried in pass 3 
     1957   * 1. Tactical attack moves if all original strings are unstable. 
     1958   * 2. Vital moves in the interval  [70..]      [45..] 
     1959   * 3. Shape moves 
     1960   * 4. Vital moves in the interval  [..69]      [..44] 
     1961   * 5. Tactical attack moves (except certain kos) 
     1962   * 6. Moves found by the defender 
     1963   * 7. Tactical ko attack moves which were not tried in pass 3 
    19401964   */ 
    1941   for (pass = 0; pass < 6; pass++) { 
     1965  for (pass = 1; pass < 8; pass++) { 
    19421966    moves = NULL; 
    19431967    move_cutoff = 1; 
    19441968     
    19451969    current_owl_data = owl; 
    19461970    /* Get the shape moves if we are in the right pass. */ 
    19471971    switch (pass) { 
    1948     case 1: 
     1972    case 3: 
    19491973      if (stackp > owl_branch_depth && number_tried_moves > 0) 
    19501974        continue; 
    19511975       
     
    19531977      moves = shape_moves; 
    19541978      break; 
    19551979 
    1956     case 0: 
    19571980    case 2: 
     1981    case 4: 
    19581982      if (stackp > owl_branch_depth && number_tried_moves > 0) 
    19591983        continue; 
    19601984       
    19611985      moves = vital_moves; 
    1962       if (pass == 0 || stackp > owl_distrust_depth) { 
     1986      if (pass == 2 || stackp > owl_distrust_depth) { 
    19631987        if (stackp == 0) 
    19641988          move_cutoff = 70; 
    19651989        else 
     
    19691993        move_cutoff = 99; /* Effectively disable vital moves. */ 
    19701994      break; 
    19711995 
    1972     case 3: 
     1996    case 1: 
     1997      if (!all_original_strings_tactically_unstable) 
     1998        break; 
     1999      /* Otherwise fall through. */ 
    19732000    case 5: 
     2001    case 7: 
    19742002      { 
    19752003        /* Look for a tactical attack. This is primarily intended for 
    19762004         * the case where the whole dragon is a single string, therefore 
     
    19792007         * We must be wary with attacks giving ko. Unless the dragon 
    19802008         * otherwise looks alive, this may turn a dead dragon into one 
    19812009         * which can live by ko. Such moves will be tried anyway in 
    1982          * pass 5. Notice though that we can only reach there if an owl 
    1983          * defense was found in pass 4. 
     2010         * pass 7. Notice though that we can only reach there if an owl 
     2011         * defense was found in pass 6. 
    19842012         */ 
    19852013        int apos; 
    19862014        int result; 
     
    19922020        result = attack(str, &apos); 
    19932021        if (result == WIN 
    19942022            || (result != 0 && (min_eyes(&probable_eyes) >= 2 
    1995                                 || pass == 5))) { 
     2023                                || pass == 7))) { 
    19962024          set_single_owl_move(shape_moves, apos, "tactical attack"); 
    19972025          moves = shape_moves; 
    19982026        } 
     
    20042032    /* If we found no move in the first four passes we ask the defender 
    20052033     * for a move suggestion. 
    20062034     */ 
    2007     case 4: 
     2035    case 6: 
    20082036      if (number_tried_moves == 0) { 
    20092037        int dpos; 
    20102038        int dcode = do_owl_defend(str, &dpos, NULL, owl, escape); 
     
    20912119      current_owl_data = owl; 
    20922120 
    20932121      /* Shape moves are selected on demand. */ 
    2094       if (pass == 1) { 
     2122      if (pass == 3) { 
    20952123        if (!get_next_move_from_list(&shape_patterns, other, 
    20962124                                     shape_moves, move_cutoff, owl)) 
    20972125          break; 
     
    21342162       */ 
    21352163      if (IS_STONE(board[str])) 
    21362164        origin = str; 
     2165      else if (owl->num_original_goal_strings > 0) 
     2166        origin = owl->original_goal_strings[0]; 
    21372167      else 
    2138         origin = select_new_goal_origin(NO_MOVE, owl); 
     2168        origin = NO_MOVE; 
    21392169 
    21402170      /* Test whether the move cut the goal dragon apart. */ 
    21412171      if (moves[k].cuts[0] != NO_MOVE) { 
     
    21472177 
    21482178      if (origin == NO_MOVE) 
    21492179        dcode = 0; 
    2150       else 
     2180      else { 
    21512181        dcode = do_owl_defend(origin, NULL, &wid, owl, escape); 
     2182      } 
    21522183 
    21532184      if (!ko_move) { 
    21542185        if (dcode == 0) { 
     
    24732504  int eyemin = -1;               /* Lower bound on the number of eyes. */ 
    24742505  int eyemax = -1;               /* Upper bound on the number of eyes. */ 
    24752506  struct eyevalue probable_eyes; /* Best guess of eyevalue. */ 
    2476   int escape_route; 
    24772507  const char *live_reason; 
    24782508  int move_cutoff; 
    24792509  int xpos; 
    24802510  int value1; 
    24812511  int value2; 
    24822512  int this_variation_number = count_variations - 1; 
     2513  int all_original_strings_tactically_unstable; 
     2514  SGFTree *save_sgf_dumptree; 
     2515  int save_count_variations; 
    24832516 
    24842517  SETUP_TRACE_INFO("owl_defend", str); 
    24852518 
     
    25142547    return value1; 
    25152548  } 
    25162549 
     2550  /* Do not declare victory if all original strings are tactically 
     2551   * unstable. 
     2552   */ 
     2553  save_sgf_dumptree = sgf_dumptree; 
     2554  save_count_variations = count_variations; 
     2555  sgf_dumptree = NULL; 
     2556  count_variations = 0; 
     2557  all_original_strings_tactically_unstable = 1; 
     2558  for (k = 0; k < owl->num_original_goal_strings; k++) { 
     2559    if (!attack(owl->original_goal_strings[k], NULL)) { 
     2560      all_original_strings_tactically_unstable = 0; 
     2561      break; 
     2562    } 
     2563  } 
     2564  sgf_dumptree = save_sgf_dumptree; 
     2565  count_variations = save_count_variations; 
     2566   
    25172567  /* In order to get a defense move even if we seem to already have 
    25182568   * escaped and to reduce the impact of overestimated escape 
    25192569   * possibilities, we don't declare escape victory on the first move. 
     
    25212571   * FIXME: Should introduce a new owl depth value rather than having 
    25222572   *        this hardwired value. 
    25232573   */ 
    2524   escape_route = owl_escape_route(owl); 
    2525   if (stackp > 2 && escape_route >= 5) { 
    2526     /* FIXME: We probably should make distinction in the returned 
    2527      * result whether the dragon lives by making two eyes or by 
    2528      * escaping. 
    2529      */ 
    2530     TRACE("%oVariation %d: ALIVE (escaped)\n", this_variation_number); 
    2531     SGFTRACE(0, WIN, "escaped"); 
    2532     READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN); 
     2574  if (stackp > 2 && !all_original_strings_tactically_unstable) { 
     2575    int escape_route = owl_escape_route(owl); 
     2576    if (escape_route >= 5) { 
     2577      /* FIXME: We probably should make distinction in the returned 
     2578       * result whether the dragon lives by making two eyes or by 
     2579       * escaping. 
     2580       */ 
     2581      TRACE("%oVariation %d: ALIVE (escaped)\n", this_variation_number); 
     2582      SGFTRACE(0, WIN, "escaped"); 
     2583      READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN); 
     2584    } 
    25332585  } 
    25342586 
    2535   /* If reading goes to deep or we run out of nodes, we assume life. */ 
     2587  /* If reading goes too deep or we run out of nodes, we assume life. */ 
    25362588  if (reading_limit_reached(&live_reason, this_variation_number)) { 
    25372589    SGFTRACE(0, WIN, live_reason); 
    25382590    READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN); 
     
    25452597  current_owl_data = owl; 
    25462598  memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache)); 
    25472599 
    2548   /* First see whether we might already be alife. */ 
     2600  /* First see whether we might already be alive. */ 
    25492601  if (escape < MAX_ESCAPE) { 
    25502602    if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 0, 
    2551                           &probable_eyes, &eyemin, &eyemax)) { 
     2603                          &probable_eyes, &eyemin, &eyemax) 
     2604        && !all_original_strings_tactically_unstable) { 
    25522605      SGFTRACE(0, WIN, live_reason); 
    25532606      TRACE("%oVariation %d: ALIVE (%s)\n", 
    25542607            this_variation_number, live_reason); 
     
    25712624 
    25722625  /* We try moves in four passes. 
    25732626   *                                stackp==0   stackp>0 
    2574    * 0. Vital moves in the interval  [70..]      [45..] 
    2575    * 1. Shape moves 
    2576    * 2. Vital moves in the interval  [..69]      [..44] 
    2577    * 3. Tactical defense moves 
     2627   * 1. Tactical defense moves if all original strings unstable 
     2628   * 2. Vital moves in the interval  [70..]      [45..] 
     2629   * 3. Shape moves 
     2630   * 4. Vital moves in the interval  [..69]      [..44] 
     2631   * 5. Tactical defense moves 
    25782632   */ 
    2579   for (pass = 0; pass < 4; pass++) { 
     2633  for (pass = 1; pass < 6; pass++) { 
    25802634    moves = NULL; 
    25812635    move_cutoff = 1; 
    25822636     
    25832637    current_owl_data = owl; 
    25842638    switch (pass) { 
    25852639    /* Get the shape moves if we are in the right pass. */ 
    2586     case 1: 
     2640    case 3: 
    25872641       
    25882642      if (stackp > owl_branch_depth && number_tried_moves > 0) 
    25892643        continue; 
     
    25922646      moves = shape_moves; 
    25932647      break; 
    25942648 
    2595     case 0: 
    25962649    case 2: 
     2650    case 4: 
    25972651      if (stackp > owl_branch_depth && number_tried_moves > 0) 
    25982652        continue; 
    25992653       
    26002654      moves = vital_moves; 
    2601       if (pass == 0 || stackp > owl_distrust_depth) { 
     2655      if (pass == 2 || stackp > owl_distrust_depth) { 
    26022656        if (stackp == 0) 
    26032657          move_cutoff = 70; 
    26042658        else if (eyemin + min_eyes(&probable_eyes) > 3) 
     
    26122666        move_cutoff = 99; /* Effectively disable vital moves. */ 
    26132667      break; 
    26142668 
    2615     case 3: 
     2669    case 1: 
     2670    case 5: 
    26162671      { 
    26172672        int goalcount = 0; 
    26182673 
     
    26222677          if (ON_BOARD(k)) 
    26232678            goalcount += owl->goal[k]; 
    26242679 
    2625         if (goalcount < 5) { 
     2680        if ((pass == 5 && all_original_strings_tactically_unstable) 
     2681            || (pass == 5 && goalcount < 5)) { 
    26262682 
    26272683          /* Look for a tactical defense. This is primarily intended for 
    26282684           * the case where the whole dragon is a single string, therefore 
     
    26352691           * confusing the eye analysis. 
    26362692           */ 
    26372693          int dpos; 
    2638           SGFTree *save_sgf_dumptree = sgf_dumptree; 
    2639           int save_count_variations = count_variations; 
     2694          save_sgf_dumptree = sgf_dumptree; 
     2695          save_count_variations = count_variations; 
    26402696 
    26412697          sgf_dumptree = NULL; 
    26422698          count_variations = 0; 
     
    26762732       
    26772733      current_owl_data = owl; 
    26782734       
    2679       if (pass == 1) { 
     2735      if (pass == 3) { 
    26802736        if (!get_next_move_from_list(&shape_patterns, color, shape_moves, 
    26812737                                     move_cutoff, owl)) 
    26822738          break; 
     
    44524508  int color = board[apos]; 
    44534509   
    44544510  ASSERT1(bpos == NO_MOVE || board[bpos] == color, bpos); 
    4455  
     4511   
    44564512  if (new_dragons == NULL) { 
    44574513    for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
    44584514      if (ON_BOARD(pos)) { 
     
    44744530      } 
    44754531  } 
    44764532 
     4533  owl->num_original_goal_strings = 0; 
     4534  for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     4535    if (IS_STONE(board[pos]) 
     4536        && owl->goal[pos] 
     4537        && owl->num_original_goal_strings < MAX_GOAL_WORMS 
     4538        && find_origin(pos) == pos) { 
     4539      owl->original_goal_strings[owl->num_original_goal_strings] = pos; 
     4540      owl->num_original_goal_strings++; 
     4541    } 
     4542 
    44774543  memcpy(owl->cumulative_goal, owl->goal, sizeof(owl->goal)); 
    44784544  owl->color = color; 
    44794545  owl_mark_boundary(owl); 
     4546  if (owl->num_original_goal_strings == 1) 
     4547    owl_update_goal(apos, 2, NO_MOVE, owl, 0); 
    44804548} 
    44814549 
    44824550 
     
    46204688  int stones[MAX_BOARD * MAX_BOARD]; 
    46214689  int num_stones; 
    46224690  int k; 
     4691  int m; 
    46234692  int do_add = 1; 
    46244693  SGFTree *save_sgf_dumptree = sgf_dumptree; 
    46254694  int save_count_variations = count_variations; 
     
    46764745      } 
    46774746  } 
    46784747 
     4748  /* Update the list of original goal strings. This move may have 
     4749   * merged two or more of the strings. 
     4750   */ 
     4751  for (k = 0; k < owl->num_original_goal_strings; k++) { 
     4752    for (m = 0; m < k; m++) 
     4753      if (same_string(owl->original_goal_strings[k], 
     4754                      owl->original_goal_strings[m])) { 
     4755        owl->num_original_goal_strings--; 
     4756        owl->original_goal_strings[k] = 
     4757          owl->original_goal_strings[owl->num_original_goal_strings]; 
     4758        k--; 
     4759        break; 
     4760      } 
     4761  } 
     4762 
     4763  /*  It might also have recreated a previously captured string. */ 
     4764  if (owl->goal[pos] == 1 
     4765      && owl->num_original_goal_strings < MAX_GOAL_WORMS) { 
     4766    for (k = 0; k < owl->num_original_goal_strings; k++) { 
     4767      if (same_string(owl->original_goal_strings[k], pos)) 
     4768        break; 
     4769    } 
     4770    if (k == owl->num_original_goal_strings) { 
     4771      owl->original_goal_strings[owl->num_original_goal_strings] = pos; 
     4772      owl->num_original_goal_strings++; 
     4773    } 
     4774  } 
     4775 
    46794776  if (1 && verbose) 
    46804777    goaldump(owl->goal); 
    46814778} 
     
    48984995  } 
    48994996 
    49004997  mark_string(pos, owl->boundary, boundary_mark); 
     4998 
     4999  /* The move may have captured one or more of the original goal strings. */ 
     5000  for (k = 0; k < owl->num_original_goal_strings; k++) { 
     5001    if (board[owl->original_goal_strings[k]] == EMPTY) { 
     5002      owl->num_original_goal_strings--; 
     5003      owl->original_goal_strings[k] = 
     5004        owl->original_goal_strings[owl->num_original_goal_strings]; 
     5005      k--; 
     5006    } 
     5007  } 
    49015008} 
    49025009 
    49035010/* Lists the goal array. For use in GDB: 
     
    59646071  int result; 
    59656072  double start = 0.0; 
    59666073  struct local_owl_data *owl; 
     6074  int pos; 
    59676075  int num_moves = 0; 
    59686076 
    59696077  if (debug & DEBUG_OWL_PERFORMANCE) 
     
    60416149  /* FIXME: We would want to use init_owl() here too, but it doesn't 
    60426150   * fit very well with the construction of the goal array above. 
    60436151   */ 
     6152  owl->num_original_goal_strings = 0; 
     6153  for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     6154    if (ON_BOARD(pos) 
     6155        && owl->goal[pos] 
     6156        && owl->num_original_goal_strings < MAX_GOAL_WORMS 
     6157        && find_origin(pos) == pos) { 
     6158      owl->original_goal_strings[owl->num_original_goal_strings] = pos; 
     6159      owl->num_original_goal_strings++; 
     6160    } 
     6161 
    60446162  memcpy(owl->cumulative_goal, owl->goal, BOARDMAX); 
    60456163  compute_owl_escape_values(owl); 
    60466164  owl_mark_boundary(owl); 
     
    66516769  memcpy(new_owl->cumulative_goal, (*owl)->cumulative_goal, 
    66526770         sizeof(new_owl->cumulative_goal)); 
    66536771  memcpy(new_owl->boundary, (*owl)->boundary, sizeof(new_owl->boundary)); 
     6772  memcpy(new_owl->original_goal_strings, (*owl)->original_goal_strings, 
     6773         sizeof(new_owl->original_goal_strings)); 
     6774  new_owl->num_original_goal_strings = (*owl)->num_original_goal_strings; 
    66546775  memcpy(new_owl->neighbors, (*owl)->neighbors, sizeof(new_owl->neighbors)); 
    66556776  memcpy(new_owl->escape_values, (*owl)->escape_values, 
    66566777         sizeof(new_owl->escape_values)); 
  • engine/worm.c

    RCS file: /cvsroot/gnugo/gnugo/engine/worm.c,v
    retrieving revision 1.71
    diff -u -r1.71 worm.c
     
    3232static void compute_effective_worm_sizes(void); 
    3333static void do_compute_effective_worm_sizes(int color, 
    3434                                            int (*cw)[MAX_CLOSE_WORMS], 
    35                                             int *ncw, int max_distance); 
     35                                            int *ncw, float *effective_sizes, 
     36                                            int max_distance); 
    3637static void compute_unconditional_status(void); 
    3738static void find_worm_attacks_and_defenses(void); 
    3839static void find_worm_threats(void); 
     
    566567static void 
    567568compute_effective_worm_sizes() 
    568569{ 
     570  float effective_sizes[BOARDMAX]; 
     571  int pos; 
     572   
    569573  do_compute_effective_worm_sizes(BLACK | WHITE, close_worms, 
    570                                   number_close_worms, 3); 
     574                                  number_close_worms, effective_sizes, 3); 
     575   
     576  for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     577    if (IS_STONE(board[pos])) 
     578      worm[pos].effective_size = effective_sizes[worm[pos].origin]; 
     579   
    571580  do_compute_effective_worm_sizes(BLACK, close_black_worms, 
    572                                   number_close_black_worms, 5); 
     581                                  number_close_black_worms, NULL, 5); 
     582   
    573583  do_compute_effective_worm_sizes(WHITE, close_white_worms, 
    574                                   number_close_white_worms, 5); 
     584                                  number_close_white_worms, NULL, 5); 
     585} 
     586 
     587/* Same as above but does not write to the worm array or update the 
     588 * close worms arrays. Intended to be used when stackp > 0. 
     589 */ 
     590void 
     591compute_effective_string_sizes(float effective_sizes[BOARDMAX]) 
     592{ 
     593  do_compute_effective_worm_sizes(BLACK | WHITE, NULL, NULL, 
     594                                   effective_sizes, 3); 
    575595} 
    576596 
    577597static void 
    578598do_compute_effective_worm_sizes(int color, int (*cw)[MAX_CLOSE_WORMS], 
    579                                 int *ncw, int max_distance) 
     599                                int *ncw, float *effective_sizes, 
     600                                int max_distance) 
    580601{ 
    581602  int pos; 
    582603 
     
    647668    } 
    648669  } 
    649670 
    650   /* Compute the effective sizes but only when all worms are considered. */ 
    651   if (color == (BLACK | WHITE)) { 
     671  /* Compute the effective sizes if caller wants them. */ 
     672  if (effective_sizes) { 
     673    for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     674      if (ON_BOARD(pos)) 
     675        effective_sizes[pos] = 0.0; 
     676       
    652677    /* Distribute (fractional) contributions to the worms. */ 
    653678    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
    654679      if (!ON_BOARD(pos)) 
     
    657682      for (k = 0; k < nworms[pos]; k++) { 
    658683        int w = worms[pos][k]; 
    659684        if (board[pos] == EMPTY) 
    660           worm[w].effective_size += 0.5/nworms[pos]; 
     685          effective_sizes[w] += 0.5/nworms[pos]; 
    661686        else 
    662           worm[w].effective_size += 1.0; 
     687          effective_sizes[w] += 1.0; 
    663688      } 
    664689    } 
    665      
    666     /* Propagate the effective size values all over the worms. */ 
    667     for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
    668       if (IS_STONE(board[pos]) && is_worm_origin(pos, pos)) 
    669         propagate_worm(pos); 
    670690  } 
    671691 
    672692  /* Fill in the appropriate close_*_worms (cw) and 
     
    676696    if (!ON_BOARD(pos)) 
    677697      continue; 
    678698 
    679     if (nworms[pos] > MAX_CLOSE_WORMS) 
    680       ncw[pos] = 0; 
    681     else 
    682       ncw[pos] = nworms[pos]; 
     699    if (ncw) { 
     700      if (nworms[pos] > MAX_CLOSE_WORMS) 
     701        ncw[pos] = 0; 
     702      else 
     703        ncw[pos] = nworms[pos]; 
     704    } 
    683705 
    684     for (k = 0; k < ncw[pos]; k++) 
    685       cw[pos][k] = worms[pos][k]; 
     706    if (cw) 
     707      for (k = 0; k < ncw[pos]; k++)  
     708        cw[pos][k] = worms[pos][k]; 
    686709  } 
    687710} 
    688711 
     
    16211644         * possible that it only has a ko defense and then we would 
    16221645         * risk to find an irrelevant move to attack with ko. 
    16231646         */ 
    1624         if (dcode != WIN && REVERSE_RESULT(dcode) >= worm[str].attack_codes[0]) { 
     1647        if (dcode != WIN 
     1648            && REVERSE_RESULT(dcode) >= worm[str].attack_codes[0]) { 
    16251649          change_attack(str, move, REVERSE_RESULT(dcode)); 
    16261650          DEBUG(DEBUG_WORMS, 
    16271651                "Attack pattern %s+%d found attack on %1m at %1m with code %d\n", 
     
    17321756} 
    17331757 
    17341758/* ================================================================ */ 
     1759/*                Static worm connection analysis                   */ 
     1760/* ================================================================ */ 
     1761 
     1762/* The static worm connection analysis uses the C patterns in conn.db 
     1763 * to find worms which are close enough so that the connection reading 
     1764 * can be expected to determine that they are expected unless there is 
     1765 * a serious connection problem. Then connection reading is done to 
     1766 * see which of these are indeed connected and intransitive 
     1767 * connections (A connected to B and B connected to C but A not 
     1768 * connected to C) are detected. 
     1769 * 
     1770 * The results are stored in a two-dimensional array for each pair of 
     1771 * worms. Only the worm origins have valid data. Each entry is an 
     1772 * unsigned char where the three lowest bits contain the disconnect 
     1773 * result code, the fourth bit marks potential connections (as found 
     1774 * by the C patterns in conn.db) and the fifth bit is set for pairs of 
     1775 * strings being intransitively connected. 
     1776 * 
     1777 * There are two parallel worm connection matrices. The primary one is 
     1778 * used at stackp==0 and contains the static information for the 
     1779 * original position. The secondary array is used when stackp>0, 
     1780 * primarily to allow computation of a new set of dragons after a move 
     1781 * has been made. 
     1782 */ 
     1783static unsigned char primary_worm_connection_matrix[BOARDMAX][BOARDMAX]; 
     1784static unsigned char secondary_worm_connection_matrix[BOARDMAX][BOARDMAX]; 
     1785/* The three lowest bits in the matrix store the disconnect result. */ 
     1786#define POTENTIAL_WORM_CONNECTION     8 
     1787#define INTRANSITIVE_WORM_CONNECTION 16 
     1788 
     1789void 
     1790initialize_static_worm_connections(void) 
     1791{ 
     1792  int w1; 
     1793  int w2; 
     1794 
     1795  unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 
     1796  if (stackp == 0) 
     1797    worm_connection_matrix = &primary_worm_connection_matrix; 
     1798  else 
     1799    worm_connection_matrix = &secondary_worm_connection_matrix; 
     1800   
     1801#if 0 
     1802  memset(worm_connection_matrix, 0, sizeof(worm_connection_matrix)); 
     1803#else 
     1804  for (w1 = BOARDMIN; w1 < BOARDMAX; w1++) 
     1805    for (w2 = BOARDMIN; w2 < BOARDMAX; w2++) 
     1806      (*worm_connection_matrix)[w1][w2] = 0; 
     1807#endif 
     1808} 
     1809 
     1810#define DEBUG_EXPERIMENTAL_CONNECTIONS \ 
     1811  ((debug & DEBUG_DRAGONS) && experimental_connections) 
     1812 
     1813 
     1814void 
     1815analyze_worm_connections() 
     1816{ 
     1817  int w1; 
     1818  int w2; 
     1819  int w3; 
     1820 
     1821  unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 
     1822  if (stackp == 0) 
     1823    worm_connection_matrix = &primary_worm_connection_matrix; 
     1824  else 
     1825    worm_connection_matrix = &secondary_worm_connection_matrix; 
     1826   
     1827  if (DEBUG_EXPERIMENTAL_CONNECTIONS) 
     1828    gprintf("analyze_worm_connections\n"); 
     1829   
     1830  for (w1 = BOARDMIN; w1 < BOARDMAX; w1++) { 
     1831    if (!IS_STONE(board[w1]) || w1 != find_origin(w1)) 
     1832      continue; 
     1833     
     1834    for (w2 = w1 + 1; w2 < BOARDMAX; w2++) { 
     1835      if (board[w2] != board[w1] || w2 != find_origin(w2)) 
     1836        continue; 
     1837 
     1838      if ((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) { 
     1839        int nodes = get_connection_node_counter(); 
     1840        unsigned char disconnect_result = disconnect(w1, w2, NULL); 
     1841        gg_assert(disconnect_result < 8); 
     1842        (*worm_connection_matrix)[w1][w2] |= disconnect_result; 
     1843        (*worm_connection_matrix)[w2][w1] |= disconnect_result; 
     1844        if (DEBUG_EXPERIMENTAL_CONNECTIONS) 
     1845          gprintf("disconnect %1m %1m = %d, %d nodes %d %d\n", w1, w2, 
     1846                  disconnect_result, get_connection_node_counter() - nodes, 
     1847                  (*worm_connection_matrix)[w1][w2], 
     1848                  (*worm_connection_matrix)[w2][w1]); 
     1849      } 
     1850    } 
     1851  } 
     1852 
     1853  for (w1 = BOARDMIN; w1 < BOARDMAX; w1++) { 
     1854    if (!IS_STONE(board[w1]) || w1 != find_origin(w1)) 
     1855      continue; 
     1856     
     1857    for (w2 = BOARDMIN; w2 < BOARDMAX; w2++) { 
     1858      if (w2 == w1 || board[w2] != board[w1] || w2 != find_origin(w2)) 
     1859        continue; 
     1860 
     1861      if (!((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) 
     1862          || ((*worm_connection_matrix)[w1][w2] & 7) != 0) 
     1863        continue; 
     1864 
     1865      for (w3 = BOARDMIN; w3 < BOARDMAX; w3++) { 
     1866        if (w3 == w2 || board[w3] != board[w2] || w3 != find_origin(w3)) 
     1867          continue; 
     1868       
     1869        if (!((*worm_connection_matrix)[w2][w3] & POTENTIAL_WORM_CONNECTION) 
     1870            || ((*worm_connection_matrix)[w2][w3] & 7) != 0) 
     1871          continue; 
     1872 
     1873        if (((*worm_connection_matrix)[w1][w3] & POTENTIAL_WORM_CONNECTION) 
     1874            && ((*worm_connection_matrix)[w1][w3] & 7) != 0) { 
     1875          if (DEBUG_EXPERIMENTAL_CONNECTIONS) 
     1876            gprintf("intransitive connection %1m - %1m - %1m %d\n", w1, w2, w3, 
     1877                    (*worm_connection_matrix)[w1][w3], 
     1878                    (*worm_connection_matrix)[w3][w1]); 
     1879          (*worm_connection_matrix)[w1][w3] |= INTRANSITIVE_WORM_CONNECTION; 
     1880          (*worm_connection_matrix)[w3][w1] |= INTRANSITIVE_WORM_CONNECTION; 
     1881        } 
     1882      } 
     1883    } 
     1884  } 
     1885} 
     1886 
     1887static void 
     1888normalize_worms(int *w1, int *w2) 
     1889{ 
     1890  *w1 = find_origin(*w1); 
     1891  *w2 = find_origin(*w2); 
     1892} 
     1893 
     1894void 
     1895register_potential_worm_connection(int w1, int w2) 
     1896{ 
     1897  unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 
     1898  if (stackp == 0) 
     1899    worm_connection_matrix = &primary_worm_connection_matrix; 
     1900  else 
     1901    worm_connection_matrix = &secondary_worm_connection_matrix; 
     1902   
     1903  normalize_worms(&w1, &w2); 
     1904  if (DEBUG_EXPERIMENTAL_CONNECTIONS 
     1905      && !((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION)) 
     1906    gprintf("Registered potential worm connection %1m - %1m %d %d\n", w1, w2, 
     1907            (*worm_connection_matrix)[w1][w2], 
     1908            (*worm_connection_matrix)[w2][w1]); 
     1909  (*worm_connection_matrix)[w1][w2] |= POTENTIAL_WORM_CONNECTION; 
     1910  (*worm_connection_matrix)[w2][w1] |= POTENTIAL_WORM_CONNECTION; 
     1911} 
     1912 
     1913int 
     1914worms_are_connected(int w1, int w2) 
     1915{ 
     1916  unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 
     1917  if (stackp == 0) 
     1918    worm_connection_matrix = &primary_worm_connection_matrix; 
     1919  else 
     1920    worm_connection_matrix = &secondary_worm_connection_matrix; 
     1921   
     1922  normalize_worms(&w1, &w2); 
     1923  if (((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) 
     1924      && ((*worm_connection_matrix)[w1][w2] & 7) == 0) 
     1925    return 1; 
     1926 
     1927  return 0; 
     1928} 
     1929 
     1930int 
     1931worms_are_connected_with_ko(int w1, int w2) 
     1932{ 
     1933  unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 
     1934  if (stackp == 0) 
     1935    worm_connection_matrix = &primary_worm_connection_matrix; 
     1936  else 
     1937    worm_connection_matrix = &secondary_worm_connection_matrix; 
     1938   
     1939  normalize_worms(&w1, &w2); 
     1940  if (((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) 
     1941      && (((*worm_connection_matrix)[w1][w2] & 7) == KO_A 
     1942          || ((*worm_connection_matrix)[w1][w2] & 7) == KO_B)) 
     1943    return 1; 
     1944 
     1945  return 0; 
     1946} 
     1947 
     1948int 
     1949worms_are_close(int w1, int w2) 
     1950{ 
     1951  unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 
     1952  if (stackp == 0) 
     1953    worm_connection_matrix = &primary_worm_connection_matrix; 
     1954  else 
     1955    worm_connection_matrix = &secondary_worm_connection_matrix; 
     1956   
     1957  normalize_worms(&w1, &w2); 
     1958  return ((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION); 
     1959} 
     1960 
     1961int 
     1962worms_are_intransitively_connected(int w1, int w2) 
     1963{ 
     1964  unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 
     1965  if (stackp == 0) 
     1966    worm_connection_matrix = &primary_worm_connection_matrix; 
     1967  else 
     1968    worm_connection_matrix = &secondary_worm_connection_matrix; 
     1969   
     1970  normalize_worms(&w1, &w2); 
     1971  return ((*worm_connection_matrix)[w1][w2] & INTRANSITIVE_WORM_CONNECTION); 
     1972} 
     1973 
     1974/* ================================================================ */ 
    17351975/*                      Debugger functions                          */ 
    17361976/* ================================================================ */ 
    17371977 
  • patterns/conn.db

    RCS file: /cvsroot/gnugo/gnugo/patterns/conn.db,v
    retrieving revision 1.43
    diff -u -r1.43 conn.db
     
    7777# 
    7878######################## 
    7979 
    80 callback_data X! 
     80callback_data OX! 
     81 
     82Pattern EB1 
     83 
     84OxOxO 
     85..*.. 
     86----- 
     87 
     88:|,BY 
    8189 
    8290 
    8391########################## 
     
    8694# 
    8795########################## 
    8896 
    89 callback_data X! 
     97callback_data OX! 
    9098 
    9199 
    92100Pattern CB1b 
     
    443451# 
    444452############################ 
    445453 
     454Pattern CC330 
     455 
     456O.o 
     457XOo 
     458O.o 
     459XOo 
     460 
     461:8,CY 
     462 
     463 
     464 
    446465#################################################################### 
    447466# 
    448467# CC4xx -  fragile double connections 
     
    489508Xaf 
    490509?e. 
    491510 
    492 ;xcut(a) 
     511;xcut(a) && !experimental_connections 
    493512 
    494513>if (!xplay_attack_either(b,c,d,b,d) || !xplay_attack_either(c,b,a,c,a)) 
    495514>  amalgamate(e,f); 
  • patterns/connections.c

    RCS file: /cvsroot/gnugo/gnugo/patterns/connections.c,v
    retrieving revision 1.44
    diff -u -r1.44 connections.c
     
    4040  int first_dragon  = NO_MOVE; 
    4141  int second_dragon = NO_MOVE; 
    4242 
     43  /* Strings of our color. */ 
     44  int o_strings[BOARDMAX]; 
     45  int o_nstrings = 0; 
     46 
    4347  int other = OTHER_COLOR(color); 
    4448  UNUSED(data); 
    4549 
    4650  move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor); 
    4751   
    48   if ((pattern->class & CLASS_B) && !safe_move(move, other)) 
     52  if ((pattern->class & CLASS_B) && !safe_move(move, other) 
     53      && !experimental_connections) 
     54    return; 
     55 
     56  if ((pattern->class & CLASS_Y) && !experimental_connections) 
    4957    return; 
    5058 
    51   if (pattern->class & CLASS_C) { 
     59  if ((pattern->class & CLASS_C) || experimental_connections) { 
    5260    /* If C pattern, test if there are more than one dragon in this 
    5361     * pattern so that there is something to connect, before doing any 
    5462     * expensive reading. 
     
    5765    for (k = 0; k < pattern->patlen; ++k) { /* match each point */ 
    5866      /* transform pattern real coordinate */ 
    5967      int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor); 
    60        
    61       /* Look for distinct dragons. */ 
     68 
    6269      if (pattern->patn[k].att == ATT_O) { 
    63         if (first_dragon == NO_MOVE) 
    64           first_dragon = dragon[pos].origin; 
    65         else if (second_dragon == NO_MOVE 
    66                  && dragon[pos].origin != first_dragon) { 
    67           second_dragon = dragon[pos].origin; 
    68           /* A second dragon found, no need to continue looping. */ 
    69           break; 
     70        if (!experimental_connections) { 
     71          /* Look for distinct dragons. */ 
     72          if (first_dragon == NO_MOVE) 
     73            first_dragon = dragon[pos].origin; 
     74          else if (second_dragon == NO_MOVE 
     75                   && dragon[pos].origin != first_dragon) { 
     76            second_dragon = dragon[pos].origin; 
     77            /* A second dragon found, no need to continue looping. */ 
     78            break; 
     79          } 
     80        } 
     81        else { 
     82          int origin = find_origin(pos); 
     83          int l; 
     84          for (l = 0; l < o_nstrings; l++) { 
     85            if (o_strings[l] == origin) 
     86              break; 
     87          } 
     88          if (l == o_nstrings) { 
     89            for (l = 0; l < o_nstrings; l++) 
     90              register_potential_worm_connection(o_strings[l], origin); 
     91            o_strings[l] = origin; 
     92            o_nstrings++; 
     93          } 
    7094        } 
    7195      } 
    7296    } 
    73     if (second_dragon == NO_MOVE) 
     97    if (!experimental_connections && second_dragon == NO_MOVE) 
    7498      return; /* Nothing to amalgamate. */ 
    7599  } 
    76100     
     
    144168     * can be attacked. 
    145169     */ 
    146170    if ((pattern->class & CLASS_C) 
     171        && !experimental_connections 
    147172        && board[pos] == color 
    148173        && pattern->patn[k].att == ATT_O 
    149174        && ((pattern->class & CLASS_s) || attack(pos, NULL) == 0)) { 
  • patterns/helpers.c

    RCS file: /cvsroot/gnugo/gnugo/patterns/helpers.c,v
    retrieving revision 1.72
    diff -u -r1.72 helpers.c
     
    428428void 
    429429amalgamate_most_valuable_helper(int apos, int bpos, int cpos) 
    430430{ 
     431  if (experimental_connections) 
     432    return; 
    431433  if (!is_same_dragon(apos, bpos) && !is_same_dragon(bpos, cpos)) { 
    432434    if (dragon[apos].effective_size >= dragon[cpos].effective_size) 
    433435      join_dragons(apos, bpos); 
  • patterns/owl_defendpats.db

    RCS file: /cvsroot/gnugo/gnugo/patterns/owl_defendpats.db,v
    retrieving revision 1.133
    diff -u -r1.133 owl_defendpats.db
     
    70747074;&& oplay_disconnect(*,a,b) != WIN 
    70757075 
    70767076 
     7077Pattern D1396 
     7078# gf New pattern. (3.7.5) 
     7079# See gifu03:404 
     7080 
     7081O...O 
     7082.*.O. 
     7083----- 
     7084 
     7085:8,b,value(80) 
     7086 
     7087B...A 
     7088.*.O. 
     7089----- 
     7090 
     7091;attack(A) && owl_strong_dragon(B) && !oplay_disconnect(*,A,B) 
     7092 
     7093 
    70777094######################################################### 
    70787095#                                                       # 
    70797096#                          Ko                           # 
  • patterns/patterns2.db

    RCS file: /cvsroot/gnugo/gnugo/patterns/patterns2.db,v
    retrieving revision 1.82
    diff -u -r1.82 patterns2.db
     
    852852;oplay_attack_either(*,a,B,a) && !oplay_attack(*,c) && !oplay_attack(*,d) 
    853853 
    854854 
     855Pattern Conn612 
     856 
     857O*O. 
     858XOXO 
     859 
     860:8,C 
     861 
     862 
    855863############################################## 
    856864# 
    857865# Connection of two space jump from two stones