Ticket #150: MonteGNU.diff

File MonteGNU.diff, 50.6 kB (added by gunnar, 17 months ago)

Updated Monte Carlo board code and UCT implementation.

  • engine/genmove.c

     
    3030#include "sgftree.h" 
    3131#include "gg_utils.h" 
    3232 
     33 
     34static int 
     35monte_carlo_genmove(int color, int allowed_moves[BOARDMAX], 
     36                    float *value, int *resign) 
     37{ 
     38  int pos; 
     39  int best_move = PASS_MOVE; 
     40  int best_uct_move = PASS_MOVE; 
     41  int unconditional_territory_black[BOARDMAX]; 
     42  int unconditional_territory_white[BOARDMAX]; 
     43  int forbidden_move[BOARDMAX]; 
     44  float move_values[BOARDMAX]; 
     45  int move_frequencies[BOARDMAX]; 
     46 
     47  memset(move_values, 0, sizeof(move_values)); 
     48  memset(move_frequencies, 0, sizeof(move_frequencies)); 
     49   
     50  if (0) { 
     51    simple_showboard(stderr); 
     52    gprintf("\n"); 
     53  } 
     54 
     55  if (resign) 
     56    *resign = 0; 
     57   
     58  unconditional_life(unconditional_territory_black, BLACK); 
     59  unconditional_life(unconditional_territory_white, WHITE); 
     60 
     61  for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     62    if (!ON_BOARD(pos)) 
     63      continue; 
     64    else if (unconditional_territory_black[pos]) 
     65      forbidden_move[pos] = BLACK; 
     66    else if (unconditional_territory_white[pos]) 
     67      forbidden_move[pos] = WHITE; 
     68    else 
     69      forbidden_move[pos] = 0; 
     70 
     71  /* FIXME: Add configuration option. */ 
     72#if 1 
     73  uct_genmove(color, &best_uct_move, forbidden_move, allowed_moves, 
     74              10000 * (get_level() + 1), move_values, move_frequencies); 
     75#else 
     76  uct_genmove(color, &best_uct_move, forbidden_move, allowed_moves, 
     77              2000, move_values, move_frequencies); 
     78#endif 
     79  best_move = best_uct_move; 
     80#if 0 
     81  /* FIXME: Don't hardcode 0.75 and 0.4. */ 
     82  if (move_values[best_move] > 0.75) { 
     83    float best_value = 0.0; 
     84    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     85      if (ON_BOARD(pos) 
     86          && move_values[pos] > 0.75 
     87          && potential_moves[pos] > best_value) { 
     88        best_move = pos; 
     89        best_value = potential_moves[pos]; 
     90      } 
     91    } 
     92  } 
     93  else if (move_values[best_move] < 0.40) { 
     94    float best_value = 0.0; 
     95    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     96      if (ON_BOARD(pos) 
     97          && (!allowed_moves || allowed_moves[pos]) 
     98          && potential_moves[pos] > best_value) { 
     99        best_move = pos; 
     100        best_value = potential_moves[pos]; 
     101      } 
     102    } 
     103  } 
     104#elif 1 
     105  if (1) { 
     106    float best_value = 0.0; 
     107    int frequency_cutoff = move_frequencies[best_uct_move] / 2; 
     108    int frequency_cutoff2 = move_frequencies[best_uct_move] / 10; 
     109    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     110      if (ON_BOARD(pos) 
     111          && (move_frequencies[pos] > frequency_cutoff 
     112              || (move_values[pos] > 0.9 
     113                  && move_frequencies[pos] > frequency_cutoff2) 
     114              || move_values[best_uct_move] < 0.1) 
     115          && (!allowed_moves || allowed_moves[pos]) 
     116          && potential_moves[pos] > best_value) { 
     117        best_move = pos; 
     118        best_value = potential_moves[pos]; 
     119      } 
     120    } 
     121  } 
     122#else 
     123  if (1) { 
     124    float best_value = 0.0; 
     125    for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     126      if (ON_BOARD(pos) 
     127          && (!allowed_moves || allowed_moves[pos]) 
     128          && potential_moves[pos] + 10.0 * move_values[pos] > best_value) { 
     129        best_move = pos; 
     130        best_value = potential_moves[pos] + 10.0 * move_values[pos]; 
     131      } 
     132    } 
     133  } 
     134#endif 
     135 
     136  unconditionally_meaningless_move(best_move, color, &best_move); 
     137 
     138  *value = 1.0; 
     139   
     140  return best_move; 
     141} 
     142 
    33143/* Return one if x doesn't equal position_number and 0 otherwise. 
    34144 * After using this macro x will always have the value 
    35145 * position_number. 
     
    475585                NO_MOVE, 1.0); 
    476586  } 
    477587 
     588  if (move != PASS_MOVE && (*value < 75.0 || *value > 75.01) && !doing_scoring) { 
     589    int allowed_moves2[BOARDMAX]; 
     590    int num_allowed_moves2 = 0; 
     591    int pos; 
     592    for (pos = BOARDMIN; pos < BOARDMAX; pos++) 
     593      if (ON_BOARD(pos) 
     594          && (!allowed_moves || allowed_moves[pos]) 
     595#if 0 
     596          && potential_moves[pos] > (*value * 3 / 4) 
     597#endif 
     598          && is_allowed_move(pos, color)) { 
     599        allowed_moves2[pos] = 1; 
     600        num_allowed_moves2++; 
     601      } 
     602      else 
     603        allowed_moves2[pos] = 0; 
     604     
     605    if (num_allowed_moves2 > 1) 
     606      move = monte_carlo_genmove(color, allowed_moves2, value, resign); 
     607  } 
     608   
    478609  /* If still no move, fill a remaining liberty. This should pick up 
    479610   * all missing dame points. 
    480611   */ 
  • engine/liberty.h

     
    492492                      int allowed_moves[BOARDMAX]); 
    493493enum dragon_status aftermath_final_status(int color, int pos); 
    494494 
     495void uct_genmove(int color, int *move, int *forbidden_moves, 
     496                 int *allowed_moves, int nodes, float *move_values, 
     497                 int *move_frequencies); 
     498 
     499 
    495500int owl_attack(int target, int *attack_point, int *certain, int *kworm); 
    496501int owl_defend(int target, int *defense_point, int *certain, int *kworm); 
    497502int owl_threaten_attack(int target, int *attack1, int *attack2); 
  • 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,         * 
     6 * and 2007 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 2             * 
     11 *                                                                   * 
     12 * This program is distributed in the hope that it will be useful,   * 
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of    * 
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     * 
     15 * GNU General Public License in file COPYING for more details.      * 
     16 *                                                                   * 
     17 * You should have received a copy of the GNU General Public         * 
     18 * License along with this program; if not, write to the Free        * 
     19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       * 
     20 * Boston, MA 02111, USA.                                            * 
     21\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 
     22 
     23#include "gnugo.h" 
     24 
     25#include <stdio.h> 
     26#include <stdlib.h> 
     27#include <string.h> 
     28 
     29#include "liberty.h" 
     30#include "sgftree.h" 
     31#include "gg_utils.h" 
     32 
     33#include "random.h" 
     34#include <math.h> 
     35 
     36/* Special board code for Monte Carlo simulations. 
     37 * 
     38 * A liberty edge is the combination of the position of the liberty 
     39 * and the direction to a string given by the index into the delta[] 
     40 * array. A liberty edge at lib with corresponding string in direction 
     41 * delta[dir] is encoded as (lib << 2 | dir). 
     42 * 
     43 * The stones of a string are linked in a cyclic list through the 
     44 * next_stone field, just like the global board does. 
     45 * 
     46 * Likewise the liberty edges corresponding to each string are 
     47 * connected in a doubly linked cyclic list through the 
     48 * previous_liberty_edge and next_liberty_edge fields. 
     49 * 
     50 * The reference stone has to be the same for every stone in a string 
     51 * but it doesn't have to be a predictable one, in contrast to the 
     52 * origin in the global board. The reference stone is the only one 
     53 * which is guaranteed to have a valid pointer to the "first" liberty 
     54 * edge (just an arbitrary element in the circular list). 
     55 */ 
     56 
     57 
     58struct mc_board { 
     59  Intersection board[BOARDSIZE]; 
     60  int board_ko_pos; 
     61  int reference_stone[BOARDMAX]; 
     62  int next_stone[BOARDMAX]; 
     63  int first_liberty_edge[BOARDMAX]; 
     64  int previous_liberty_edge[4 * BOARDMAX]; 
     65  int next_liberty_edge[4 * BOARDMAX]; 
     66  Hash_data hash; 
     67}; 
     68 
     69#define MC_ON_BOARD(pos) (mc->board[pos] != GRAY) 
     70 
     71/* Add a liberty edge for a string at pos with liberty at lib and 
     72 * direction dir. 
     73 */ 
     74static void 
     75mc_add_liberty_edge(struct mc_board *mc, int pos, int lib, int dir) 
     76{ 
     77  int this_liberty_edge = (lib << 2) | dir; 
     78  int reference = mc->reference_stone[pos]; 
     79  int first_liberty_edge = mc->first_liberty_edge[reference]; 
     80 
     81  gg_assert(lib + delta[dir] == pos); 
     82   
     83  if (first_liberty_edge) { 
     84    int second_liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     85    mc->previous_liberty_edge[this_liberty_edge] = first_liberty_edge; 
     86    mc->next_liberty_edge[this_liberty_edge] = second_liberty_edge; 
     87    mc->next_liberty_edge[first_liberty_edge] = this_liberty_edge; 
     88    mc->previous_liberty_edge[second_liberty_edge] = this_liberty_edge; 
     89  } 
     90  else { 
     91    mc->first_liberty_edge[reference] = this_liberty_edge; 
     92    mc->next_liberty_edge[this_liberty_edge] = this_liberty_edge; 
     93    mc->previous_liberty_edge[this_liberty_edge] = this_liberty_edge; 
     94  } 
     95} 
     96 
     97 
     98/* Remove a liberty edge for a string at pos with liberty at lib and 
     99 * direction dir. 
     100 */ 
     101static int 
     102mc_remove_liberty_edge(struct mc_board *mc, int pos, int lib, int dir) 
     103{ 
     104  int reference = mc->reference_stone[pos]; 
     105  int this_liberty_edge = (lib << 2) | dir; 
     106  int next = mc->next_liberty_edge[this_liberty_edge]; 
     107  int previous = mc->previous_liberty_edge[this_liberty_edge]; 
     108   
     109  gg_assert(lib + delta[dir] == pos); 
     110   
     111  if (next == this_liberty_edge) { 
     112    mc->first_liberty_edge[reference] = 0; 
     113    return 0; 
     114  } 
     115 
     116  mc->next_liberty_edge[previous] = next; 
     117  mc->previous_liberty_edge[next] = previous; 
     118  if (mc->first_liberty_edge[reference] == this_liberty_edge) 
     119    mc->first_liberty_edge[reference] = next; 
     120 
     121  return next; 
     122} 
     123 
     124 
     125/* Join the strings at str1 and str2. It is assumed that str1 is a 
     126 * newly placed stone (possibly already joined with other strings) and 
     127 * that the liberty edge corresponding to the liberty at the newly 
     128 * placed stone has not yet been removed. 
     129 */ 
     130static void 
     131mc_join_strings(struct mc_board *mc, int str1, int str2) 
     132{ 
     133  int reference = mc->reference_stone[str2]; 
     134  int liberty_edge2 = mc->first_liberty_edge[reference]; 
     135  int liberty_edge1 = mc->first_liberty_edge[mc->reference_stone[str1]]; 
     136  int next1; 
     137  int next2; 
     138  int pos = str1; 
     139 
     140  /* Update the reference stone for str1. */ 
     141  do { 
     142    mc->reference_stone[pos] = reference; 
     143    pos = mc->next_stone[pos]; 
     144  } while (pos != str1); 
     145 
     146  /* Switch next_stone pointers to join the strings. */ 
     147  next1 = mc->next_stone[str1]; 
     148  mc->next_stone[str1] = mc->next_stone[str2]; 
     149  mc->next_stone[str2] = next1; 
     150 
     151  /* Join the circular liberty_edge structures. We know that str2 
     152   * still has a liberty listed at the newly added stone so 
     153   * liberty_edge2 is guaranteed to be non-zero. 
     154   */ 
     155  if (liberty_edge1 != 0) { 
     156    next1 = mc->next_liberty_edge[liberty_edge1]; 
     157    next2 = mc->next_liberty_edge[liberty_edge2]; 
     158    mc->next_liberty_edge[liberty_edge1] = next2; 
     159    mc->next_liberty_edge[liberty_edge2] = next1; 
     160    mc->previous_liberty_edge[next1] = liberty_edge2; 
     161    mc->previous_liberty_edge[next2] = liberty_edge1; 
     162  } 
     163} 
     164 
     165 
     166/* Remove the string at str from the board. */ 
     167static int 
     168mc_remove_string(struct mc_board *mc, int str) 
     169{ 
     170  int color = mc->board[str]; 
     171  int other = OTHER_COLOR(color); 
     172  int pos = str; 
     173  int num_removed_stones = 0; 
     174  int k; 
     175   
     176  do { 
     177    for (k = 0; k < 4; k++) 
     178      if (mc->board[pos + delta[k]] == other) 
     179        mc_add_liberty_edge(mc, pos + delta[k], pos, k); 
     180    mc->board[pos] = EMPTY; 
     181    hashdata_invert_stone(&(mc->hash), pos, color); 
     182    num_removed_stones++; 
     183    pos = mc->next_stone[pos]; 
     184  } while (pos != str); 
     185 
     186  return num_removed_stones; 
     187} 
     188 
     189 
     190/* Initialize a Monte Carlo board struct from the global board. */ 
     191static void 
     192mc_init_board_from_global_board(struct mc_board *mc) 
     193{ 
     194  int stones[BOARDMAX]; 
     195  int num_stones; 
     196  int pos; 
     197  int k; 
     198  int r; 
     199   
     200  memcpy(mc->board, board, sizeof(mc->board)); 
     201  mc->board_ko_pos = board_ko_pos; 
     202  mc->hash = board_hash; 
     203 
     204  memset(mc->next_stone, 0, sizeof(mc->next_stone)); 
     205  for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 
     206    if (IS_STONE(board[pos]) && mc->next_stone[pos] == 0) { 
     207      num_stones = findstones(pos, BOARDMAX, stones); 
     208      mc->first_liberty_edge[pos] = 0; 
     209      for (r = 0; r < num_stones; r++) { 
     210        mc->next_stone[stones[r]] = stones[(r + 1) % num_stones]; 
     211        mc->reference_stone[stones[r]] = pos; 
     212        for (k = 0; k < 4; k++) { 
     213          if (board[stones[r] + delta[k]] == EMPTY) 
     214            mc_add_liberty_edge(mc, stones[r], stones[r] + delta[k], 
     215                                (k + 2) % 4); 
     216        } 
     217      } 
     218    } 
     219  } 
     220} 
     221 
     222 
     223static void 
     224mc_check_consistency_with_global_board(struct mc_board *mc) 
     225{ 
     226  int pos; 
     227 
     228  ASSERT1(board_ko_pos == mc->board_ko_pos, mc->board_ko_pos); 
     229  for (pos = 0; pos < BOARDSIZE; pos++) { 
     230    ASSERT1(board[pos] == mc->board[pos], pos); 
     231    if (IS_STONE(board[pos])) { 
     232      ASSERT1(same_string(pos, mc->reference_stone[pos]), pos); 
     233      if (find_origin(pos) == pos) { 
     234        int reference = mc->reference_stone[pos]; 
     235        int pos2 = pos; 
     236        int num_stones = 0; 
     237        int first_liberty_edge; 
     238        int liberty_edge; 
     239        int num_liberty_edges = 0; 
     240        int k; 
     241        int ml[4 * BOARDMAX]; 
     242        memset(ml, 0, sizeof(ml)); 
     243         
     244        do { 
     245          ASSERT1(mc->reference_stone[pos2] == reference, pos2); 
     246          ASSERT1(num_stones < countstones(pos), pos); 
     247          num_stones++; 
     248          for (k = 0; k < 4; k++) 
     249            if (board[pos2 + delta[k]] == EMPTY) { 
     250              ml[(pos2 + delta[k]) << 2 | (k + 2) % 4] = 1; 
     251              num_liberty_edges++; 
     252            } 
     253          pos2 = mc->next_stone[pos2]; 
     254        } while (pos2 != pos); 
     255        ASSERT1(num_stones == countstones(pos), pos); 
     256 
     257        first_liberty_edge = mc->first_liberty_edge[reference]; 
     258        liberty_edge = first_liberty_edge; 
     259        do { 
     260          int previous = mc->previous_liberty_edge[liberty_edge]; 
     261          int next = mc->next_liberty_edge[liberty_edge]; 
     262          ASSERT1(ml[liberty_edge] == 1, pos); 
     263          ml[liberty_edge] = 0; 
     264          num_liberty_edges--; 
     265          ASSERT1(mc->next_liberty_edge[previous] == liberty_edge, pos); 
     266          ASSERT1(mc->previous_liberty_edge[next] == liberty_edge, pos); 
     267          ASSERT1(liberty_of_string(liberty_edge >> 2, pos), pos); 
     268          liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     269        } while (liberty_edge != first_liberty_edge); 
     270        ASSERT1(num_liberty_edges == 0, pos); 
     271      } 
     272    } 
     273  } 
     274} 
     275 
     276 
     277/* Write the Monte Carlo board to outfile. 
     278 */ 
     279static void 
     280mc_showboard(struct mc_board *mc, FILE *outfile) 
     281{ 
     282  int i, j; 
     283 
     284  draw_letter_coordinates(outfile); 
     285   
     286  for (i = 0; i < board_size; i++) { 
     287    fprintf(outfile, "\n%2d", board_size - i); 
     288     
     289    for (j = 0; j < board_size; j++) { 
     290      if (mc->board[POS(i, j)] == EMPTY) 
     291        fprintf(outfile, " %c", is_hoshi_point(i, j) ? '+' : '.'); 
     292      else 
     293        fprintf(outfile, " %c", mc->board[POS(i, j)] == BLACK ? 'X' : 'O'); 
     294    } 
     295  } 
     296   
     297  fprintf(outfile, "\n"); 
     298  draw_letter_coordinates(outfile); 
     299} 
     300 
     301 
     302/* Count the number of stones in the string at str. Stop counting if 
     303 * maxstones is reached. 
     304 */ 
     305static int 
     306mc_countstones(struct mc_board *mc, int str, int maxstones) 
     307{ 
     308  int stone = str; 
     309  int num_stones = 0; 
     310  do { 
     311    num_stones++; 
     312    stone = mc->next_stone[stone]; 
     313  } while (stone != str && num_stones < maxstones); 
     314 
     315  return num_stones; 
     316} 
     317 
     318/* Is a move at pos by color suicide? */ 
     319static int 
     320mc_is_suicide(struct mc_board *mc, int pos, int color) 
     321{ 
     322  int k; 
     323   
     324  if (mc->board[SOUTH(pos)] == EMPTY 
     325      || mc->board[WEST(pos)] == EMPTY 
     326      || mc->board[NORTH(pos)] == EMPTY 
     327      || mc->board[EAST(pos)] == EMPTY) 
     328    return 0; 
     329 
     330  for (k = 0; k < 4; k++) { 
     331    int first_liberty_edge; 
     332    int liberty_edge; 
     333    int additional_liberty = 0; 
     334    if (!ON_BOARD(pos + delta[k])) 
     335      continue; 
     336 
     337    first_liberty_edge = (pos << 2) | k; 
     338    liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     339    while (liberty_edge != first_liberty_edge) { 
     340      if ((liberty_edge >> 2) != pos) { 
     341        additional_liberty = 1; 
     342        break; 
     343      } 
     344      liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     345    } 
     346 
     347    if ((mc->board[pos + delta[k]] != color) ^ additional_liberty) 
     348      return 0; 
     349  } 
     350 
     351  return 1; 
     352} 
     353 
     354 
     355/* Is a move at pos by color legal? */ 
     356static int 
     357mc_is_legal(struct mc_board *mc, int pos, int color) 
     358{ 
     359  if (pos == PASS_MOVE) 
     360    return 1; 
     361 
     362  if (mc->board[pos] != EMPTY) 
     363    return 0; 
     364 
     365  if (pos == mc->board_ko_pos) { 
     366    if (mc->board[WEST(pos)] == OTHER_COLOR(color) 
     367        || mc->board[EAST(pos)] == OTHER_COLOR(color)) { 
     368      return 0; 
     369    } 
     370  } 
     371 
     372  return !mc_is_suicide(mc, pos, color); 
     373} 
     374 
     375 
     376/* Is the string at str in atari? Always place one liberty of the 
     377 * string in lib, unless it's a null pointer. 
     378 */ 
     379static int 
     380mc_is_in_atari(struct mc_board *mc, int str, int *lib) 
     381{ 
     382  int reference = mc->reference_stone[str]; 
     383  int first_liberty_edge = mc->first_liberty_edge[reference]; 
     384  int liberty = first_liberty_edge >> 2; 
     385  int liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     386  ASSERT1(IS_STONE(mc->board[str]), str); 
     387  if (lib) 
     388    *lib = liberty; 
     389  while (liberty_edge != first_liberty_edge) { 
     390    if ((liberty_edge >> 2) != liberty) 
     391      return 0; 
     392    liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     393  } 
     394 
     395  return 1; 
     396} 
     397 
     398 
     399/* Does the string at str have exactly two liberties? Place those in 
     400 * lib[0] and lib[1] unless lib is a NULL pointer.  
     401 */ 
     402static int 
     403mc_has_two_liberties(struct mc_board *mc, int str, int *lib) 
     404{ 
     405  int reference = mc->reference_stone[str]; 
     406  int first_liberty_edge = mc->first_liberty_edge[reference]; 
     407  int first_liberty = first_liberty_edge >> 2; 
     408  int liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     409  int second_liberty; 
     410  ASSERT1(IS_STONE(mc->board[str]), str); 
     411  if (lib) 
     412    lib[0] = first_liberty; 
     413  while (liberty_edge != first_liberty_edge) { 
     414    if ((liberty_edge >> 2) != first_liberty) { 
     415      second_liberty = liberty_edge >> 2; 
     416      if (lib) 
     417        lib[1] = second_liberty; 
     418      while (liberty_edge != first_liberty_edge) { 
     419        if ((liberty_edge >> 2) != first_liberty 
     420            && (liberty_edge >> 2) != second_liberty) 
     421          return 0; 
     422        liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     423      } 
     424      return 1; 
     425    } 
     426    liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     427  } 
     428 
     429  return 0; 
     430} 
     431 
     432 
     433/* Is a move at pos by color a self atari? */ 
     434static int 
     435mc_is_self_atari(struct mc_board *mc, int pos, int color) 
     436{ 
     437  int k; 
     438  int captured = NO_MOVE; 
     439  int liberty = NO_MOVE; 
     440  int reference; 
     441  int other; 
     442 
     443  /* Quick test which is often effective. */ 
     444  if (((mc->board[SOUTH(pos)] == EMPTY) 
     445       + (mc->board[WEST(pos)] == EMPTY) 
     446       + (mc->board[NORTH(pos)] == EMPTY) 
     447       + (mc->board[EAST(pos)] == EMPTY)) > 1) 
     448    return 0; 
     449 
     450  /* Otherwise look closer. */ 
     451  for (k = 0; k < 4; k++) { 
     452    int first_liberty_edge; 
     453    int liberty_edge; 
     454    int additional_liberty = 0; 
     455    int pos2 = pos + delta[k]; 
     456    if (mc->board[pos2] == EMPTY) { 
     457      if (pos2 != liberty) { 
     458        if (liberty != NO_MOVE) 
     459          return 0; 
     460        else 
     461          liberty = pos2; 
     462      } 
     463    } 
     464    else if (IS_STONE(mc->board[pos2])) { 
     465      first_liberty_edge = (pos << 2) | k; 
     466      liberty_edge = mc->next_liberty_edge[first_liberty_edge]; 
     467      while (liberty_edge != first_liberty_edge) { 
     468        int lib = liberty_edge >> 2; 
     469        if (lib != pos) { 
     470          additional_liberty = 1; 
     471          if (mc->board[pos2] == color) { 
     472            if (lib != liberty) { 
     473              if (liberty != NO_MOVE) 
     474                return 0; 
     475              else 
     476                liberty = lib; 
     477            } 
     478          } 
     479          else 
     480            break; 
     481        } 
     482        liberty_edge = mc->next_liberty_edge[liberty_edge]; 
     483      } 
     484 
     485      if (mc->board[pos2] != color && additional_liberty == 0) { 
     486        captured = pos2; 
     487        if (pos2 != liberty) { 
     488          if (liberty != NO_MOVE) 
     489            return 0; 
     490          else 
     491            liberty = pos2; 
     492        } 
     493      } 
     494    } 
     495  } 
     496 
     497  if (liberty == NO_MOVE || captured == NO_MOVE) 
     498    return 1; 
     499 
     500  /* Now only the difficult case remains where there was no adjacent 
     501   * empty stone, no adjacent friendly stone with an extra liberty, 
     502   * and exactly one neighbor was captured. Then the question is 
     503   * whether the capture produced a second liberty elsewhere. 
     504   */ 
     505  reference = mc->reference_stone[captured]; 
     506  other = OTHER_COLOR(color); 
     507  for (k = 0; k < 4; k++) { 
     508    if (board[pos + delta[k]] == color) { 
     509      int stone = pos + delta[k]; 
     510      do { 
     511        int m; 
     512        for (m = 0; m < 4; m++) { 
     513          int pos2 = stone + delta[m]; 
     514          if (board[pos2] == other 
     515              && pos2 != captured 
     516              && mc->reference_stone[pos2] == reference) 
     517            return 0; 
     518        } 
     519        stone = mc->next_stone[stone]; 
     520      } while (stone != pos + delta[k]); 
     521    } 
     522  } 
     523 
     524  return 1; 
     525} 
     526 
     527 
     528/* Does the string at str have a neighbor in atari? If so, return a 
     529 * move to capture a neighbor. Do not return a ko recapture. 
     530 * FIXME: Modify this to optionally return all such moves. 
     531 * FIXME: Does it pay off the keep a string mark array in the mc_board 
     532 *        struct? 
     533 */ 
     534static int 
     535mc_break_chain(struct mc_board *mc, int str, int *move) 
     536{ 
     537  unsigned char found_neighbors[BOARDMAX]; 
     538  int pos = str; 
     539  int other = OTHER_COLOR(mc->board[str]); 
     540  ASSERT1(IS_STONE(mc->board[str]), str); 
     541  memset(found_neighbors, 0, sizeof(found_neighbors)); 
     542  do { 
     543    int k; 
     544    for (k = 0; k < 4; k++) { 
     545      if (mc->board[pos + delta[k]] == other) { 
     546        int reference = mc->reference_stone[pos + delta[k]]; 
     547        if (!found_neighbors[reference]) { 
     548          found_neighbors[reference] = 1; 
     549          if (mc_is_in_atari(mc, pos + delta[k], move) 
     550              && *move != mc->board_ko_pos) 
     551            return 1; 
     552        } 
     553      } 
     554    } 
     555    pos = mc->next_stone[pos]; 
     556  } while (pos != str); 
     557 
     558  *move = NO_MOVE; 
     559  return 0; 
     560} 
     561 
     562 
     563/* Play the move at pos by color. */ 
     564static int 
     565mc_play_move(struct mc_board *mc, int pos, int color) 
     566{ 
     567  int k; 
     568  int captured_stones = 0; 
     569  int num_direct_liberties = 0; 
     570   
     571  if (pos == PASS_MOVE) { 
     572    if (mc->board_ko_pos != NO_MOVE) 
     573      hashdata_invert_ko(&mc->hash, mc->board_ko_pos); 
     574    mc->board_ko_pos = NO_MOVE; 
     575    return 1; 
     576  } 
     577   
     578  /* The move must not be the ko point. */ 
     579  if (pos == mc->board_ko_pos) { 
     580    if (mc->board[WEST(pos)] == OTHER_COLOR(color) 
     581        || mc->board[EAST(pos)] == OTHER_COLOR(color)) { 
     582      return 0; 
     583    } 
     584  } 
     585   
     586  /* Test for suicide. */ 
     587  if (mc_is_suicide(mc, pos, color)) 
     588    return 0; 
     589 
     590  if (mc->board_ko_pos != NO_MOVE) 
     591    hashdata_invert_ko(&mc->hash, mc->board_ko_pos); 
     592  mc->board_ko_pos = NO_MOVE; 
     593 
     594  ASSERT1(mc->board[pos] == EMPTY, pos); 
     595  mc->board[pos] = color; 
     596  hashdata_invert_stone(&mc->hash, pos, color); 
     597  mc->next_stone[pos] = pos; 
     598  mc->reference_stone[pos] = pos; 
     599  mc->first_liberty_edge[pos] = 0; 
     600 
     601  for (k = 0; k < 4; k++) { 
     602    int pos2 = pos + delta[k]; 
     603    if (mc->board[pos2] == EMPTY) { 
     604      mc_add_liberty_edge(mc, pos, pos2, (k + 2) % 4); 
     605      num_direct_liberties++; 
     606    } 
     607  } 
     608   
     609  for (k = 0; k < 4; k++) { 
     610    int pos2 = pos + delta[k]; 
     611    if (mc->board[pos2] == OTHER_COLOR(color)) { 
     612      if (mc_remove_liberty_edge(mc, pos2, pos, k) == 0) 
     613        captured_stones += mc_remove_string(mc, pos2); 
     614    } 
     615    else if (mc->board[pos2] == color) { 
     616      if (mc->reference_stone[pos] != mc->reference_stone[pos2]) 
     617        mc_join_strings(mc, pos, pos2); 
     618      mc_remove_liberty_edge(mc, pos2, pos, k); 
     619    } 
     620  } 
     621 
     622  if (captured_stones == 1 
     623      && mc->next_stone[pos] == pos 
     624      && num_direct_liberties == 0) { 
     625    mc->board_ko_pos = mc->first_liberty_edge[pos] >> 2; 
     626    hashdata_invert_ko(&mc->hash, mc->board_ko_pos); 
     627  } 
     628   
     629  return 1; 
     630} 
     631 
     632 
     633/***************************************************/ 
     634 
     635#define ASSERT_LEGAL 1 
     636 
     637struct mc_game { 
     638  struct mc_board mc; 
     639  unsigned char settled[BOARDMAX]; 
     640  int color_to_move; 
     641  int last_move; 
     642  int consecutive_passes; 
     643  int consecutive_ko_captures; 
     644  int depth; 
     645}; 
     646 
     647/* Generate a random move. */ 
     648static int 
     649mc_generate_random_move(struct mc_game *game, int *global_move_ordering, 
     650                        int num_ordered_moves, int only_reactive_moves) 
     651{ 
     652  struct mc_board *mc = &game->mc; 
     653  int last_move = game->last_move; 
     654  int color = game->color_to_move; 
     655  int depth = game->depth; 
     656   
     657  int moves[MAX_BOARD * MAX_BOARD]; 
     658  int num_moves = 0; 
     659  int pos; 
     660  int k; 
     661  int offset; 
     662  int move; 
     663  int liberties[2]; 
     664 
     665  /* If we get this deep we are almost certainly playing triple ko 
     666   * without alternative options, so just give up and score as is. 
     667   * 
     668   * FIXME: Handle this in some proper way. 
     669   */ 
     670  if (depth > 600) { 
     671    fprintf(stderr, "Reached 600 iterations.\n"); 
     672    mc_showboard(mc, stderr); 
     673    return PASS_MOVE; 
     674  } 
     675