Ticket #150: gunnar_7_12.3.diff

File gunnar_7_12.3.diff, 56.4 kB (added by gunnar, 9 months ago)

Monte Carlo patch ready for merge.

  • interface/main.c

     
    157157      OPT_MIRROR_LIMIT, 
    158158      OPT_METAMACHINE, 
    159159      OPT_RESIGN_ALLOWED, 
    160       OPT_NEVER_RESIGN 
     160      OPT_NEVER_RESIGN, 
     161      OPT_MONTE_CARLO, 
     162      OPT_MC_GAMES_PER_LEVEL 
    161163}; 
    162164 
    163165/* names of playing modes */ 
     
    305307  {"metamachine",    no_argument,       0, OPT_METAMACHINE}, 
    306308  {"resign-allowed", no_argument,       0, OPT_RESIGN_ALLOWED}, 
    307309  {"never-resign",   no_argument,       0, OPT_NEVER_RESIGN}, 
     310  {"monte-carlo",    no_argument,       0, OPT_MONTE_CARLO}, 
     311  {"mc-games-per-level", required_argument, 0, OPT_MC_GAMES_PER_LEVEL}, 
    308312  {NULL, 0, NULL, 0} 
    309313}; 
    310314 
     
    348352   */ 
    349353  int seed = 0; 
    350354  int seed_specified = 0; 
     355   
     356  int requested_boardsize = -1; 
    351357 
    352358  sgftree_clear(&sgftree); 
    353359  gameinfo_clear(&gameinfo); 
     
    508514        break; 
    509515       
    510516      case OPT_BOARDSIZE: 
    511         { 
    512           int boardsize = atoi(gg_optarg); 
    513  
    514           if (!check_boardsize(boardsize, stderr)) 
    515             exit(EXIT_FAILURE); 
    516            
    517           gnugo_clear_board(boardsize); 
    518           break; 
    519         } 
     517        requested_boardsize = atoi(gg_optarg); 
     518        break; 
    520519         
    521520      case OPT_KOMI:  
    522521        if (sscanf(gg_optarg, "%f", &komi) != 1) { 
     
    634633        resign_allowed = 0; 
    635634        break; 
    636635 
     636      case OPT_MONTE_CARLO: 
     637        use_monte_carlo_genmove = 1; 
     638        break; 
     639 
     640      case OPT_MC_GAMES_PER_LEVEL: 
     641        mc_games_per_level = atoi(gg_optarg); 
     642        break; 
     643 
    637644      case OPT_MODE:  
    638645        if (strcmp(gg_optarg, "ascii") == 0) 
    639646          playmode = MODE_ASCII; 
     
    963970      } 
    964971    } 
    965972 
     973  if (requested_boardsize != -1) { 
     974    if (!check_boardsize(requested_boardsize, stderr)) 
     975      exit(EXIT_FAILURE); 
     976    gnugo_clear_board(requested_boardsize); 
     977  } 
     978   
    966979  /* Start random number seed. */ 
    967980  if (!seed_specified) 
    968981    seed = time(0); 
  • engine/interface.c

     
    6666 */ 
    6767int check_boardsize(int boardsize, FILE *out) 
    6868{ 
    69   if (boardsize < MIN_BOARD || boardsize > MAX_BOARD) { 
     69  int max_board = MAX_BOARD; 
     70  if (use_monte_carlo_genmove && max_board > 9) 
     71    max_board = 9; 
     72   
     73  if (boardsize < MIN_BOARD || boardsize > max_board) { 
    7074    if (out) { 
    7175      fprintf(out, "Unsupported board size: %d. ", boardsize); 
    7276      if (boardsize < MIN_BOARD) 
    7377        fprintf(out, "Min size is %d.\n", MIN_BOARD); 
    74       else 
    75         fprintf(out, "Max size is %d.\n", MAX_BOARD); 
     78      else { 
     79        fprintf(out, "Max size is %d", max_board); 
     80        if (max_board < MAX_BOARD) 
     81          fprintf(out, " (%d without --monte-carlo)", MAX_BOARD); 
     82        fprintf(out, ".\n"); 
     83      } 
    7684      fprintf(out, "Try `gnugo --help' for more information.\n"); 
    7785    } 
    7886    return 0; 
  • engine/genmove.c

     
    300300  unconditional_move_reasons(color); 
    301301} 
    302302 
     303/* Call Monte Carlo module to generate a move. */ 
     304static int 
     305monte_carlo_genmove(int color, int allowed_moves[BOARDMAX], 
     306                    float *value, int *resign) 
     307{ 
     308  int pos; 
     309  int best_move = PASS_MOVE; 
     310  int best_uct_move = PASS_MOVE; 
     311  int unconditional_territory_black[BOARDMAX]; 
     312  int unconditional_territory_white[BOARDMAX]; 
     313  int forbidden_move[BOARDMAX]; 
     314  float move_values[BOARDMAX]; 
     315  int move_frequencies[BOARDMAX]; 
     316  float best_value; 
     317  int frequency_cutoff; 
     318  int frequency_cutoff2; 
     319  int number_of_simulations; 
     320 
     321  memset(move_values, 0, sizeof(move_values)); 
     322  memset(move_frequencies, 0, sizeof(move_frequencies)); 
     323   
     324  if (0) { 
     325    simple_showboard(stderr); 
     326    gprintf("\n"); 
     327  } 
     328 
     329  if (resign) 
     330    *resign = 0; 
     331   
     332  unconditional_life(unconditional_territory_black, BLACK); 
     333  unconditional_life(unconditional_territory_white, WHITE); 
     334 
     335  for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     336    if (!ON_BOARD(pos)) 
     337      continue; 
     338    else if (unconditional_territory_black[pos]) 
     339      forbidden_move[pos] = BLACK; 
     340    else if (unconditional_territory_white[pos]) 
     341      forbidden_move[pos] = WHITE; 
     342    else 
     343      forbidden_move[pos] = 0; 
     344 
     345  number_of_simulations = mc_games_per_level * gg_max(get_level(), 1); 
     346   
     347  uct_genmove(color, &best_uct_move, forbidden_move, allowed_moves, 
     348              number_of_simulations, move_values, move_frequencies); 
     349 
     350  best_move = best_uct_move; 
     351  best_value = 0.0; 
     352  frequency_cutoff = move_frequencies[best_uct_move] / 2; 
     353  frequency_cutoff2 = move_frequencies[best_uct_move] / 10; 
     354  for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     355    if (ON_BOARD(pos) 
     356        && (move_frequencies[pos] > frequency_cutoff 
     357            || (move_values[pos] > 0.9 
     358                && move_frequencies[pos] > frequency_cutoff2) 
     359            || move_values[best_uct_move] < 0.1) 
     360        && (!allowed_moves || allowed_moves[pos]) 
     361        && potential_moves[pos] > best_value) { 
     362      best_move = pos; 
     363      best_value = potential_moves[pos]; 
     364    } 
     365  } 
     366 
     367  unconditionally_meaningless_move(best_move, color, &best_move); 
     368 
     369  *value = 1.0; 
     370   
     371  return best_move; 
     372} 
     373 
     374 
    303375/*  
    304376 * Perform the actual move generation. 
    305377 * 
     
    477549                NO_MOVE, 1.0); 
    478550  } 
    479551 
     552  /* If Monte Carlo move generation is enabled, call it now. Do not 
     553   * override a fuseki move. 
     554   * 
     555   * FIXME: Identifying fuseki moves by checking the move value is 
     556   * very ugly and fragile. 
     557   */ 
     558  if (use_monte_carlo_genmove && move != PASS_MOVE 
     559      && (*value < 75.0 || *value > 75.01) && !doing_scoring) { 
     560    int allowed_moves2[BOARDMAX]; 
     561    int num_allowed_moves2 = 0; 
     562    int pos; 
     563    for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     564      if (ON_BOARD(pos) 
     565          && (!allowed_moves || allowed_moves[pos]) 
     566          && is_allowed_move(pos, color)) { 
     567        allowed_moves2[pos] = 1; 
     568        num_allowed_moves2++; 
     569      } 
     570      else 
     571        allowed_moves2[pos] = 0; 
     572     
     573    if (num_allowed_moves2 > 1) 
     574      move = monte_carlo_genmove(color, allowed_moves2, value, resign); 
     575  } 
     576   
    480577  /* If still no move, fill a remaining liberty. This should pick up 
    481578   * all missing dame points. 
    482579   */ 
  • engine/Makefile.in

     
    6363        endgame.$(OBJEXT) filllib.$(OBJEXT) fuseki.$(OBJEXT) \ 
    6464        genmove.$(OBJEXT) globals.$(OBJEXT) handicap.$(OBJEXT) \ 
    6565        hash.$(OBJEXT) influence.$(OBJEXT) interface.$(OBJEXT) \ 
    66         matchpat.$(OBJEXT) move_reasons.$(OBJEXT) movelist.$(OBJEXT) \ 
    67         optics.$(OBJEXT) oracle.$(OBJEXT) owl.$(OBJEXT) \ 
    68         persistent.$(OBJEXT) printutils.$(OBJEXT) \ 
     66        matchpat.$(OBJEXT) montecarlo.$(OBJEXT) move_reasons.$(OBJEXT) \ 
     67        movelist.$(OBJEXT) optics.$(OBJEXT) oracle.$(OBJEXT) \ 
     68        owl.$(OBJEXT) persistent.$(OBJEXT) printutils.$(OBJEXT) \ 
    6969        readconnect.$(OBJEXT) reading.$(OBJEXT) semeai.$(OBJEXT) \ 
    7070        sgfdecide.$(OBJEXT) sgffile.$(OBJEXT) shapes.$(OBJEXT) \ 
    7171        showbord.$(OBJEXT) surround.$(OBJEXT) unconditional.$(OBJEXT) \ 
  • engine/liberty.h

     
    496496                      int allowed_moves[BOARDMAX]); 
    497497enum dragon_status aftermath_final_status(int color, int pos); 
    498498 
     499void uct_genmove(int color, int *move, int *forbidden_moves, 
     500                 int *allowed_moves, int nodes, float *move_values, 
     501                 int *move_frequencies); 
     502 
    499503int owl_attack(int target, int *attack_point, int *certain, int *kworm); 
    500504int owl_defend(int target, int *defense_point, int *certain, int *kworm); 
    501505int owl_threaten_attack(int target, int *attack1, int *attack2); 
  • engine/gnugo.h

     
    219219extern int play_mirror_go;           /* try to play mirror go if possible */ 
    220220extern int mirror_stones_limit;      /* but stop at this number of stones */ 
    221221extern int gtp_version;              /* version of Go Text Protocol */ 
     222extern int use_monte_carlo_genmove;  /* use Monte Carlo move generation */ 
     223extern int mc_games_per_level;       /* number of Monte Carlo simulations per level */ 
    222224 
    223225/* Mandatory values of reading parameters. Normally -1, if set at  
    224226 * these override the values derived from the level. */ 
  • engine/montecarlo.c

     
     1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ 
     2 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see       * 
     3 * http://www.gnu.org/software/gnugo/ for more information.          * 
     4 *                                                                   * 
     5 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 and 2007 * 
     6 * by the Free Software Foundation.                                  * 
     7 *                                                                   * 
     8 * This program is free software; you can redistribute it and/or     * 
     9 * modify it under the terms of the GNU General Public License as    * 
     10 * published by the Free Software Foundation - version 3 or          * 
     11 * (at your option) any later version.                               * 
     12 *                                                                   * 
     13 * This program is distributed in the hope that it will be useful,   * 
     14 * but WITHOUT ANY WARRANTY; without even the implied warranty of    * 
     15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     * 
     16 * GNU General Public License in file COPYING for more details.      * 
     17 *                                                                   * 
     18 * You should have received a copy of the GNU General Public         * 
     19 * License along with this program; if not, write to the Free        * 
     20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       * 
     21 * Boston, MA 02111, USA.                                            * 
     22\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 
     23 
     24#include "gnugo.h" 
     25 
     26#include <stdio.h> 
     27#include <stdlib.h> 
     28#include <string.h> 
     29 
     30#include "liberty.h" 
     31#include "sgftree.h" 
     32#include "gg_utils.h" 
     33 
     34#include "random.h" 
     35#include <math.h> 
     36 
     37/* FIXME: Replace with a DEBUG_MC symbol for use with -d. */ 
     38static int mc_debug = 0; 
     39 
     40#define CACHE_CAPTURE_MOVES 1 
     41 
     42/* Special board code for Monte Carlo simulations. 
     43 * 
     44 * A liberty edge is the combination of the position of the liberty 
     45 * and the direction to a string given by the index into the delta[] 
     46 * array. A liberty edge at lib with corresponding string in direction 
     47 * delta[dir] is encoded as (lib << 2 | dir). 
     48 * 
     49 * The stones of a string are linked in a cyclic list through the 
     50 * next_stone field, just like the global board does. 
     51 * 
     52 * Likewise the liberty edges corresponding to each string are 
     53 * connected in a doubly linked cyclic list through the 
     54 * previous_liberty_edge and next_liberty_edge fields. 
     55 * 
     56 * The reference stone has to be the same for every stone in a string 
     57 * but it doesn't have to be a predictable one, in contrast to the 
     58 * origin in the global board. The reference stone is the only one 
     59 * which is guaranteed to have a valid pointer to the "first" liberty 
     60 * edge (just an arbitrary element in the circular list). 
     61 */ 
     62 
     63 
     64struct mc_board { 
     65  Intersection board[BOARDSIZE]; 
     66  int board_ko_pos; 
     67  int reference_stone[BOARDMAX]; 
     68  int next_stone[BOARDMAX]; 
     69  int first_liberty_edge[BOARDMAX]; 
     70  int previous_liberty_edge[4 * BOARDMAX]; 
     71  int next_liberty_edge[4 * BOARDMAX]; 
     72  Hash_data hash; 
     73}; 
     74 
     75#define MC_ON_BOARD(pos) (mc->board[pos] != GRAY) 
     76 
     77/* FIXME: In principle same a MAXCHAIN but we don't need to care about 
     78 * such high numbers. 
     79 */ 
     80#define MAX_NEIGHBORS 20 
     81 
     82/* Add a liberty edge for a string at pos with liberty at lib and 
     83 * direction dir. 
     84 */ 
     85static void 
     86mc_add_liberty_edge(struct mc_board *mc, int pos, int lib, int dir) 
     87{ 
     88  int this_liberty_edge = (lib << 2) | dir; 
     89  int reference = mc->reference_stone[pos]; 
     90  int first_liberty_edge = mc->first_liberty_edge[reference]; 
     91 
     92  gg_assert(lib + delta[dir] == pos); 
     93   
     94  if (first_liberty_edge) { 
     95    int second_liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     96    mc->previous_liberty_edge[this_liberty_edge] = first_liberty_edge; 
     97    mc->next_liberty_edge[this_liberty_edge] = second_liberty_edge; 
     98    mc->next_liberty_edge[first_liberty_edge] = this_liberty_edge; 
     99    mc->previous_liberty_edge[second_liberty_edge] = this_liberty_edge; 
     100  } 
     101  else { 
     102    mc->first_liberty_edge[reference] = this_liberty_edge; 
     103    mc->next_liberty_edge[this_liberty_edge] = this_liberty_edge; 
     104    mc->previous_liberty_edge[this_liberty_edge] = this_liberty_edge; 
     105  } 
     106} 
     107 
     108 
     109/* Remove a liberty edge for a string at pos with liberty at lib and 
     110 * direction dir. 
     111 */ 
     112static int 
     113mc_remove_liberty_edge(struct mc_board *mc, int pos, int lib, int dir) 
     114{ 
     115  int reference = mc->reference_stone[pos]; 
     116  int this_liberty_edge = (lib << 2) | dir; 
     117  int next = mc->next_liberty_edge[this_liberty_edge]; 
     118  int previous = mc->previous_liberty_edge[this_liberty_edge]; 
     119   
     120  gg_assert(lib + delta[dir] == pos); 
     121   
     122  if (next == this_liberty_edge) { 
     123    mc->first_liberty_edge[reference] = 0; 
     124    return 0; 
     125  } 
     126 
     127  mc->next_liberty_edge[previous] = next; 
     128  mc->previous_liberty_edge[next] = previous; 
     129  if (mc->first_liberty_edge[reference] == this_liberty_edge) 
     130    mc->first_liberty_edge[reference] = next; 
     131 
     132  return next; 
     133} 
     134 
     135 
     136/* Join the strings at str1 and str2. It is assumed that str1 is a 
     137 * newly placed stone (possibly already joined with other strings) and 
     138 * that the liberty edge corresponding to the liberty at the newly 
     139 * placed stone has not yet been removed. 
     140 */ 
     141static void 
     142mc_join_strings(struct mc_board *mc, int str1, int str2) 
     143{ 
     144  int reference = mc->reference_stone[str2]; 
     145  int liberty_edge2 = mc->first_liberty_edge[reference]; 
     146  int liberty_edge1 = mc->first_liberty_edge[mc->reference_stone[str1]]; 
     147  int next1; 
     148  int next2; 
     149  int pos = str1; 
     150 
     151  /* Update the reference stone for str1. */ 
     152  do { 
     153    mc->reference_stone[pos] = reference; 
     154    pos = mc->next_stone[pos]; 
     155  } while (pos != str1); 
     156 
     157  /* Switch next_stone pointers to join the strings. */ 
     158  next1 = mc->next_stone[str1]; 
     159  mc->next_stone[str1] = mc->next_stone[str2]; 
     160  mc->next_stone[str2] = next1; 
     161 
     162  /* Join the circular liberty_edge structures. We know that str2 
     163   * still has a liberty listed at the newly added stone so 
     164   * liberty_edge2 is guaranteed to be non-zero. 
     165   */ 
     166  if (liberty_edge1 != 0) { 
     167    next1 = mc->next_liberty_edge[liberty_edge1]; 
     168    next2 = mc->next_liberty_edge[liberty_edge2]; 
     169    mc->next_liberty_edge[liberty_edge1] = next2; 
     170    mc->next_liberty_edge[liberty_edge2] = next1; 
     171    mc->previous_liberty_edge[next1] = liberty_edge2; 
     172    mc->previous_liberty_edge[next2] = liberty_edge1; 
     173  } 
     174} 
     175 
     176 
     177/* Remove the string at str from the board. */ 
     178static int 
     179mc_remove_string(struct mc_board *mc, int str) 
     180{ 
     181  int color = mc->board[str]; 
     182  int other = OTHER_COLOR(color); 
     183  int pos = str; 
     184  int num_removed_stones = 0; 
     185  int k; 
     186   
     187  do { 
     188    for (k = 0; k < 4; k++) 
     189      if (mc->board[pos + delta[k]] == other) 
     190        mc_add_liberty_edge(mc, pos + delta[k], pos, k); 
     191    mc->board[pos] = EMPTY; 
     192    hashdata_invert_stone(&(mc->hash), pos, color); 
     193    num_removed_stones++; 
     194    pos = mc->next_stone[pos]; 
     195  } while (pos != str); 
     196 
     197  return num_removed_stones; 
     198} 
     199 
     200 
     201/* Initialize a Monte Carlo board struct from the global board. */ 
     202static void 
     203mc_init_board_from_global_board(struct mc_board *mc) 
     204{ 
     205  int stones[BOARDMAX]; 
     206  int num_stones; 
     207  int pos; 
     208  int k; 
     209  int r; 
     210   
     211  memcpy(mc->board, board, sizeof(mc->board)); 
     212  mc->board_ko_pos = board_ko_pos; 
     213  mc->hash = board_hash; 
     214 
     215  memset(mc->next_stone, 0, sizeof(mc->next_stone)); 
     216  for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     217    if (IS_STONE(board[pos]) && mc->next_stone[pos] == 0) { 
     218      num_stones = findstones(pos, BOARDMAX, stones); 
     219      mc->first_liberty_edge[pos] = 0; 
     220      for (r = 0; r < num_stones; r++) { 
     221        mc->next_stone[stones[r]] = stones[(r + 1) % num_stones]; 
     222        mc->reference_stone[stones[r]] = pos; 
     223        for (k = 0; k < 4; k++) { 
     224          if (board[stones[r] + delta[k]] == EMPTY) 
     225            mc_add_liberty_edge(mc, stones[r], stones[r] + delta[k], 
     226                                (k + 2) % 4); 
     227        } 
     228      } 
     229    } 
     230  } 
     231} 
     232 
     233 
     234#if 0 
     235/* Debug tool. */ 
     236static void 
     237mc_check_consistency_with_global_board(struct mc_board *mc) 
     238{ 
     239  int pos; 
     240 
     241  ASSERT1(board_ko_pos == mc->board_ko_pos, mc->board_ko_pos); 
     242  for (pos = 0; pos < BOARDSIZE; pos++) { 
     243    ASSERT1(board[pos] == mc->board[pos], pos); 
     244    if (IS_STONE(board[pos])) { 
     245      ASSERT1(same_string(pos, mc->reference_stone[pos]), pos); 
     246      if (find_origin(pos) == pos) { 
     247        int reference = mc->reference_stone[pos]; 
     248        int pos2 = pos; 
     249        int num_stones = 0; 
     250        int first_liberty_edge; 
     251        int liberty_edge; 
     252        int num_liberty_edges = 0; 
     253        int k; 
     254        int ml[4 * BOARDMAX]; 
     255        memset(ml, 0, sizeof(ml)); 
     256         
     257        do { 
     258          ASSERT1(mc->reference_stone[pos2] == reference, pos2); 
     259          ASSERT1(num_stones < countstones(pos), pos); 
     260          num_stones++; 
     261          for (k = 0; k < 4; k++) 
     262            if (board[pos2 + delta[k]] == EMPTY) { 
     263              ml[(pos2 + delta[k]) << 2 | (k + 2) % 4] = 1; 
     264              num_liberty_edges++; 
     265            } 
     266          pos2 = mc->next_stone[pos2]; 
     267        } while (pos2 != pos); 
     268        ASSERT1(num_stones == countstones(pos), pos); 
     269 
     270        first_liberty_edge = mc->first_liberty_edge[reference]; 
     271        liberty_edge = first_liberty_edge; 
     272        do { 
     273          int previous = mc->previous_liberty_edge[liberty_edge]; 
     274          int next = mc->next_liberty_edge[liberty_edge]; 
     275          ASSERT1(ml[liberty_edge] == 1, pos); 
     276          ml[liberty_edge] = 0; 
     277          num_liberty_edges--; 
     278          ASSERT1(mc->next_liberty_edge[previous] == liberty_edge, pos); 
     279          ASSERT1(mc->previous_liberty_edge[next] == liberty_edge, pos); 
     280          ASSERT1(liberty_of_string(liberty_edge >> 2, pos), pos); 
     281          liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     282        } while (liberty_edge != first_liberty_edge); 
     283        ASSERT1(num_liberty_edges == 0, pos); 
     284      } 
     285    } 
     286  } 
     287} 
     288#endif 
     289 
     290 
     291/* Write the Monte Carlo board to outfile. 
     292 */ 
     293static void 
     294mc_showboard(struct mc_board *mc, FILE *outfile) 
     295{ 
     296  int i, j; 
     297 
     298  draw_letter_coordinates(outfile); 
     299   
     300  for (i = 0; i < board_size; i++) { 
     301    fprintf(outfile, "\n%2d", board_size - i); 
     302     
     303    for (j = 0; j < board_size; j++) { 
     304      if (mc->board[POS(i, j)] == EMPTY) 
     305        fprintf(outfile, " %c", is_hoshi_point(i, j) ? '+' : '.'); 
     306      else 
     307        fprintf(outfile, " %c", mc->board[POS(i, j)] == BLACK ? 'X' : 'O'); 
     308    } 
     309  } 
     310   
     311  fprintf(outfile, "\n"); 
     312  draw_letter_coordinates(outfile); 
     313} 
     314 
     315 
     316/* Count the number of stones in the string at str. Stop counting if 
     317 * maxstones is reached. 
     318 */ 
     319static int 
     320mc_countstones(struct mc_board *mc, int str, int maxstones) 
     321{ 
     322  int stone = str; 
     323  int num_stones = 0; 
     324  do { 
     325    num_stones++; 
     326    stone = mc->next_stone[stone]; 
     327  } while (stone != str && num_stones < maxstones); 
     328 
     329  return num_stones; 
     330} 
     331 
     332/* Is a move at pos by color suicide? */ 
     333static int 
     334mc_is_suicide(struct mc_board *mc, int pos, int color) 
     335{ 
     336  int k; 
     337   
     338  if (mc->board[SOUTH(pos)] == EMPTY 
     339      || mc->board[WEST(pos)] == EMPTY 
     340      || mc->board[NORTH(pos)] == EMPTY 
     341      || mc->board[EAST(pos)] == EMPTY) 
     342    return 0; 
     343 
     344  for (k = 0; k < 4; k++) { 
     345    int first_liberty_edge; 
     346    int liberty_edge; 
     347    int additional_liberty = 0; 
     348    if (!ON_BOARD(pos + delta[k])) 
     349      continue; 
     350 
     351    first_liberty_edge = (pos << 2) | k; 
     352    liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     353    while (liberty_edge != first_liberty_edge) { 
     354      if ((liberty_edge >> 2) != pos) { 
     355        additional_liberty = 1; 
     356        break; 
     357      } 
     358      liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     359    } 
     360 
     361    if ((mc->board[pos + delta[k]] != color) ^ additional_liberty) 
     362      return 0; 
     363  } 
     364 
     365  return 1; 
     366} 
     367 
     368 
     369/* Is a move at pos by color legal? */ 
     370static int 
     371mc_is_legal(struct mc_board *mc, int pos, int color) 
     372{ 
     373  if (pos == PASS_MOVE) 
     374    return 1; 
     375 
     376  if (mc->board[pos] != EMPTY) 
     377    return 0; 
     378 
     379  if (pos == mc->board_ko_pos) { 
     380    if (mc->board[WEST(pos)] == OTHER_COLOR(color) 
     381        || mc->board[EAST(pos)] == OTHER_COLOR(color)) { 
     382      return 0; 
     383    } 
     384  } 
     385 
     386  return !mc_is_suicide(mc, pos, color); 
     387} 
     388 
     389 
     390/* Is the string at str in atari? Always place one liberty of the 
     391 * string in lib, unless it's a null pointer. 
     392 */ 
     393static int 
     394mc_is_in_atari(struct mc_board *mc, int str, int *lib) 
     395{ 
     396  int reference = mc->reference_stone[str]; 
     397  int first_liberty_edge = mc->first_liberty_edge[reference]; 
     398  int liberty = first_liberty_edge >> 2; 
     399  int liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     400  ASSERT1(IS_STONE(mc->board[str]), str); 
     401  if (lib) 
     402    *lib = liberty; 
     403  while (liberty_edge != first_liberty_edge) { 
     404    if ((liberty_edge >> 2) != liberty) 
     405      return 0; 
     406    liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     407  } 
     408 
     409  return 1; 
     410} 
     411 
     412 
     413/* Does the string at str have exactly two liberties? Place those in 
     414 * lib[0] and lib[1] unless lib is a NULL pointer.  
     415 */ 
     416static int 
     417mc_has_two_liberties(struct mc_board *mc, int str, int *lib) 
     418{ 
     419  int reference = mc->reference_stone[str]; 
     420  int first_liberty_edge = mc->first_liberty_edge[reference]; 
     421  int first_liberty = first_liberty_edge >> 2; 
     422  int liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     423  int second_liberty; 
     424  ASSERT1(IS_STONE(mc->board[str]), str); 
     425  if (lib) 
     426    lib[0] = first_liberty; 
     427  while (liberty_edge != first_liberty_edge) { 
     428    if ((liberty_edge >> 2) != first_liberty) { 
     429      second_liberty = liberty_edge >> 2; 
     430      if (lib) 
     431        lib[1] = second_liberty; 
     432      while (liberty_edge != first_liberty_edge) { 
     433        if ((liberty_edge >> 2) != first_liberty 
     434            && (liberty_edge >> 2) != second_liberty) 
     435          return 0; 
     436        liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     437      } 
     438      return 1; 
     439    } 
     440    liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     441  } 
     442 
     443  return 0; 
     444} 
     445 
     446 
     447/* Is a move at pos by color a self atari? */ 
     448static int 
     449mc_is_self_atari(struct mc_board *mc, int pos, int color) 
     450{ 
     451  int k; 
     452  int captured = NO_MOVE; 
     453  int liberty = NO_MOVE; 
     454  int reference; 
     455  int other; 
     456 
     457  /* Quick test which is often effective. */ 
     458  if (((mc->board[SOUTH(pos)] == EMPTY) 
     459       + (mc->board[WEST(pos)] == EMPTY) 
     460       + (mc->board[NORTH(pos)] == EMPTY) 
     461       + (mc->board[EAST(pos)] == EMPTY)) > 1) 
     462    return 0; 
     463 
     464  /* Otherwise look closer. */ 
     465  for (k = 0; k < 4; k++) { 
     466    int first_liberty_edge; 
     467    int liberty_edge; 
     468    int additional_liberty = 0; 
     469    int pos2 = pos + delta[k]; 
     470    if (mc->board[pos2] == EMPTY) { 
     471      if (pos2 != liberty) { 
     472        if (liberty != NO_MOVE) 
     473          return 0; 
     474        else 
     475          liberty = pos2; 
     476      } 
     477    } 
     478    else if (IS_STONE(mc->board[pos2])) { 
     479      first_liberty_edge = (pos << 2) | k; 
     480      liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     481      while (liberty_edge != first_liberty_edge) { 
     482        int lib = liberty_edge >> 2; 
     483        if (lib != pos) { 
     484          additional_liberty = 1; 
     485          if (mc->board[pos2] == color) { 
     486            if (lib != liberty) { 
     487              if (liberty != NO_MOVE) 
     488                return 0; 
     489              else 
     490                liberty = lib; 
     491            } 
     492          } 
     493          else 
     494            break; 
     495        } 
     496        liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     497      } 
     498 
     499      if (mc->board[pos2] != color && additional_liberty == 0) { 
     500        captured = pos2; 
     501        if (pos2 != liberty) { 
     502          if (liberty != NO_MOVE) 
     503            return 0; 
     504          else 
     505            liberty = pos2; 
     506        } 
     507      } 
     508    } 
     509  } 
     510 
     511  if (liberty == NO_MOVE || captured == NO_MOVE) 
     512    return 1; 
     513 
     514  /* Now only the difficult case remains where there was no adjacent 
     515   * empty stone, no adjacent friendly stone with an extra liberty, 
     516   * and exactly one neighbor was captured. Then the question is 
     517   * whether the capture produced a second liberty elsewhere. 
     518   */ 
     519  reference = mc->reference_stone[captured]; 
     520  other = OTHER_COLOR(color); 
     521  for (k = 0; k < 4; k++) { 
     522    if (mc->board[pos + delta[k]] == color) { 
     523      int stone = pos + delta[k]; 
     524      do { 
     525        int m; 
     526        for (m = 0; m < 4; m++) { 
     527          int pos2 = stone + delta[m]; 
     528          if (mc->board[pos2] == other 
     529              && pos2 != captured 
     530              && mc->reference_stone[pos2] == reference) 
     531            return 0; 
     532        } 
     533        stone = mc->next_stone[stone]; 
     534      } while (stone != pos + delta[k]); 
     535    } 
     536  } 
     537 
     538  return 1; 
     539} 
     540 
     541 
     542/* Does the string at str have one or more neighbors in atari? If so, 
     543 * return moves to capture a neighbor. 
     544 * FIXME: Does it pay off the keep a string mark array in the mc_board 
     545 *        struct? 
     546 */ 
     547static int