Ticket #148: worm3.patch

File worm3.patch, 21.1 kB (added by draqo, 22 months ago)

some cleanups - most in worm.c

  • doc/utils.texi

    diff -N -r -u -X .ignore gnugo-copy/doc/utils.texi gnugo/doc/utils.texi
    old new  
    3535@item @code{int does_attack(int move, int str)} 
    3636@findex does_attack 
    3737@quotation 
    38 returns true if the move at @code{move} attacks @code{str}. This means that it captures 
    39 the string, and that @code{str} is not already dead.   
     38returns the result code for an attack on the string @code{'str'} by the move 
     39@code{'move'}. However, if the move does not improve the attack result compared 
     40to tenuki, 0 is returned. In particular if the string is already captured, 
     41@code{does_attack()} always returns 0. 
    4042@end quotation 
    4143@item @code{int does_defend(int move, int str)} 
    4244@findex does_defend 
    4345@quotation 
    44 @code{does_defend(move, str)} returns true if the move at @code{move} 
    45 defends @code{str}. This means that it defends the string, and that 
    46 @code{str} can be captured if no defense is made. 
     46returns the result code for a defense on the string @code{'str'} by the move 
     47@code{'move'}. However, if the move does not improve the defense result compared 
     48to tenuki, 0 is returned. If the string (str) can't be captured if no defense 
     49is made, 0 is returned too. 
    4750@end quotation 
    4851@item @code{int somewhere(int color, int last_move, ...)} 
    4952@findex somewhere 
     
    770773@item @code{int has_neighbor(int pos, int color)} 
    771774@findex has_neighbor 
    772775@quotation 
    773 Returns true if @code{pos} has a neighbor of @code{color}. 
     776Returns true if @code{pos} has a neighbor of color @code{color}. 
     777@end quotation 
     778@item @code{int find_neighbor(int pos, int color)} 
     779@findex find_neighbor 
     780@quotation 
     781If @code{pos} has exactly one neighbor of color @code{color} returns 
     782position of this neighbor. Otherwise returns -1. 
    774783@end quotation 
    775784@item @code{int same_string(int str1_pos, int str2_pos)} 
    776785@findex same_string 
  • engine/board.c

    diff -N -r -u -X .ignore gnugo-copy/engine/board.c gnugo/engine/board.c
    old new  
    374374const int deltai[8] = { 1,  0, -1,  0,  1, -1, -1, 1}; 
    375375const int deltaj[8] = { 0, -1,  0,  1, -1, -1,  1, 1}; 
    376376const int delta[8]  = { NS, -WE, -NS, WE, NS-WE, -NS-WE, -NS+WE, NS+WE}; 
     377const int *last_delta_4 = delta + 4; 
     378const int *last_delta_8 = delta + 8; 
    377379 
    378380 
    379381/* ================================================================ */ 
     
    15421544 * 5b) Unconditional ko capture is only allowed if it is nested ko capture. 
    15431545 *     Kom_pos is moved to the old value of board_ko_pos. 
    15441546 * 5c) Conditional ko capture is allowed according to the rules of 1b. 
     1547 * 
     1548 * For description what is "conditional ko" look in the documentation: 
     1549 * Tactical reading: Ko Handling 
    15451550 */ 
    15461551int 
    15471552komaster_trymove(int pos, int color, const char *message, int str, 
     
    19721977   * it is not optimized much. 
    19731978   */ 
    19741979  else { 
    1975     const int *cur_delta, *last_delta; 
     1980    const int *cur_delta; 
    19761981    int other = OTHER_COLOR(color); 
    19771982 
    1978     cur_delta = delta; 
    1979     last_delta = cur_delta + 4; 
    1980     for (; cur_delta < last_delta; cur_delta++) { 
     1983    for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { 
    19811984      int neighbor_pos = pos + *cur_delta; 
    19821985 
    19831986      if (LIBERTY(neighbor_pos) 
     
    22612264slow_approxlib(int pos, int color, int maxlib, int *libs, 
    22622265               struct board_cache_entry *entry) 
    22632266{ 
    2264   const int *delta_o, *delta_i, *last_delta = delta + 4; 
     2267  const int *delta_o, *delta_i; 
    22652268  int liberties = 0; 
    22662269  int checked_pos, checked_pos2; 
    22672270  int pos2, str_nr, first_stone; 
     
    22702273  MARK_LIBERTY(pos); 
    22712274  string_mark++; 
    22722275 
    2273   for (delta_o = delta; delta_o < last_delta; delta_o++) { 
     2276  for (delta_o = delta; delta_o < last_delta_4; delta_o++) { 
    22742277    checked_pos = pos + *delta_o; 
    22752278    if (board[checked_pos] == EMPTY) { 
    22762279      if (ml[checked_pos] != liberty_mark) { 
     
    22872290      first_stone = FIRST_STONE(str_nr); 
    22882291      pos2 = first_stone; 
    22892292      do { 
    2290         int l; 
    2291         for (delta_i = delta; delta_i < last_delta; delta_i++) { 
     2293        for (delta_i = delta; delta_i < last_delta_4; delta_i++) { 
    22922294          checked_pos2 = pos2 + *delta_i; 
    22932295          if (UNMARKED_LIBERTY(checked_pos2)) { 
    22942296            if (libs) 
     
    24162418do_accuratelib(int pos, int color, int maxlib, int *libs, 
    24172419               struct board_cache_entry *entry) 
    24182420{ 
    2419   const int *act_delta, *last_delta; 
     2421  const int *act_delta; 
    24202422  int *act_lib, *last_lib; 
    24212423  int lib_count = 0; 
    24222424  int captured[4]; 
     
    24302432  liberty_mark++; 
    24312433  MARK_LIBERTY(pos); 
    24322434 
    2433   act_delta = delta; 
    2434   last_delta = act_delta + 4; 
    2435   for (; act_delta < last_delta; act_delta++) { 
     2435  for (act_delta = delta; act_delta < last_delta_4; act_delta++) { 
    24362436    int checked_pos = pos + *act_delta; 
    24372437    if (board[checked_pos] == EMPTY) { 
    24382438      if (ml[checked_pos] != liberty_mark) { 
     
    38093809propagate_string(int stone_pos, int str_pos, int color) 
    38103810{ 
    38113811  int size = 1; 
    3812   const int *act_delta, *last_delta; 
     3812  const int *act_delta; 
    38133813   
    38143814  if (stone_pos == str_pos) { 
    38153815    /* Start a new string. */ 
     
    38233823  } 
    38243824 
    38253825  /* Look in all four directions for more stones to add. */ 
    3826   act_delta = delta; 
    3827   last_delta = act_delta + 4; 
    3828   for (; act_delta < last_delta; act_delta++) { 
     3826  for (act_delta = delta; act_delta < last_delta_4; act_delta++) { 
    38293827    int new_pos = stone_pos + *act_delta; 
    38303828    if (board[new_pos] == color 
    38313829        && string_number[new_pos] == -1) 
  • engine/board.h

    diff -N -r -u -X .ignore gnugo-copy/engine/board.h gnugo/engine/board.h
    old new  
    22 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see       * 
    33 * http://www.gnu.org/software/gnugo/ for more information.          * 
    44 *                                                                   * 
    5  * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 and 2006      * 
     5 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 and 2007 * 
    66 * by the Free Software Foundation.                                  * 
    77 *                                                                   * 
    88 * This program is free software; you can redistribute it and/or     * 
     
    393393extern const int deltai[8]; /* = { 1,  0, -1,  0,  1, -1, -1, 1}; */ 
    394394extern const int deltaj[8]; /* = { 0, -1,  0,  1, -1, -1,  1, 1}; */ 
    395395extern const int delta[8];  /* = { NS, -WE, -NS, WE, NS-WE, -NS-WE, -NS+WE, NS+WE}; */ 
     396extern const int *last_delta_4; 
     397extern const int *last_delta_8; 
    396398 
    397399 
    398400 
  • engine/liberty.h

    diff -N -r -u -X .ignore gnugo-copy/engine/liberty.h gnugo/engine/liberty.h
    old new  
    835835   * points with corresponding result codes. (0 = loss, 1 = bad ko, 2 
    836836   * = good ko, 3 = win). The arrays are guaranteed to be sorted with 
    837837   * respect to the codes so that the first element contains the best 
    838    * result. 
     838   * result. Checked and discarded moves are stored, too. 
    839839   */ 
    840840  int attack_points[MAX_TACTICAL_POINTS]; 
    841841  int attack_codes[MAX_TACTICAL_POINTS]; 
  • engine/unconditional.c

    diff -N -r -u -X .ignore gnugo-copy/engine/unconditional.c gnugo/engine/unconditional.c
    old new  
    4545  int moves_played = 0; 
    4646  int save_moves; 
    4747  int libs[MAXLIBS]; 
    48   int liberties; 
    4948  int pos; 
    5049  int *cur_lib, *last_lib; 
    5150   
     
    347346    int stones[2]; 
    348347    int pos2; 
    349348    int checked_stone; 
    350     const int *cur_delta, *last_delta; 
     349    const int *cur_delta; 
    351350     
    352351    if (board[pos] != color 
    353352        || find_origin(pos) != pos 
     
    357356    findstones(pos, 2, stones); 
    358357    for (k = 0; k < 2 && isolated; k++) { 
    359358      checked_stone = stones[k]; 
    360       cur_delta = delta; 
    361       last_delta = cur_delta + 8; 
    362       for (; cur_delta < last_delta; cur_delta++) { 
     359      for (cur_delta = delta; cur_delta < last_delta_8; cur_delta++) { 
    363360        pos2 = checked_stone + *cur_delta; 
    364361        if (!ON_BOARD(pos2) 
    365362            || (board[pos2] == color 
  • engine/worm.c

    diff -N -r -u -X .ignore gnugo-copy/engine/worm.c gnugo/engine/worm.c
    old new  
    7272 * the first element when they are given the lexicographical order, 
    7373 * though its location is irrelevant for applications. To see if two 
    7474 * stones lie in the same worm, compare their origins. 
    75  * 
    76  * We will use the field dragon[pos].genus to keep track of 
    77  * black- or white-bordered cavities (essentially eyes) which are found.   
    78  * so this field must be zero'd now. 
    7975 */ 
    8076 
    8177void 
     
    8379{ 
    8480  int pos; 
    8581  int str; 
    86   int dcode; 
     82  int acode, dcode; 
     83  int other; 
     84  const int *cur_delta; 
    8785 
    8886  /* Build the basic worm data:  color, origin, size, liberties. */ 
    8987  build_worms(); 
     
    104102   
    105103  gg_assert(stackp == 0); 
    106104 
    107   /* Count liberties of different orders. */ 
    108   for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
    109     int lib1; 
    110     if (IS_STONE(board[pos]) && is_worm_origin(pos, pos)) { 
    111       ping_cave(pos, &lib1, &worm[pos].liberties2, &worm[pos].liberties3, 
    112                 &worm[pos].liberties4); 
    113       ASSERT1(worm[pos].liberties == lib1, pos); 
    114       propagate_worm(pos); 
    115     } 
    116   } 
    117    
    118   gg_assert(stackp == 0); 
    119  
    120105  /* 
    121106   * There are two concepts of cutting stones in the worm array. 
    122107   * 
     
    164149   * 
    165150   * For the time being we use both concepts in parallel. It's 
    166151   * possible we also need the old concept for correct handling of lunches. 
     152   * 
     153   * We also set liberties and genus fields of worm_data in this loop. 
    167154   */ 
    168155 
    169   for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
    170     int w1 = NO_MOVE; 
    171     int w2 = NO_MOVE; 
    172     int k; 
    173     int pos2; 
     156  for (str = BOARDMIN; str < BOARDMAX; str++) { 
     157    int w1; 
     158    int w2; 
    174159     
    175160    /* Only work on each worm once. This is easiest done if we only  
    176161     * work with the origin of each worm. 
    177162     */ 
    178     if (!IS_STONE(board[pos]) || !is_worm_origin(pos, pos)) 
     163    if (!IS_STONE(board[str]) || !is_worm_origin(str, str)) 
    179164      continue; 
     165 
     166    /* Count liberties of different orders. */ 
     167    ping_cave(str, &worm[str].liberties, &worm[str].liberties2, 
     168              &worm[str].liberties3, &worm[str].liberties4); 
     169    ASSERT1(worm[str].liberties == countlib(str), str); 
     170 
     171    /* Set the genus of all worms. */ 
     172    worm[str].genus = genus(str); 
     173 
     174    w1 = 0; 
     175    w2 = 0; 
     176    other = OTHER_COLOR(board[str]); 
    180177     
    181178    /* Try to find two adjacent worms (w1) and (w2)  
    182      * of opposite colour from (pos). 
     179     * of opposite color from (str). 
    183180     */ 
    184     for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) { 
    185       /* Work only with the opposite color from (pos). */ 
    186       if (board[pos2] != OTHER_COLOR(board[pos]))  
     181    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     182      /* Work only with the opposite color from (str). */ 
     183      if (board[pos] != other)  
    187184        continue; 
    188185       
    189       for (k = 0; k < 4; k++) { 
    190         if (!IS_STONE(board[pos2 + delta[k]]) 
    191             || worm[pos2 + delta[k]].origin != pos) 
     186      for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { 
     187        if (!IS_STONE(board[pos + *cur_delta]) 
     188            || worm[pos + *cur_delta].origin != str) 
    192189          continue; 
    193190         
    194         ASSERT1(board[pos2 + delta[k]] == board[pos], pos); 
     191        ASSERT1(board[pos + *cur_delta] == board[str], str); 
    195192         
    196193        /* If we have not already found a worm which meets the criteria, 
    197194         * store it into (w1), otherwise store it into (w2). 
    198195         */ 
    199         if (w1 == NO_MOVE) 
    200           w1 = worm[pos2].origin; 
    201         else if (!is_same_worm(pos2, w1)) 
    202           w2 = worm[pos2].origin; 
     196        if (!w1) 
     197          w1 = pos; 
     198        else if (!is_same_worm(pos, w1)) { 
     199          w2 = pos; 
     200          break; 
     201        } 
    203202      } 
    204203    } 
    205204     
     
    211210     */ 
    212211     
    213212    /* Only do this if we really found something. */ 
    214     if (w2 != NO_MOVE) { 
    215       worm[pos].cutstone = 2; 
    216       if (count_common_libs(w1, w2) > 0) 
    217         worm[pos].cutstone = 1; 
     213    if (w2) { 
     214      if (have_common_lib(w1, w2, NULL)) 
     215        worm[str].cutstone = 1; 
     216      else 
     217        worm[str].cutstone = 2; 
    218218       
    219219      DEBUG(DEBUG_WORMS, "Worm at %1m has w1 %1m and w2 %1m, cutstone %d\n", 
    220             pos, w1, w2, worm[pos].cutstone); 
     220            str, worm[w1].origin, worm[w2].origin, worm[str].cutstone); 
    221221    } 
     222 
     223    propagate_worm(str); 
    222224  } 
    223225   
    224226  gg_assert(stackp == 0); 
    225227   
    226   /* Set the genus of all worms. */ 
    227   for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
    228     if (IS_STONE(board[pos]) && is_worm_origin(pos, pos)) { 
    229       worm[pos].genus = genus(pos); 
    230       propagate_worm(pos); 
    231     } 
    232   } 
    233   gg_assert(stackp == 0); 
    234  
    235228  /* Now we try to improve the values of worm.attack and worm.defend. 
    236229   * If we find that capturing the string at str also defends the 
    237230   * string at str2, or attacks it, then we add points of attack and 
     
    240233   */ 
    241234  { 
    242235    int color; 
     236    int attack_works, defense_works; 
     237    int worm_acode, worm_dcode; 
    243238    int moves_to_try[BOARDMAX]; 
    244239    memset(moves_to_try, 0, sizeof(moves_to_try)); 
    245240 
     
    252247      } 
    253248    } 
    254249 
     250    increase_depth_values(); 
     251 
    255252    /* Loop over the board and over the colors and try the moves found 
    256      * in the previous loop. 
     253     * in the previous loop. We must read to the same depth that was 
     254     * used in the initial determination of worm.attack and worm.defend 
     255     * to avoid horizon effects - that's why we must also increment 
     256     * depth values. 
    257257     */ 
    258258    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
    259259      if (!ON_BOARD(pos)) 
     
    267267        if (!trymove(pos, color, "make_worms", NO_MOVE)) 
    268268          continue; 
    269269           
    270         /* We must read to the same depth that was used in the 
    271          * initial determination of worm.attack and worm.defend 
    272          * to avoid horizon effects. Since stackp has been 
    273          * incremented we must also increment depth values. 
    274          */ 
    275          
    276270        DEBUG(DEBUG_WORMS, "trying %1m\n", pos); 
    277         increase_depth_values(); 
     271 
     272        other = OTHER_COLOR(color); 
    278273         
    279274        /* Now we try to find a group which is saved or attacked as well 
    280275         * by this move. 
     
    283278          if (!IS_STONE(board[str]) 
    284279              || find_origin(str) != str) 
    285280            continue; 
     281 
     282          worm_acode = worm[str].attack_codes[0]; 
    286283           
    287284          /* If the worm is of the opposite color to the move, 
    288285           * then we try to defend it. If there was a previous  
    289286           * attack and defense of it, and there is no defense 
    290287           * for the attack now... 
    291288           */ 
    292           if (worm[str].color == OTHER_COLOR(color) 
    293               && worm[str].attack_codes[0] != 0 
    294               && worm[str].attack_points[0] != pos 
    295               && worm[str].defense_codes[0] != 0) { 
     289          if (worm[str].color == other 
     290              && worm_acode && worm[str].attack_points[0] != pos 
     291              && (worm_dcode = worm[str].defense_codes[0])) { 
    296292            dcode = find_defense(str, NULL); 
    297             if (dcode < worm[str].defense_codes[0]) { 
    298               int attack_works = 1; 
     293            if (dcode < worm_dcode) { 
     294              attack_works = 1; 
    299295 
    300296              /* Sometimes find_defense() fails to find a 
    301297               * defense which has been found by other means. 
     
    305301               * because we could, for instance, drive the worm into 
    306302               * seki with our move. 
    307303               */ 
    308               if (attack(str, NULL) >= worm[str].attack_codes[0]) { 
    309                 if (worm[str].defense_codes[0] != 0 
    310                     && trymove(worm[str].defense_points[0], 
    311                                OTHER_COLOR(color), "make_worms", 0)) { 
     304              if (attack(str, NULL) >= worm_acode) { 
     305                if (trymove(worm[str].defense_points[0], other, 
     306                            "make_worms", 0)) { 
    312307                  int this_dcode = REVERSE_RESULT(attack(str, NULL)); 
    313308                  if (this_dcode > dcode) { 
    314                     dcode = this_dcode; 
    315                     if (dcode >= worm[str].defense_codes[0]) 
     309                    if (this_dcode >= worm_dcode) 
    316310                      attack_works = 0; 
     311                    else 
     312                      dcode = this_dcode; 
    317313                  } 
    318314                  popgo(); 
    319315                } 
     
    336332           * there is none now, then add a defense point of str at 
    337333           * pos. 
    338334           */ 
    339           else if (worm[str].color == color 
    340                    && worm[str].attack_codes[0] != 0 
     335          else if (worm[str].color == color && worm_acode 
    341336                   && worm[str].defense_points[0] != pos) { 
    342             int acode = attack(str, NULL); 
    343             if (acode < worm[str].attack_codes[0]) { 
    344               int defense_works = 1; 
     337            acode = attack(str, NULL); 
     338            if (acode < worm_acode) { 
     339              defense_works = 1; 
    345340              /* Sometimes attack() fails to find an 
    346341               * attack which has been found by other means. 
    347342               * Try if the old attack move still works. 
    348343               */ 
    349               if (worm[str].attack_codes[0] != 0 
    350                   && trymove(worm[str].attack_points[0], 
    351                              OTHER_COLOR(color), "make_worms", 0)) { 
    352                 int this_acode; 
    353                 if (board[str] == EMPTY) 
    354                   this_acode = WIN; 
    355                 else 
    356                   this_acode = REVERSE_RESULT(find_defense(str, NULL)); 
    357                 if (this_acode > acode) { 
    358                   acode = this_acode; 
    359                   if (acode >= worm[str].attack_codes[0]) 
    360                     defense_works = 0; 
     344              if (trymove(worm[str].attack_points[0], other, 
     345                          "make_worms", 0)) { 
     346                if (!board[str]) 
     347                  defense_works = 0; 
     348                else { 
     349                  int this_acode = REVERSE_RESULT(find_defense(str, NULL)); 
     350                  if (this_acode > acode) { 
     351                    if (this_acode >= worm_acode) 
     352                      defense_works = 0; 
     353                    else 
     354                      acode = this_acode; 
     355                  } 
    361356                } 
    362357                popgo(); 
    363358              } 
     
    372367            } 
    373368          } 
    374369        } 
    375         decrease_depth_values(); 
    376370        popgo(); 
    377371      } 
    378372    } 
     373    decrease_depth_values(); 
    379374  } 
    380375   
    381376  gg_assert(stackp == 0); 
     
    428423   
    429424  gg_assert(stackp == 0); 
    430425   
    431   /* Find adjacent worms that can be easily captured, aka lunches. */ 
    432  
    433   for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
    434     int lunch; 
    435      
    436     if (!IS_STONE(board[pos]) || !is_worm_origin(pos, pos)) 
    437       continue; 
    438      
    439     if (find_lunch(pos, &lunch) 
    440         && (worm[lunch].attack_codes[0] == WIN 
    441             || worm[lunch].attack_codes[0] == KO_A)) { 
    442       DEBUG(DEBUG_WORMS, "lunch found for %1m at %1m\n", pos, lunch); 
    443       worm[pos].lunch = lunch; 
    444     } 
    445     else 
    446       worm[pos].lunch = NO_MOVE; 
    447      
    448     propagate_worm(pos); 
    449   } 
    450    
    451426  if (!disable_threat_computation) 
    452427    find_worm_threats(); 
    453428 
     
    457432   * potential unless part of their surrounding chain can be captured. 
    458433   * We give a conservative definition of inessential: 
    459434   *  - the genus must be zero  
    460    *  - there can no second order liberties 
    461    *  - there can be no more than two edge liberties 
     435   *  - there can be no second order liberties 
     436   *  - it can't be a cutstone 
    462437   *  - if it is removed from the board, the remaining cavity has 
    463438   *    border color the opposite color of the string  
    464439   *  - it contains at most two edge vertices. 
     
    472447   * 
    473448   * An inessential string can be thought of as residing inside the 
    474449   * opponent's eye space. 
     450   * 
     451   * We also find lunches here. 
    475452   */ 
    476453 
    477454  gg_assert(stackp == 0); 
    478455 
    479456  for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     457    int edge; 
     458    int lunch; 
     459 
    480460    if (IS_STONE(board[pos]) 
    481         && worm[pos].origin == pos 
    482         && worm[pos].genus == 0 
    483         && worm[pos].liberties2 == 0 
    484         && !worm[pos].cutstone 
    485         && worm[pos].lunch == NO_MOVE) { 
    486       int edge; 
    487       int border_color = examine_cavity(pos, &edge); 
    488       if (border_color != GRAY && edge < 3) { 
    489         DEBUG(DEBUG_WORMS, "Worm %1m identified as inessential.\n", pos); 
    490         worm[pos].inessential = 1; 
     461        && worm[pos].origin == pos) { 
     462 
     463      /* Find adjacent worms that can be easily captured, aka lunches. */ 
     464      if (find_lunch(pos, &lunch) 
     465          && ((acode = worm[lunch].attack_codes[0]) == WIN 
     466              || acode == KO_A)) { 
     467        DEBUG(DEBUG_WORMS, "lunch found for %1m at %1m\n", pos, lunch); 
     468        worm[pos].lunch = lunch; 
    491469        propagate_worm(pos); 
    492470      } 
     471      else { 
     472        /* Identify INESSENTIAL strings. */ 
     473        if (!worm[pos].genus 
     474            && !worm[pos].liberties2 
     475            && !worm[pos].cutstone) { 
     476          if (examine_cavity(pos, &edge) != GRAY && edge < 3) { 
     477            DEBUG(DEBUG_WORMS, "Worm %1m identified as inessential.\n", pos); 
     478            worm[pos].inessential = 1; 
     479            propagate_worm(pos); 
     480          } 
     481        } 
     482      } 
    493483    } 
    494484  } 
    495485} 
     
    746736    TRACE("considering attack of %1m\n", str); 
    747737     
    748738    acode = attack(str, &attack_point); 
    749     if (acode != 0) { 
     739    if (acode) { 
    750740      DEBUG(DEBUG_WORMS, "worm at %1m can be attacked at %1m\n", 
    751741            str, attack_point); 
    752742      change_attack(str, attack_point, acode); 
     
    16011591  cur_el = pattern->patn; 
    16021592  last_el = cur_el + pattern->patlen; 
    16031593  for (; cur_el < last_el; ++cur_el) { /* match each point */ 
     1594    int pos; 
     1595    int str; 
    16041596    if (cur_el->att == ATT_X) { 
    16051597      /* transform pattern real coordinate */ 
    1606       int pos = AFFINE_TRANSFORM(cur_el->offset, ll, anchor); 
     1598      pos = AFFINE_TRANSFORM(cur_el->offset, ll, anchor); 
    16071599 
    1608       int str = worm[pos].origin; 
     1600      str = worm[pos].origin; 
    16091601 
    16101602      /* A string with 5 liberties or more is considered tactically alive. */ 
    16111603      if (countlib(str) > 4) 
     
    16991691  cur_el = pattern->patn; 
    17001692  last_el = cur_el + pattern->patlen; 
    17011693  for (; cur_el < last_el; ++cur_el) { /* match each point */ 
     1694    int pos; 
     1695    int str; 
    17021696    if (cur_el->att == ATT_O) { 
    17031697      /* transform pattern real coordinate */ 
    1704       int pos = AFFINE_TRANSFORM(cur_el->offset, ll, anchor); 
    1705       int str = worm[pos].origin; 
     1698      pos = AFFINE_TRANSFORM(cur_el->offset, ll, anchor); 
     1699      str = worm[pos].origin; 
    17061700 
    1707       if (worm[str].attack_codes[0] == 0 
     1701      if (!worm[str].attack_codes[0] 
    17081702          || defense_move_known(move, str) 
    17091703          || discarded_move_known(move, MAX_TACTICAL_POINTS, 
    17101704                                  worm[str].discarded_defenses))