/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see       *
 * http://www.gnu.org/software/gnugo/ for more information.          *
 *                                                                   *
 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,   *
 * 2008 and 2009 by the Free Software Foundation.                    *
 *                                                                   *
 * This program is free software; you can redistribute it and/or     *
 * modify it under the terms of the GNU General Public License as    *
 * published by the Free Software Foundation - version 3 or          *
 * (at your option) any later version.                               *
 *                                                                   *
 * This program is distributed in the hope that it will be useful,   *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *
 * GNU General Public License in file COPYING for more details.      *
 *                                                                   *
 * You should have received a copy of the GNU General Public         *
 * License along with this program; if not, write to the Free        *
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       *
 * Boston, MA 02111, USA.                                            *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "gnugo.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "liberty.h"
#include "eyes.h"
#include "gg_utils.h"

#define MAXEYE 20


/* This structure is used in communication between read_eye() and
 * recognize_eye().
 */
struct vital_points {
  int attacks[4 * MAXEYE];
  int defenses[4 * MAXEYE];
  int num_attacks;
  int num_defenses;
};


static void
compute_primary_domains(int color, int domain[BOARDMAX],
			int lively[BOARDMAX],
			int false_margins[BOARDMAX],
			int first_time);
static void count_neighbours(struct eye_data eyedata[BOARDMAX]);
static int is_lively(int owl_call, int pos);
static int false_margin(int pos, int color, int lively[BOARDMAX]);
static void originate_eye(int origin, int pos,
			  int *esize, int *msize,
			  struct eye_data eye[BOARDMAX]);
static int read_eye(int pos, int *attack_point, int *defense_point,
		    struct eyevalue *value,
		    struct eye_data eye[BOARDMAX],
		    struct half_eye_data heye[BOARDMAX],
		    int add_moves);
static int recognize_eye(int pos, int *attack_point, int *defense_point,
			 struct eyevalue *value,
			 struct eye_data eye[BOARDMAX],
			 struct half_eye_data heye[BOARDMAX],
			 struct vital_points *vp);
static void guess_eye_space(int pos, int effective_eyesize, int margins,
			    int bulk_score, struct eye_data eye[BOARDMAX],
			    struct eyevalue *value, int *pessimistic_min);
static void reset_map(int size);
static void first_map(int *map_value);
static int next_map(int *q, int map[MAXEYE]);
static void print_eye(struct eye_data eye[BOARDMAX],
		      struct half_eye_data heye[BOARDMAX], int pos);
static void add_false_eye(int pos, struct eye_data eye[BOARDMAX], 
			  struct half_eye_data heye[BOARDMAX]);
static float topological_eye(int pos, int color,
			     struct eye_data my_eye[BOARDMAX],
			     struct half_eye_data heye[BOARDMAX]);
static float evaluate_diagonal_intersection(int m, int n, int color,
					    int *attack_point,
					    int *defense_point,
					    struct eye_data my_eye[BOARDMAX]);


/* These are used during the calculations of eye spaces. */
static int black_domain[BOARDMAX];
static int white_domain[BOARDMAX];

/* Used internally by mapping functions. */
static int map_size;
static signed char used_index[MAXEYE];


/*
 * make_domains() is called from make_dragons() and from
 * owl_determine_life(). It marks the black and white domains
 * (eyeshape regions) and collects some statistics about each one.
 */

void
make_domains(struct eye_data b_eye[BOARDMAX],
	     struct eye_data w_eye[BOARDMAX],
	     int owl_call)
{
  int k;
  int pos;
  int lively[BOARDMAX];
  int false_margins[BOARDMAX];
  
  memset(black_domain, 0, sizeof(black_domain));
  memset(white_domain, 0, sizeof(white_domain));
  memset(false_margins, 0, sizeof(false_margins));

  if (b_eye)
    memset(b_eye, 0, BOARDMAX * sizeof(b_eye[0]));
  if (w_eye)
    memset(w_eye, 0, BOARDMAX * sizeof(w_eye[0]));

  /* Initialize eye data and compute the lively array. */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (ON_BOARD(pos))
      lively[pos] = is_lively(owl_call, pos);

  /* Compute the domains of influence of each color. */
  compute_primary_domains(BLACK, black_domain, lively, false_margins, 1);
  compute_primary_domains(WHITE, white_domain, lively, false_margins, 0);

  /* Now we fill out the arrays b_eye and w_eye with data describing
   * each eye shape.
   */

  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (!ON_BOARD(pos))
      continue;
    
    if (board[pos] == EMPTY || !lively[pos]) {
      if (black_domain[pos] == 0 && white_domain[pos] == 0) {
	if (w_eye)
	  w_eye[pos].color = GRAY;
	if (b_eye)
	  b_eye[pos].color = GRAY;
      }
      else if (black_domain[pos] == 1 && white_domain[pos] == 0 && b_eye) {
	b_eye[pos].color = BLACK;
	for (k = 0; k < 4; k++) {
	  int apos = pos + delta[k];
	  if (ON_BOARD(apos) && white_domain[apos] && !black_domain[apos]) {
	    b_eye[pos].marginal = 1;
	    break;
	  }
	}
      }
      else if (black_domain[pos] == 0 && white_domain[pos] == 1 && w_eye) {
	w_eye[pos].color = WHITE;
	for (k = 0; k < 4; k++) {
	  int apos = pos + delta[k];
	  if (ON_BOARD(apos) && black_domain[apos] && !white_domain[apos]) {
	    w_eye[pos].marginal = 1;
	    break;
	  }
	}
      }
      else if (black_domain[pos] == 1 && white_domain[pos] == 1) {
	if (b_eye) {
	  for (k = 0; k < 4; k++) {
	    int apos = pos + delta[k];
	    if (ON_BOARD(apos) && black_domain[apos]
		&& !white_domain[apos]) {
	      b_eye[pos].marginal = 1;
	      b_eye[pos].color = BLACK;
	      break;
	    }
	  }
	  if (k == 4)
	    b_eye[pos].color = GRAY;
	}
	
	if (w_eye) {
	  for (k = 0; k < 4; k++) {
	    int apos = pos + delta[k];
	    if (ON_BOARD(apos) && white_domain[apos]
		&& !black_domain[apos]) {
	      w_eye[pos].marginal = 1;
	      w_eye[pos].color = WHITE;
	      break;
	    }
	  }
	  if (k == 4)
	    w_eye[pos].color = GRAY;
	}
      }
    }
  }
  
  /* The eye spaces are all found. Now we need to find the origins. */
  partition_eyespaces(b_eye, BLACK);
  partition_eyespaces(w_eye, WHITE);
}

/* Find connected eyespace components and compute relevant statistics. */
void
partition_eyespaces(struct eye_data eye[BOARDMAX], int color)
{
  int pos;

  if (!eye)
    return;

  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (ON_BOARD(pos))
      eye[pos].origin = NO_MOVE;

  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (!ON_BOARD(pos))
      continue;
    if (eye[pos].origin == NO_MOVE && eye[pos].color == color) {
      int esize = 0;
      int msize = 0;
      
      originate_eye(pos, pos, &esize, &msize, eye);
      eye[pos].esize = esize;
      eye[pos].msize = msize;
    }
  }

  /* Now we count the number of neighbors and marginal neighbors
   * of each vertex.
   */
  count_neighbours(eye);
}


/* Compute the domains of influence of each color, used in determining
 * eye shapes. NOTE: the term influence as used here is distinct from the
 * influence in influence.c.
 * 
 * For this algorithm the strings which are not lively are invisible. Ignoring
 * these, the algorithm assigns friendly influence to:
 *
 * (1) every vertex which is occupied by a (lively) friendly stone, 
 * (2) every empty vertex adjoining a (lively) friendly stone,
 * (3) every empty vertex for which two adjoining vertices (not
 *     on the first line) in the (usually 8) surrounding ones have friendly
 *     influence, with two CAVEATS explained below.
 *
 * Thus in the following diagram, e would be assigned friendly influence
 * if a and b have friendly influence, or a and d. It is not sufficent
 * for b and d to have friendly influence, because they are not adjoining.
 * 
 *        uabc
 *         def
 *         ghi
 * 
 * The constraint that the two adjoining vertices not lie on the first
 * line prevents influence from leaking under a stone on the third line.
 * 
 * The first CAVEAT alluded to above is that even if a and b have friendly
 * influence, this does not cause e to have friendly influence if there
 * is a lively opponent stone at d. This constraint prevents 
 * influence from leaking past knight's move extensions.
 *
 * The second CAVEAT is that even if a and b have friendly influence
 * this does not cause e to have influence if there are lively opponent
 * stones at u and at c. This prevents influence from leaking past
 * nikken tobis (two space jumps).  
 *
 * The corner vertices are handled slightly different.
 * 
 *    +---
 *    |ab
 *    |cd
 * 
 * We get friendly influence at a if we have friendly influence
 * at b or c and no lively unfriendly stone at b, c or d. 
 *
 */

#define sufficient_influence(pos, apos, bpos) \
  (ON_BOARD(bpos) && influence[bpos] > threshold[pos] - influence[apos])

static void
compute_primary_domains(int color, int domain[BOARDMAX],
			int lively[BOARDMAX],
			int false_margins[BOARDMAX],
			int first_time)
{
  int other = OTHER_COLOR(color);
  int i, j, k;
  int pos, pos2;
  int own, enemy;
  signed char threshold[BOARDMAX];
  signed char influence[BOARDMAX];
  int list[BOARDMAX];
  int size = 0, lastchange = 0;

  memset(threshold, 0, sizeof(threshold));
  memset(influence, 0, sizeof(influence));
  
  /* In the first pass we
   * 1. Give influence to lively own stones and their neighbors.
   *    (Cases (1) and (2) above.)
   * 2. Fill influence[] and threshold[] arrays with initial values.
   */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (!ON_BOARD(pos))
      continue;
   
    if (lively[pos]) {
      if (board[pos] == color) {
        domain[pos] = 1; /* Case (1) above. */
        influence[pos] = 1;
      }
      else
        influence[pos] = -1;
      continue;
    }
    
    own = enemy = 0;
    for (k = 0; k < 4; k++) {
      pos2 = pos + delta[k];
      if (ON_BOARD(pos2) && lively[pos2]) {
        if (board[pos2] == color)
          own = 1;
        else
          enemy = 1;
      }
    }
    
    if (own) {
      /* To explain the asymmetry between the first time around
       * this loop and subsequent ones, a false margin is adjacent
       * to both B and W lively stones, so it's found on the first
       * pass through the loop.
       */
      if (first_time) {
        if (board[pos] == EMPTY && (false_margin(pos, color, lively)
				    || false_margin(pos, other, lively)))
          false_margins[pos] = 1;
        else {
          domain[pos] = 1;
          influence[pos] = 1;
        }
      }
      else if (board[pos] != EMPTY || !false_margins[pos]) {
        domain[pos] = 1;
        influence[pos] = 1;
      }
    }
    else
      list[size++] = pos;
    
    if (enemy) {
      threshold[pos] = 1;
      influence[pos]--;
    }
    else if (is_edge_vertex(pos))
      influence[pos]--;
  }
  
  /* Now we loop over the board until no more vertices can be added to
   * the domain through case (3) above.
   */
  if (size) {
    k = size;
    while (1) {
      if (!k)
        k = size;
      pos = list[--k];
   
      /* Case (3) above. */
      if (sufficient_influence(pos, SOUTH(pos), SE(pos))
          || sufficient_influence(pos, SOUTH(pos), SW(pos))
          || sufficient_influence(pos, EAST(pos), SE(pos))
          || sufficient_influence(pos, EAST(pos), NE(pos))
          || sufficient_influence(pos, WEST(pos), SW(pos))
          || sufficient_influence(pos, WEST(pos), NW(pos))
          || sufficient_influence(pos, NORTH(pos), NW(pos))
          || sufficient_influence(pos, NORTH(pos), NE(pos))) {
        domain[pos] = 1;
        influence[pos]++;
	
        if (!--size)
          break;
        if (k < size)
          list[k] = list[size];
        else
          k--;
        lastchange = k;
      }
      else if (k == lastchange)
        break; /* Looped the whole list and found nothing new */
    }
  }
  
  if (0 && (debug & DEBUG_EYES)) {
    start_draw_board();
    for (i = 0; i < board_size; i++)
      for (j = 0; j < board_size; j++) {
	draw_color_char(i, j, domain[POS(i, j)] ? '1' : '0', GG_COLOR_BLACK);
      }
    end_draw_board();
  }
}


static void
count_neighbours(struct eye_data eyedata[BOARDMAX])
{
  int pos;
  int k;

  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (!ON_BOARD(pos) || eyedata[pos].origin == NO_MOVE) 
      continue;

    eyedata[pos].esize = eyedata[eyedata[pos].origin].esize;
    eyedata[pos].msize = eyedata[eyedata[pos].origin].msize;
    eyedata[pos].neighbors = 0;
    eyedata[pos].marginal_neighbors = 0;
    
    for (k = 0; k < 4; k++) {
      int pos2 = pos + delta[k];
      if (ON_BOARD(pos2) && eyedata[pos2].origin == eyedata[pos].origin) {
	eyedata[pos].neighbors++;
	if (eyedata[pos2].marginal)
	  eyedata[pos].marginal_neighbors++;
      }
    }
  }
}


static int
is_lively(int owl_call, int pos)
{
  if (board[pos] == EMPTY)
    return 0;

  if (owl_call)
    return owl_lively(pos);
  else
    return (!worm[pos].inessential
	    && (worm[pos].attack_codes[0] == 0
		|| worm[pos].defense_codes[0] != 0));
}


/* In the following situation, we do not wish the vertex at 'a'
 * included in the O eye space:
 * 
 * OOOOXX
 * OXaX..
 * ------
 *
 * This eyespace should parse as (X), not (X!). Thus the vertex
 * should not be included in the eyespace if it is adjacent to
 * an X stone which is alive, yet X cannot play safely at a.
 * The function returns 1 if this situation is found at 
 * (pos) for color O.
 *
 * The condition above is true, curiously enough, also for the
 * following case:
 *   A group has two eyes, one of size 1 and one which is critical 1/2.
 *   It also has to have less than 4 external liberties, since the
 *   reading has to be able to capture the group tactically. In that 
 *   case, the eye of size one will be treated as a false marginal.
 * Thus we have to exclude this case, which is done by requiring (pos)
 * to be adjacent to both white and black stones. Since this test is
 * least expensive, we start with it.
 *
 * As a second optimization we require that one of the other colored
 * neighbors is not lively. This should cut down on the number of
 * calls to attack() and safe_move().
 */

static int
false_margin(int pos, int color, int lively[BOARDMAX])
{
  int other = OTHER_COLOR(color);
  int neighbors = 0;
  int k;
  int all_lively;
  int potential_false_margin;
  
  /* Require neighbors of both colors. */
  for (k = 0; k < 4; k++)
    if (ON_BOARD(pos + delta[k]))
	neighbors |= board[pos + delta[k]];	

  if (neighbors != (WHITE | BLACK))
    return 0;

  /* At least one opponent neighbor should be not lively. */
  all_lively = 1;
  for (k = 0; k < 4; k++)
    if (board[pos + delta[k]] == other && !lively[pos + delta[k]])
      all_lively = 0;

  if (all_lively)
    return 0;

  potential_false_margin = 0;
  for (k = 0; k < 4; k++) {
    int apos = pos + delta[k];
    if (board[apos] != other || !lively[apos])
      continue;
    
    if (stackp == 0 && worm[apos].attack_codes[0] == 0)
      potential_false_margin = 1;
    
    if (stackp > 0 && !attack(apos, NULL))
      potential_false_margin = 1;
  }
  
  if (potential_false_margin && safe_move(pos, other) == 0) {
    DEBUG(DEBUG_EYES, "False margin for %C at %1m.\n", color, pos);
    return 1;
  }

  return 0;
}


/*
 * originate_eye(pos, pos, *esize, *msize, eye) creates an eyeshape
 * with origin pos. esize and msize return the size and the number of
 * marginal vertices. The repeated variables (pos) are due to the
 * recursive definition of the function.
 */
static void
originate_eye(int origin, int pos,
	      int *esize, int *msize, 
	      struct eye_data eye[BOARDMAX])
{
  int k;
  ASSERT_ON_BOARD1(origin);
  ASSERT_ON_BOARD1(pos);
  gg_assert(esize != NULL);
  gg_assert(msize != NULL);
  
  eye[pos].origin = origin;
  (*esize)++;
  if (eye[pos].marginal)
    (*msize)++;

  for (k = 0; k < 4; k++) {
    int pos2 = pos + delta[k];
    if (ON_BOARD(pos2)
	&& eye[pos2].color == eye[pos].color
	&& eye[pos2].origin == NO_MOVE
	&& (!eye[pos2].marginal || !eye[pos].marginal))
      originate_eye(origin, pos2, esize, msize, eye);
  }
}


/* 
 * propagate_eye(origin) copies the data at the (origin) to the
 * rest of the eye (invariant fields only).
 */

void
propagate_eye(int origin, struct eye_data eye[BOARDMAX])
{
  int pos;

  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (ON_BOARD(pos) && eye[pos].origin == origin) {
      eye[pos].color         = eye[origin].color;
      eye[pos].esize         = eye[origin].esize;
      eye[pos].msize         = eye[origin].msize;
      eye[pos].origin        = eye[origin].origin;
      eye[pos].value         = eye[origin].value;
    }
}


/* Find the dragon or dragons surrounding an eye space. Up to
 * max_dragons dragons adjacent to the eye space are added to
 * the dragon array, and the number of dragons found is returned.
 */

int
find_eye_dragons(int origin, struct eye_data eye[BOARDMAX], int eye_color,
		 int dragons[], int max_dragons)
{
  int mx[BOARDMAX];
  int num_dragons = 0;
  int pos;

  memset(mx, 0, sizeof(mx));
  DEBUG(DEBUG_MISCELLANEOUS, "find_eye_dragons: %1m %C\n", origin, eye_color);
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (board[pos] == eye_color
	&& mx[dragon[pos].origin] == 0
	&& ((ON_BOARD(SOUTH(pos))
	     && eye[SOUTH(pos)].origin == origin
	     && !eye[SOUTH(pos)].marginal)
	    || (ON_BOARD(WEST(pos))
		&& eye[WEST(pos)].origin == origin
		&& !eye[WEST(pos)].marginal)
	    || (ON_BOARD(NORTH(pos))
		&& eye[NORTH(pos)].origin == origin
		&& !eye[NORTH(pos)].marginal)
	    || (ON_BOARD(EAST(pos))
		&& eye[EAST(pos)].origin == origin
		&& !eye[EAST(pos)].marginal))) {
      DEBUG(DEBUG_MISCELLANEOUS, 
	    "  dragon: %1m %1m\n", pos, dragon[pos].origin);
      mx[dragon[pos].origin] = 1;
      if (dragons != NULL && num_dragons < max_dragons)
	dragons[num_dragons] = dragon[pos].origin;
      num_dragons++;
    }
  }
  
  return num_dragons;
}

/* Print debugging data for the eyeshape at (i,j). Useful with GDB.
 */

static void
print_eye(struct eye_data eye[BOARDMAX], struct half_eye_data heye[BOARDMAX],
	  int pos)
{
  int m, n;
  int pos2;
  int mini, maxi;
  int minj, maxj;
  int origin = eye[pos].origin;

  gprintf("Eyespace at %1m: color=%C, esize=%d, msize=%d\n",
	  pos, eye[pos].color, eye[pos].esize, eye[pos].msize);
  
  for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
    if (!ON_BOARD(pos2))
      continue;
    
    if (eye[pos2].origin != pos) 
      continue;
    
    if (eye[pos2].marginal && IS_STONE(board[pos2]))
      gprintf("%1m (X!)\n", pos2);
    else if (is_halfeye(heye, pos2) && IS_STONE(board[pos2])) {
      if (heye[pos2].value == 3.0)
	gprintf("%1m (XH)\n", pos2);
      else
	gprintf("%1m (XH) (topological eye value = %f)\n", pos2,
		heye[pos2].value);
    }
    else if (!eye[pos2].marginal && IS_STONE(board[pos2]))
      gprintf("%1m (X)\n", pos2);
    else if (eye[pos2].marginal && board[pos2] == EMPTY)
      gprintf("%1m (!)\n", pos2);
    else if (is_halfeye(heye, pos2) && board[pos2] == EMPTY) {
      if (heye[pos2].value == 3.0)
	gprintf("%1m (H)\n", pos2);
      else
	gprintf("%1m (H) (topological eye value = %f)\n", pos2,
		heye[pos2].value);
    }
    else
      gprintf("%1m\n", pos2);
  }
  gprintf("\n");
  
  /* Determine the size of the eye. */
  mini = board_size;
  maxi = -1;
  minj = board_size;
  maxj = -1;
  for (m = 0; m < board_size; m++)
    for (n = 0; n < board_size; n++) {
      if (eye[POS(m, n)].origin != origin)
	continue;

      if (m < mini) mini = m;
      if (m > maxi) maxi = m;
      if (n < minj) minj = n;
      if (n > maxj) maxj = n;
    }

  /* Prints the eye shape. A half eye is shown by h, if empty or H, if an
   * enemy is present. Note that each half eye has a marginal point which is 
   * not printed, so the representation here may have less points than the 
   * matching eye pattern in eyes.db. Printing a marginal for the half eye
   * would be nice, but difficult to implement.
   */
  for (m = mini; m <= maxi; m++) {
    gprintf(""); /* Get the indentation right. */
    for (n = minj; n <= maxj; n++) {
      int pos2 = POS(m, n);
      if (eye[pos2].origin == origin) {
	if (board[pos2] == EMPTY) {
	  if (eye[pos2].marginal)
	    gprintf("%o!");
	  else if (is_halfeye(heye, pos2))
	    gprintf("%oh");
	  else
	    gprintf("%o.");
	}
	else if (is_halfeye(heye, pos2))
	  gprintf("%oH");
	else
	  gprintf("%oX");
      }
      else
	gprintf("%o ");
    }
    gprintf("\n");
  }
}


/* 
 * Given an eyespace with origin (pos), this function computes the
 * minimum and maximum numbers of eyes the space can yield. If max and
 * min are different, then vital points of attack and defense are also
 * generated.
 * 
 * If add_moves == 1, this function may add a move_reason for (color) at
 * a vital point which is found by the function. If add_moves == 0,
 * set color == EMPTY.
 */

void
compute_eyes(int pos, struct eyevalue *value,
	     int *attack_point, int *defense_point,
	     struct eye_data eye[BOARDMAX],
	     struct half_eye_data heye[BOARDMAX], int add_moves)
{
  if (attack_point)
    *attack_point = NO_MOVE;
  if (defense_point)
    *defense_point = NO_MOVE;

  if (debug & DEBUG_EYES) {
    print_eye(eye, heye, pos);
    DEBUG(DEBUG_EYES, "\n");
  }
  
  /* Look up the eye space in the graphs database. */
  if (read_eye(pos, attack_point, defense_point, value, eye, heye, add_moves))
    return;

  /* Ideally any eye space that hasn't been matched yet should be two
   * secure eyes. Until the database becomes more complete we have
   * some additional heuristics to guess the values of unknown
   * eyespaces.
   */
  if (eye[pos].esize - 2*eye[pos].msize > 3)
    set_eyevalue(value, 2, 2, 2, 2);
  else if (eye[pos].esize - 2*eye[pos].msize > 0)
    set_eyevalue(value, 1, 1, 1, 1);
  else
    set_eyevalue(value, 0, 0, 0, 0);
}


/*
 * This function works like compute_eyes(), except that it also gives
 * a pessimistic view of the chances to make eyes. Since it is intended
 * to be used from the owl code, the option to add move reasons has
 * been removed.
 */
void
compute_eyes_pessimistic(int pos, struct eyevalue *value,
			 int *pessimistic_min,
			 int *attack_point, int *defense_point,
			 struct eye_data eye[BOARDMAX],
			 struct half_eye_data heye[BOARDMAX])
{
  static int bulk_coefficients[5] = {-1, -1, 1, 4, 12};

  int pos2;
  int margins = 0;
  int halfeyes = 0;
  int margins_adjacent_to_margin = 0;
  int effective_eyesize;
  int bulk_score = 0;
  signed char chainlinks[BOARDMAX];

  /* Stones inside eyespace which do not coincide with a false eye or
   * a halfeye.
   */
  int interior_stones = 0;

  memset(chainlinks, 0, BOARDMAX);

  for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
    int k;

    if (!ON_BOARD(pos2) || eye[pos2].origin != pos)
      continue;

    if (eye[pos2].marginal || is_halfeye(heye, pos2)) {
      margins++;
      if (eye[pos2].marginal && eye[pos2].marginal_neighbors > 0)
	margins_adjacent_to_margin++;
      if (is_halfeye(heye, pos2))
	halfeyes++;
    }
    else if (IS_STONE(board[pos2]))
      interior_stones++;

    bulk_score += bulk_coefficients[(int) eye[pos2].neighbors];

    for (k = 0; k < 4; k++) {
      int neighbor = pos2 + delta[k];

      if (board[neighbor] == eye[pos].color) {
	if (!chainlinks[neighbor]) {
	  bulk_score += 4;
	  mark_string(neighbor, chainlinks, 1);
	}
      }
      else if (!ON_BOARD(neighbor))
	bulk_score += 2;
    }
  }

  /* This is a measure based on the simplified assumption that both
   * players only cares about playing the marginal eye spaces. It is
   * used later to guess the eye value for unidentified eye shapes.
   */
  effective_eyesize = (eye[pos].esize + halfeyes - 2*margins
		       - margins_adjacent_to_margin);

  if (attack_point)
    *attack_point = NO_MOVE;
  if (defense_point)
    *defense_point = NO_MOVE;

  if (debug & DEBUG_EYES) {
    print_eye(eye, heye, pos);
    DEBUG(DEBUG_EYES, "\n");
  }
  
  /* Look up the eye space in the graphs database. */
  if (read_eye(pos, attack_point, defense_point, value,
	       eye, heye, 0)) {
    *pessimistic_min = min_eyes(value) - margins;

    /* A single point eye which is part of a ko can't be trusted. */
    if (eye[pos].esize == 1
	&& is_ko(pos, OTHER_COLOR(eye[pos].color), NULL))
      *pessimistic_min = 0;

    DEBUG(DEBUG_EYES, "  graph matching - %s, pessimistic_min=%d\n",
	  eyevalue_to_string(value), *pessimistic_min);
  }
  
  /* Ideally any eye space that hasn't been matched yet should be two
   * secure eyes. Until the database becomes more complete we have
   * some additional heuristics to guess the values of unknown
   * eyespaces.
   */
  else {
    guess_eye_space(pos, effective_eyesize, margins, bulk_score, eye,
		    value, pessimistic_min); 
    DEBUG(DEBUG_EYES, "  guess_eye - %s, pessimistic_min=%d\n",
	  eyevalue_to_string(value), *pessimistic_min);
  }

  if (*pessimistic_min < 0) {
    *pessimistic_min = 0;
    DEBUG(DEBUG_EYES, "  pessimistic min revised to 0\n");
  }

  /* An eyespace with at least two interior stones is assumed to be
   * worth at least one eye, regardless of previous considerations.
   */
  if (*pessimistic_min < 1 && interior_stones >= 2) {
    *pessimistic_min = 1;
    DEBUG(DEBUG_EYES, "  pessimistic min revised to 1 (interior stones)\n");
  }

  if (attack_point
      && *attack_point == NO_MOVE
      && max_eyes(value) != *pessimistic_min) {
    /* Find one marginal vertex and set as attack and defense point.
     *
     * We make some effort to find the best marginal vertex by giving
     * priority to ones with more than one neighbor in the eyespace.
     * We prefer non-halfeye margins and ones which are not self-atari
     * for the opponent. Margins not on the edge are also favored.
     */
    int best_attack_point = NO_MOVE;
    int best_defense_point = NO_MOVE;
    float score = 0.0;
    
    for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
      if (ON_BOARD(pos2) && eye[pos2].origin == pos) {
	float this_score = 0.0;
	int this_attack_point = NO_MOVE;
	int this_defense_point = NO_MOVE;
	if (eye[pos2].marginal && board[pos2] == EMPTY) {
	  this_score = eye[pos2].neighbors;
	  this_attack_point = pos2;
	  this_defense_point = pos2;

	  if (is_self_atari(pos2, OTHER_COLOR(eye[pos].color)))
	    this_score -= 0.5;
	  
	  if (is_edge_vertex(pos2))
	    this_score -= 0.1;
	}
	else if (is_halfeye(heye, pos2)) {
	  this_score = 0.75;
	  this_defense_point = heye[pos2].defense_point[0];
	  this_attack_point = heye[pos2].attack_point[0];
	}
	else
	  continue;
	
	if (gg_normalize_float2int(this_score, 0.01)
	    > gg_normalize_float2int(score, 0.01)) {
	  best_attack_point = this_attack_point;
	  best_defense_point = this_defense_point;
	  score = this_score;
	}
      }
    }
    
    if (score > 0.0) {
      if (defense_point)
	*defense_point = best_defense_point;
      if (attack_point)
	*attack_point = best_attack_point;
    }
  }

  if (defense_point && *defense_point != NO_MOVE) {
    ASSERT_ON_BOARD1(*defense_point);
  }
  if (attack_point && *attack_point != NO_MOVE) {
    ASSERT_ON_BOARD1(*attack_point);
  }
}


static void
guess_eye_space(int pos, int effective_eyesize, int margins,
		int bulk_score, struct eye_data eye[BOARDMAX],
		struct eyevalue *value, int *pessimistic_min)
{
  if (effective_eyesize > 3) {
    set_eyevalue(value, 2, 2, 2, 2);
    *pessimistic_min = 1;

    if ((margins == 0 && effective_eyesize > 7)
	|| (margins > 0 && effective_eyesize > 9)) {
      int eyes = 2 + (effective_eyesize - 2 * (margins > 0) - 8) / 2;
      int threshold = (4 * (eye[pos].esize - 2)
		       + (effective_eyesize - 8) * (effective_eyesize - 9));

      DEBUG(DEBUG_EYES, "size: %d(%d), threshold: %d, bulk score: %d\n",
	    eye[pos].esize, effective_eyesize, threshold, bulk_score);

      if (bulk_score > threshold && effective_eyesize < 15)
	eyes = gg_max(2, eyes - ((bulk_score - threshold) / eye[pos].esize));

      if (bulk_score < threshold + eye[pos].esize || effective_eyesize >= 15)
	*pessimistic_min = eyes;

      set_eyevalue(value, eyes, eyes, eyes, eyes);
    }
  }
  else if (effective_eyesize > 0) {
    set_eyevalue(value, 1, 1, 1, 1);
    if (margins > 0)
      *pessimistic_min = 0;
    else
      *pessimistic_min = 1;
  }
  else {
    if (eye[pos].esize - margins > 2)
      set_eyevalue(value, 0, 0, 1, 1);
    else
      set_eyevalue(value, 0, 0, 0, 0);
    *pessimistic_min = 0;
  }
}


/* This function does some minor reading to improve the results of
 * recognize_eye(). Currently, it has two duties. One is to read
 * positions like this:
 *
 *     .XXXX|        with half eye         with proper eye
 *     XXOOO|
 *     XO.O.|           .   (1 eye)           .   (2 eyes)
 *     XXOa.|         !..                    .*
 *     -----+
 *
 * recognize_eye() sees the eyespace of the white dragon as shown
 * (there's a half eye at a and it is considered the same as '!.' by
 * the optics code). Normally, that eye shape gives only one secure
 * eye, and owl thinks that the white dragon is dead unconditionally.
 * This function tries to turn such ko-dependent half eyes into proper
 * eyes and chooses the best alternative. Note that we don't have any
 * attack/defense codes here, since owl will determine them itself.
 *
 * Another one is related to some cases when replacing half eyes with
 * '!.' doesn't work. E.g. consider this eye (optics:328):
 *
 *     XXXOO         eye graph is 310:
 *     X..X.
 *     XOXX.             !.!  (second '!' is due to the halfeye)
 *     OXO..
 *     O.O..
 *
 * When this function detects such a half eye that can be attacked
 * and/or defended inside its eyespace, it tries to turn it into a
 * proper eye and see what happens. In case it gives an improvement
 * for attacker and/or defender, the function keeps new result but
 * only if new vital points are also vital points for the half eye.
 * The heuristics used here might need improvements since they are
 * based on a single game position.
 *
 * If add_moves != 0, this function may add move reasons for (color)
 * at the vital points which are found by recognize_eye(). If add_moves 
 * == 0, set color to be EMPTY.
 */
static int
read_eye(int pos, int *attack_point, int *defense_point,
	 struct eyevalue *value, struct eye_data eye[BOARDMAX], 
	 struct half_eye_data heye[BOARDMAX], 
	 int add_moves)
{
  int eye_color;
  int k;
  int pos2;
  int combination_halfeye = NO_MOVE;
  int combination_attack = NO_MOVE;
  int combination_defense = NO_MOVE;
  int num_ko_halfeyes = 0;
  int ko_halfeye = NO_MOVE;
  struct vital_points vp;
  struct vital_points ko_vp;
  struct vital_points *best_vp = &vp;

  eye_color = recognize_eye(pos, attack_point, defense_point, value,
			    eye, heye, &vp);
  if (!eye_color)
    return 0;

  /* Find ko half eyes and "combination" half eyes if any. */
  for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
    if (ON_BOARD(pos2)
	&& eye[pos2].origin == pos
	&& heye[pos2].type == HALF_EYE) {
      if (combination_halfeye == NO_MOVE) {
	int apos = NO_MOVE;
	int dpos = NO_MOVE;
 
	for (k = 0; k < heye[pos2].num_attacks; k++) {
	  if (eye[heye[pos2].attack_point[k]].origin == pos) {
	    apos = heye[pos2].attack_point[k];
	    break;
	  }
	}
  
	for (k = 0; k < heye[pos2].num_defenses; k++) {
	  if (eye[heye[pos2].defense_point[k]].origin == pos) {
	    dpos = heye[pos2].defense_point[k];
	    break;
	  }
	}
 
	if (apos || dpos) {
	  combination_halfeye = pos2;
	  combination_attack = apos;
	  combination_defense = dpos;
	}
      }
 
      if (heye[pos2].value < 3.0) {
	num_ko_halfeyes++;
	ko_halfeye = pos2;
      }
    }
  }

  /* In case we have a "combination" half eye, turn it into a proper eye
   * vertex for a while and see what happens.
   */
  if (combination_halfeye != NO_MOVE) {
    int result;
    int apos = NO_MOVE;
    int dpos = NO_MOVE;
    struct eyevalue combination_value;
    struct vital_points combination_vp;

    heye[combination_halfeye].type = 0;
    result = recognize_eye(pos, &apos, &dpos, &combination_value, eye,
			   heye, &combination_vp);
    heye[combination_halfeye].type = HALF_EYE;

    if (result) {
      if (combination_attack
	  && min_eyes(value) > min_eyes(&combination_value)) {
	/* FIXME: I'm not sure we can ever get here. */
	for (k = 0; k < combination_vp.num_attacks; k++) {
	  if (combination_vp.attacks[k] == combination_attack) {
	    value->a = combination_value.a;
	    value->b = combination_value.b;
	    *attack_point = apos;
	    best_vp->num_attacks = 1;
	    best_vp->attacks[0] = combination_attack;
	    break;
	  }
	}
      }

      if (combination_defense
	  && max_eyes(value) < max_eyes(&combination_value)) {
	/* Turning the half eye into a proper eye gives an improvement.
	 * However, we can only accept this result if there is a vital
	 * point that defends both the half eye and the whole eyespace.
	 */
	for (k = 0; k < combination_vp.num_defenses; k++) {
	  if (combination_vp.defenses[k] == combination_defense) {
	    value->c = combination_value.c;
	    value->d = combination_value.d;
	    *defense_point = dpos;
	    best_vp->num_defenses = 1;
	    best_vp->defenses[0] = combination_defense;
	    break;
	  }
	}
      }

      if (min_eyes(value) != max_eyes(value)) {
	ASSERT1(combination_attack || combination_defense, combination_halfeye);
	if (*attack_point == NO_MOVE) {
	  *attack_point = combination_attack;
	  if (*attack_point == NO_MOVE)
	    *attack_point = combination_defense;
	}

	if (*defense_point == NO_MOVE) {
	  *defense_point = combination_defense;
	  if (*defense_point == NO_MOVE)
	    *defense_point = combination_defense;
	}
      }
    }
  }

  /* The same with ko half eye (we cannot win two kos at once, therefore we
   * give up if there is more than one ko half eye).
   */
  if (num_ko_halfeyes == 1) {
    int result;
    int apos = NO_MOVE;
    int dpos = NO_MOVE;
    struct eyevalue ko_value;

    heye[ko_halfeye].type = 0;
    result = recognize_eye(pos, &apos, &dpos, &ko_value, eye,
			   heye, &ko_vp);
    heye[ko_halfeye].type = HALF_EYE;

    if (result && max_eyes(value) < max_eyes(&ko_value)) {
      /* It is worthy to win the ko. */
      *value = ko_value;
      *attack_point = apos;
      *defense_point = dpos;
      best_vp = &ko_vp;
    }
  }

  if (add_moves) {
    struct vital_eye_points *vital;
    if (eye_color == WHITE)
      vital = white_vital_points;
    else
      vital = black_vital_points;
    for (k = 0; k < best_vp->num_defenses && k < MAX_EYE_ATTACKS; k++)
      vital[pos].defense_points[k] = best_vp->defenses[k];
    for (k = 0; k < best_vp->num_attacks && k < MAX_EYE_ATTACKS; k++)
      vital[pos].attack_points[k] = best_vp->attacks[k];
  }

  return 1;
}


/* recognize_eye(pos, *attack_point, *defense_point, *max, *min, eye_data,
 * half_eye_data, color, vp), where pos is the origin of an eyespace, returns
 * owner of eye (his color) if there is a pattern in eyes.db matching the
 * eyespace, or 0 if no match is found. If there is a key point for attack,
 * (*attack_point) is set to its location, or NO_MOVE if there is none.
 * Similarly (*defense_point) is the location of a vital defense point.
 * *value is set according to the pattern found. Vital attack/defense points
 * exist if and only if min_eyes(value) != max_eyes(value).
 */

static int
recognize_eye(int pos, int *attack_point, int *defense_point,
	      struct eyevalue *value,
	      struct eye_data eye[BOARDMAX], 
	      struct half_eye_data heye[BOARDMAX], 
	      struct vital_points *vp)
{
  int pos2;
  int eye_color;
  int eye_size = 0;
  int num_marginals = 0;
  int vpos[MAXEYE];
  signed char marginal[MAXEYE], edge[MAXEYE], neighbors[MAXEYE];
  int graph;
  int map[MAXEYE];
  int best_score;
  int r;

  gg_assert(attack_point != NULL);
  gg_assert(defense_point != NULL);
    
  /* Set `eye_color' to the owner of the eye. */
  eye_color = eye[pos].color;

  if (eye[pos].esize-eye[pos].msize > 8)
    return 0;

  if (eye[pos].msize > MAXEYE)
    return 0;

  /* Create list of eye vertices */
  for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++) {
    if (!ON_BOARD(pos2))
      continue;
    if (eye[pos2].origin == pos) {
      vpos[eye_size] = pos2;
      marginal[eye_size] = eye[pos2].marginal;
      if (marginal[eye_size])
	num_marginals++;
      neighbors[eye_size] = eye[pos2].neighbors;
      if (0) {
	if (marginal[eye_size])
	  TRACE("(%1m)", vpos[eye_size]);
	else
	  TRACE(" %1m ", vpos[eye_size]);
	TRACE("\n");
      }
      
      if (is_corner_vertex(pos2))
	edge[eye_size] = 2;
      else if (is_edge_vertex(pos2))
	edge[eye_size] = 1;
      else 
	edge[eye_size] = 0;
      
      if (is_halfeye(heye, pos2)) {
	neighbors[eye_size]++;      /* Increase neighbors of half eye. */
	eye_size++;
	/* Use a virtual marginal vertex for mapping purposes. We set it
	 * to be at NO_MOVE so it won't accidentally count as a
	 * neighbor for another vertex. Note that the half eye precedes
	 * the virtual marginal vertex in the list.
	 */
	vpos[eye_size] = NO_MOVE;
	marginal[eye_size] = 1;
	num_marginals++;
	edge[eye_size] = 0;
	neighbors[eye_size] = 1;
      }
      
      eye_size++;
    }
  }
  
  /* We attempt to construct a map from the graph to the eyespace
   * preserving the adjacency structure. If this can be done, we've
   * identified the eyeshape.
   */

  for (graph = 0; graphs[graph].vertex != NULL; graph++) {
    int q;

    if (graphs[graph].esize != eye_size
	|| graphs[graph].msize != num_marginals)
      continue;

    reset_map(eye_size);
    q = 0;
    first_map(&map[0]);

    while (1) {
      struct eye_vertex *gv = &graphs[graph].vertex[q];
      int mv = map[q];
      int ok = 1;

      if (0)
	TRACE("q=%d: %d %d %d %d %d %d\n", 
	      q, map[0], map[1], map[2], map[3], map[4], map[5]);

      if (neighbors[mv] != gv->neighbors
	  || marginal[mv] != gv->marginal
	  || edge[mv] < gv->edge)
	ok = 0;

      if (ok) {
        if (IS_STONE(board[vpos[mv]])) {
	  if (!(gv->flags & CAN_CONTAIN_STONE))
	    ok = 0;
	}
	/* Virtual half eye marginals also fall here since they are off
	 * board.
	 */
	else if (!(gv->flags & CAN_BE_EMPTY))
	  ok = 0;
      }

      if (ok) {
	int k;

	for (k = 0; k < gv->neighbors; k++) {
	  if (gv->n[k] < q) {
	    int mn = map[gv->n[k]];

	    /* Two eye vertices are neighbours if they are adjacent on the
	     * board or one of them is a half eye and the other is its
	     * virtual marginal vertex (and follows it in vpos[] array).
	     */
	    if (vpos[mv] != SOUTH(vpos[mn])
		&& vpos[mv] != WEST(vpos[mn])
		&& vpos[mv] != NORTH(vpos[mn])
		&& vpos[mv] != EAST(vpos[mn])
		&& (mv != mn - 1
		    || vpos[mv] == NO_MOVE
		    || heye[vpos[mv]].type != HALF_EYE)
		&& (mn != mv - 1
		    || vpos[mn] == NO_MOVE
		    || heye[vpos[mn]].type != HALF_EYE)) {
	      ok = 0;
	      break;
	    }
	  }
	}
      }

      if (!ok) {
	if (!next_map(&q, map))
	  break;

	if (0)
	  gprintf("  q=%d, esize=%d: %d %d %d %d %d\n",
		  q, eye_size, 
		  map[0], map[1], map[2], map[3], map[4]);
      }
      else {
	q++;
	if (q == eye_size)
	  break;			/* A match! */
	
	first_map(&map[q]);
      }
    }

    if (q == eye_size) {
      /* We have found a match! Now sort out the vital moves. */
      *value = graphs[graph].value;
      vp->num_attacks = 0;
      vp->num_defenses = 0;
      
      if (eye_move_urgency(value) > 0) {
	/* Collect all attack and defense points in the pattern. */
	int k;

	for (k = 0; k < eye_size; k++) {
	  struct eye_vertex *ev = &graphs[graph].vertex[k];

	  if (ev->flags & EYE_ATTACK_POINT) {
	    /* Check for a marginal vertex matching a half eye virtual
	     * marginal. This is the case if a half eye preceeds the
	     * current vertex in the list.
	     */
	    if (ev->marginal
		&& map[k] > 0
		&& vpos[map[k] - 1] != NO_MOVE
		&& is_halfeye(heye, vpos[map[k] - 1])) {
	      /* Add all diagonals as vital. */
	      int ix;
	      struct half_eye_data *he = &heye[vpos[map[k] - 1]];
	      
	      for (ix = 0; ix < he->num_attacks; ix++)
		vp->attacks[vp->num_attacks++] = he->attack_point[ix];
	    }
	    else
	      vp->attacks[vp->num_attacks++] = vpos[map[k]];
	  }
	  
	  if (ev->flags & EYE_DEFENSE_POINT) {
	    /* Check for a half eye virtual marginal vertex. */
	    if (ev->marginal
		&& map[k] > 0
		&& vpos[map[k] - 1] != NO_MOVE
		&& is_halfeye(heye, vpos[map[k] - 1])) {
	      /* Add all diagonals as vital. */
	      int ix;
	      struct half_eye_data *he = &heye[vpos[map[k] - 1]];
	      
	      for (ix = 0; ix < he->num_defenses; ix++)
		vp->defenses[vp->num_defenses++] = he->defense_point[ix];
	    }
	    else
	      vp->defenses[vp->num_defenses++] = vpos[map[k]];
	  }
	}
	
	gg_assert(vp->num_attacks > 0 && vp->num_defenses > 0);

	/* We now have all vital attack and defense points listed but
         * we are also expected to single out of one of each to return
         * in *attack_point and *defense_point. Since sometimes those
         * are the only vital points considered, we want to choose the
         * best ones, in the sense that they minimize the risk for
         * error in the eye space analysis.
	 *
	 * One example is this position
	 *
	 * |..XXXX
	 * |XXX..X
	 * |..!O.X
	 * |OO.O.X
	 * |.O.!XX
	 * +------
	 *
	 * where O has an eyespace of the !..! type. The graph
	 * matching finds that both marginal vertices are vital points
	 * but here the one at 3-3 fails to defend. (For attack both
	 * points work but the 3-3 one is still worse since it leaves
	 * a ko threat.)
	 *
	 * In order to differentiate between the marginal points we
	 * count the number of straight and diagonal neighbors within
	 * the eye space. In the example above both have one straight
	 * neighbor each but the edge margin wins because it also has
	 * a diagonal margin.
	 */

	best_score = -10;
	for (k = 0; k < vp->num_attacks; k++) {
	  int apos = vp->attacks[k];
	  int score = 0;
	  for (r = 0; r < 8; r++)
	    if (ON_BOARD(apos + delta[r])
		&& eye[apos + delta[r]].color == eye[pos].color
		&& !eye[apos + delta[r]].marginal) {
	      score++;
	      if (r < 4) {
		score++;
		if (board[apos + delta[r]] != EMPTY)
		  score++;
	      }
	    }

	  /* If a vital point is not adjacent to any point in the eye
           * space, it must be a move to capture or defend a string
           * related to a halfeye, e.g. the move * in this position,
	   *
	   * ......|
	   * .XXXX.|
	   * .X.O..|
	   * .XO.OO|
	   * .*XO..|
	   * ------+
	   *
	   * Playing this is probably a good idea.
	   */
	  if (score == 0)
	    score += 2;
	  
	  if (0)
	    gprintf("attack point %1m score %d\n", apos, score);
	  
	  if (score > best_score) {
	    *attack_point = apos;
	    best_score = score;
	  }
	}

	best_score = -10;
	for (k = 0; k < vp->num_defenses; k++) {
	  int dpos = vp->defenses[k];
	  int score = 0;
	  for (r = 0; r < 8; r++)
	    if (ON_BOARD(dpos + delta[r])
		&& eye[dpos + delta[r]].color == eye[pos].color
		&& !eye[dpos + delta[r]].marginal) {
	      score++;
	      if (r < 4) {
		score++;
		if (board[dpos + delta[r]] != EMPTY)
		  score++;
	      }
	    }

	  /* If possible, choose a non-sacrificial defense point.
	   * Compare white T8 and T6 in lazarus:21.
	   */
	  if (safe_move(dpos, eye_color) != WIN)
	    score -= 5;

	  /* See comment to the same code for attack points. */
	  if (score == 0)
	    score += 2;

	  if (0)
	    gprintf("defense point %1m score %d\n", dpos, score);
	  
	  if (score > best_score) {
	    *defense_point = dpos;
	    best_score = score;
	  }
	}
	
	DEBUG(DEBUG_EYES, "  vital points: %1m (attack) %1m (defense)\n",
	      *attack_point, *defense_point);
	DEBUG(DEBUG_EYES, "  pattern matched:  %d\n", graphs[graph].patnum);
	
      }
      TRACE("eye space at %1m of type %d\n", pos, graphs[graph].patnum);
      
      return eye_color;
    }
  }

  return 0;
}


/* a MAP is a map of the integers 0,1,2, ... ,q into 
 * 0,1, ... , esize-1 where q < esize. This determines a 
 * bijection of the first q+1 elements of the graph into the 
 * eyespace. The following three functions work with maps.
 */

/* Reset internal data structure used by first_map() and
 * next_map() functions.
 */
static void
reset_map(int size)
{
  map_size = size;
  memset(used_index, 0, size * sizeof(used_index[0]));
}


/* The function first_map finds the smallest valid
 * value of a map element.
 */
static void
first_map(int *map_value)
{
  int k = 0;

  while (used_index[k])
    k++;

  used_index[k] = 1;
  *map_value = k;
}     


/* The function next_map produces the next map in lexicographical
 * order. If no next map can be found, q is decremented, then we
 * try again. If the entire map is lexicographically last, the
 * function returns false.
 */
static int
next_map(int *q, int map[MAXEYE])
{
  int k;

  do {
    used_index[map[*q]] = 0;
    for (k = map[*q]; ++k < map_size;) {
      if (!used_index[k]) {
	used_index[k] = 1;
	map[*q] = k;
	return 1;
      }
    }

    (*q)--;
  } while (*q >= 0);
  
  return 0;
}     


/* add_false_eye() turns a proper eyespace into a margin. */

static void
add_false_eye(int pos, struct eye_data eye[BOARDMAX],
	      struct half_eye_data heye[BOARDMAX])
{
  int k;
  ASSERT1(heye[pos].type == FALSE_EYE, pos);
  DEBUG(DEBUG_EYES, "false eye found at %1m\n", pos);

  if (eye[pos].color == GRAY || eye[pos].marginal != 0)
    return;
  
  eye[pos].marginal = 1;
  eye[eye[pos].origin].msize++;
  for (k = 0; k < 4; k++)
    if (ON_BOARD(pos + delta[k])
	&& eye[pos + delta[k]].origin == eye[pos].origin)
      eye[pos + delta[k]].marginal_neighbors++;
  propagate_eye(eye[pos].origin, eye);
}


/* These functions are used from constraints to identify eye spaces,
 * primarily for late endgame moves.
 */
int
is_eye_space(int pos)
{
  return (white_eye[pos].color == WHITE
	  || black_eye[pos].color == BLACK);
}

int
is_proper_eye_space(int pos)
{
  return ((white_eye[pos].color == WHITE && !white_eye[pos].marginal)
	  || (black_eye[pos].color == BLACK && !black_eye[pos].marginal));
}

/* Return the maximum number of eyes that can be obtained from the
 * eyespace at (i, j). This is most useful in order to determine
 * whether the eyespace can be assumed to produce any territory at
 * all.
 */
int
max_eye_value(int pos)
{
  int max_white = 0;
  int max_black = 0;
  
  if (white_eye[pos].color == WHITE)
    max_white = max_eyes(&white_eye[pos].value);

  if (black_eye[pos].color == BLACK)
    max_black = max_eyes(&black_eye[pos].value);

  return gg_max(max_white, max_black);
}

int
is_marginal_eye_space(int pos)
{
  return (white_eye[pos].marginal || black_eye[pos].marginal);
}

int
is_halfeye(struct half_eye_data heye[BOARDMAX], int pos)
{
  return heye[pos].type == HALF_EYE;
}

int
is_false_eye(struct half_eye_data heye[BOARDMAX], int pos)
{
  return heye[pos].type == FALSE_EYE;
}


/* Find topological half eyes and false eyes by analyzing the
 * diagonal intersections, as described in the Texinfo
 * documentation (Eyes/Eye Topology).
 */
void
find_half_and_false_eyes(int color, struct eye_data eye[BOARDMAX],
			 struct half_eye_data heye[BOARDMAX],
			 int find_mask[BOARDMAX])
{
  int eye_color = color;
  int pos;
  float sum;
  
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    /* skip eyespaces which owl doesn't want to be searched */
    if (!ON_BOARD(pos) || (find_mask && find_mask[eye[pos].origin] <= 1))
      continue;
    
    /* skip every vertex which can't be a false or half eye */
    if (eye[pos].color != eye_color
        || eye[pos].marginal
        || eye[pos].neighbors > 1)
      continue;
    
    sum = topological_eye(pos, color, eye, heye);
    if (sum >= 4.0) {
      /* false eye */
      heye[pos].type = FALSE_EYE;
      if (eye[pos].esize == 1
          || is_legal(pos, OTHER_COLOR(color))
          || board[pos] == OTHER_COLOR(color))
        add_false_eye(pos, eye, heye);
    }
    else if (sum > 2.0) {
      /* half eye */
      heye[pos].type = HALF_EYE;
      ASSERT1(heye[pos].num_attacks > 0, pos);
      ASSERT_ON_BOARD1(heye[pos].attack_point[0]);
      ASSERT1(heye[pos].num_defenses > 0, pos);
      ASSERT_ON_BOARD1(heye[pos].defense_point[0]);
    }
  }
}


/* See Texinfo documentation (Eyes:Eye Topology). Returns:
 * - 2 or less if (pos) is a proper eye for (color);
 * - between 2 and 3 if the eye can be made false only by ko
 * - 3 if (pos) is a half eye;
 * - between 3 and 4 if the eye can be made real only by ko
 * - 4 or more if (pos) is a false eye.
 *
 * Attack and defense points for control of the diagonals are stored
 * in the heye[] array.
 *
 * my_eye is the eye space information with respect to (color).
 */

static float
topological_eye(int pos, int color,
		struct eye_data my_eye[BOARDMAX],
		struct half_eye_data heye[BOARDMAX])
{
  float sum = 0.0;
  float val;
  int num_attacks = 0;
  int num_defenses = 0;
  int attack_values[4];
  int defense_values[4];
  int k;
  int r;
  int attack_point;
  int defense_point;
  int attack_value;
  int defense_value;

  memset(attack_values, 0, sizeof(attack_values));
  memset(defense_values, 0, sizeof(defense_values));
  
  /* Loop over the diagonal directions. */
  for (k = 4; k < 8; k++) {
    int diag = pos + delta[k];
    val = evaluate_diagonal_intersection(I(pos) + deltai[k],
					 J(pos) + deltaj[k], color,
					 &attack_point, &defense_point, 
					 my_eye);

    /*
     * Eyespaces with cutting points are problematic. In this position
     * 
     * .....XXXXX
     * XXXXX.OO.X
     * X.OOOO.O.X
     * X.O.XXXO.X
     * ----------
     * 
     * the eyespace will be .XXX. which evaluates to two eyes (seki)
     * unless countermeasures are taken.
     *
     * This can be worked around in the topological analysis by
     * sometimes setting the diagonal value to 2.0 for vertices inside
     * the eyespace which are occupied by opponent stones. More
     * precisely all of the following conditions must hold:
     *
     * a) The value is not already 2.0.
     * a) The (potential) eyepoint is empty.
     * b) The diagonal is occupied by an opponent string,
     * c) which is also adjacent to the (potential) eye and 
     * d) at least three stones long.
     * e) The (potential) eye is not on the edge (to steer clear of all the
     *    hairy cases that are handled by eyes.db anyway).
     * f) At least two own strings are adjacent to the (potential) eye.
     * g) At least one of the own strings adjacent to the (potential) eye has
     *    only one liberty which is an eye space and not decided false, yet.
     *
     * With this revision the eyespace above becomes .XXXh or
     * equivalently .XXX.! which is almost evaluated correctly, eye
     * value 0122 instead of the correct 1122. Compared to the
     * previous value 2222 it's a major improvement.
     *
     * FIXME: This approach has a number of shortcomings.
     *
     *        1. d) is kind of arbitrary and there may be exceptional
     *           cases.
     *
     *        2. This diagonal value modification should not apply to
     *           two diagonals of the same strings inside the eyespace.
     *           E.g. if we have a partial eyespace looking like
     *
     *           .OOO.
     *           OO.OO
     *           OXXXO
     *
     *           it doesn't make sense to mark the middle vertex as a
     *           false eye. Possibly this doesn't make any difference
     *           in practice but it's at the very least confusing.
     *
     *        3. Actually it doesn't make sense to mark vertices as
     *           false otherwise either due to these revisions (half
     *           eyes make good sense though) as can be seen if a
     *           stone is added to the initial diagram,
     * 
     *           .....XXXXX
     *           XXXXXXOO.X
     *           X.OOOO.O.X
     *           X.O.XXXO.X
     *           ----------
     *
     *           Now the eyespace instead becomes .XXX! which has the
     *           eye value 0011 but if X tries to attack the eye O
     *           suddenly gets two solid eyes!
     *
     *           The correct analysis would be to remove the vertex
     *           from the eyespace rather than turning it into a false
     *           eye. Then we would have the eyespace .XXX which is
     *           correctly evaluated to one eye (eye value 1112).
     *
     *           The problem with this is that removing eye points is
     *           messy. It can surely be done but currently there is
     *           no support in the code for doing that. It has existed
     *           at an earlier time but was removed because the
     *           implementation was not robust enough and there was no
     *           longer any apparent need for it. To correct this
     *           problem is sufficient reason to reimplement that
     *           functionality.
     *
     *        4. The test of condition g) has a result which
     *           potentially depends on the ordering of the eyespaces
     *           and thus presumably on the orientation of the board.
     *           It might make more sense to examine whether the
     *           string neighbors more than one empty vertex in the
     *           same eyespace.
     */
    if (val < 2.0 && board[pos] == EMPTY && board[diag] == OTHER_COLOR(color)
	&& !is_edge_vertex(pos) && neighbor_of_string(pos, diag)
	&& countstones(diag) >= 3) {
      int strings[3];
      int string_count;
      int s;
      string_count = 0;
      for (r = 0; r < 4; r++) {
	int str;
	str = pos + delta[r];

	if (board[str] != color)
	  continue;

	ASSERT1(string_count < 3, pos);
	for (s = 0; s < string_count; s++)
	  if (same_string(str, strings[s]))
	    break;
	if (s != string_count)
	  continue;

	strings[string_count++] = str;
      }
      if (string_count > 1) {
	for (s = 0; s < string_count; s++) {
	  int libs[MAX_LIBERTIES];
	  int adj_eye_count;
	  int lib_count;
	  adj_eye_count = 0;
	  lib_count = findlib(strings[s], MAX_LIBERTIES, libs);
	  if (lib_count > MAX_LIBERTIES)
	    continue;

	  for (r = 0; r < lib_count && adj_eye_count < 2; r++)
	    if (my_eye[libs[r]].color == OTHER_COLOR(color)
		&& !my_eye[libs[r]].marginal)
	      adj_eye_count++;
	  if (adj_eye_count < 2) {
	    val = 2.0;
	    break;
	  }
	}
      }
    }

    sum += val;

    if (val > 0.0 && val < 2.0) {
      /* Diagonals off the edge has value 1.0 but no attack or defense
       * point.
       */
      if (attack_point != NO_MOVE && defense_point != NO_MOVE) {
	ASSERT_ON_BOARD1(attack_point);
	ASSERT_ON_BOARD1(defense_point);
	/* Store these in sorted (descending) order. We remap val
         * differently for attack and defense points according to:
	 *
	 * val    attack_value     defense_value
	 * ---    ------------     -------------
	 * 1.0    3                3
	 * <1.0   2                1
	 * >1.0   1                2
	 *
	 * This means that we primarily want to take control of
	 * diagonals without ko and secondarily of diagonals we can
	 * take unconditionally but not the opponent.
	 */
	if (val == 1.0) {
	  attack_value = 3;
	  defense_value = 3;
	}
	else if (val < 1.0) {
	  attack_value = 2;
	  defense_value = 1;
	}
	else {
	  attack_value = 1;
	  defense_value = 2;
	}

	for (r = 0; r < 4; r++) {
	  if (attack_values[r] < attack_value) {
	    int tmp_value = attack_values[r];
	    int tmp_point;
	    if (tmp_value)
	      tmp_point = heye[pos].attack_point[r];
	    else
	      tmp_point = 0;
	    attack_values[r] = attack_value;
	    heye[pos].attack_point[r] = attack_point;
	    attack_value = tmp_value;
	    attack_point = tmp_point;
	  }
	  
	  if (defense_values[r] < defense_value) {
	    int tmp_value = defense_values[r];
	    int tmp_point;
	    if (tmp_value)
	      tmp_point = heye[pos].defense_point[r];
	    else
	      tmp_point = 0;
	    defense_values[r] = defense_value;
	    heye[pos].defense_point[r] = defense_point;
	    defense_value = tmp_value;
	    defense_point = tmp_point;
	  }
	}
	
	num_attacks++;
	num_defenses++;
      }
    }
  }

  /* Remove attacks and defenses with smaller value than the best
   * ones. (These might be useful to save as well, but not unless we
   * also store the attack/defense values in the half_eye_data.)
   */
  for (r = 0; r < num_attacks; r++) {
    if (attack_values[r] < attack_values[0]) {
      num_attacks = r;
      break;
    }
  }
  
  for (r = 0; r < num_defenses; r++) {
    if (defense_values[r] < defense_values[0]) {
      num_defenses = r;
      break;
    }
  }

  heye[pos].num_attacks = num_attacks;
  heye[pos].num_defenses = num_defenses;
  heye[pos].value = sum;

  return sum;
}



/* Evaluate an intersection (m, n) which is diagonal to an eye space,
 * as described in the Texinfo documentation (Eyes/Eye Topology).
 *
 * Returns:
 *
 * 0 if both coordinates are off the board
 * 1 if one coordinate is off the board
 *
 * 0    if (color) has control over the vertex
 * a    if (color) can take control over the vertex unconditionally and
 *      the opponent can take control by winning a ko.
 * 1    if both (color) and the opponent can take control of the vertex
 *      unconditionally
 * b    if (color) can take control over the vertex by winning a ko and
 *      the opponent can take control unconditionally.
 * 2    if the opponent has control over the vertex
 *
 * The values a and b are discussed in the documentation. We are
 * currently using a = 0.75 and b = 1.25.
 *
 * Notice that it's necessary to pass the coordinates separately
 * instead of as a 1D coordinate. The reason is that the 1D mapping
 * can't uniquely identify "off the corner" points.
 *
 * my_eye has to be the eye_data with respect to color.
 */
static float
evaluate_diagonal_intersection(int m, int n, int color,
			       int *attack_point, int *defense_point,
			       struct eye_data my_eye[BOARDMAX])
{
  float value = 0;
  int other = OTHER_COLOR(color);
  int pos = POS(m, n);
  int acode = 0;
  int apos = NO_MOVE;
  int dcode = 0;
  int dpos = NO_MOVE;
  int off_edge = 0;
  const float a = 0.75;
  const float b = 2 - a;

  *attack_point = NO_MOVE;
  *defense_point = NO_MOVE;
  
  /* Check whether intersection is off the board. We must do this for
   * each board coordinate separately because points "off the corner"
   * are special cases.
   */
  if (m < 0 || m >= board_size)
    off_edge++;

  if (n < 0 || n >= board_size)
    off_edge++;

  /* Must return 0 if both coordinates out of bounds. */
  if (off_edge > 0)
    return (float) (off_edge % 2);

  /* Discard points within own eyespace, unless marginal or ko point.
   *
   * Comment: For some time discardment of points within own eyespace
   * was contingent on this being the same eyespace as that of the
   * examined vertex. This caused problems, e.g. in this position,
   *
   * |........
   * |XXXXX...
   * |OOOOX...
   * |aO.OX...
   * |OXXOX...
   * |.XXOX...
   * +--------
   *
   * where the empty vertex at a was evaluated as a false eye and the
   * whole group as dead (instead of living in seki).
   *
   * The reason for the requirement of less than two marginal
   * neighbors is this position:
   *
   * |.XXXX...
   * |.OOOX...
   * |O..OX...
   * |aOO.X...
   * |O..XX...
   * |..O.X...
   * |.X..X...
   * |..XXX...
   *
   * where the empty vertex at a should not count as a solid eye.
   * (The eyespace diagonally below a looks like this:
   *   .!
   *   !
   * so we can clearly see why having two marginal vertices makes a
   * difference.)
   */
   if (my_eye[pos].color == color
       && !my_eye[pos].marginal
       && my_eye[pos].marginal_neighbors < 2
       && !(board[pos] == EMPTY && does_capture_something(pos, other)))
    return 0.0;

  if (board[pos] == EMPTY) {
    int your_safety = safe_move(pos, other);

    apos = pos;
    dpos = pos;

    /* We should normally have a safe move, but occasionally it may
     * happen that it's not safe. There are complications, however,
     * with a position like this:
     *
     * .XXXX|
     * XXOO.|
     * XO.O.|
     * XXO.O|
     * -----+
     *
     * Therefore we ignore our own safety if opponent's safety depends
     * on ko.
     */
    if (your_safety == 0)
      value = 0.0;
    else if (your_safety != WIN)
      value = a;
    else {                           /* So your_safety == WIN. */
      int our_safety = safe_move(pos, color);
      
      if (our_safety == 0) {
	int k;

	value = 2.0;

	/* This check is intended to fix a certain special case, but might
	 * be helpful in other situations as well. Consider this position,
	 * happened in owl reading deep enough:
	 *
	 * |XXXXX
	 * |XOOXX
	 * |O.OOX
	 * |.OXX.
	 * +-----
	 *
	 * Without this check, the corner eye is considered false, not half-
	 * eye. Thus, owl thinks that the capture gains at most one eye and
	 * gives up.
	 */
	for (k = 4; k < 8; k++) {
	  int diagonal = pos + delta[k];
	  int lib;

	  if (board[diagonal] == other && findlib(diagonal, 1, &lib) == 1) {
	    if (lib != pos && does_secure(color, lib, pos)) {
	      value = 1.0;
	      apos = lib;
	      break;
	    }
	  }
	}
      }
      else if (our_safety == WIN)
        value = 1.0;
      else                           /* our_safety depends on ko. */
        value = b;
    }
  }
  else if (board[pos] == color) {
    /* This stone had better be safe, otherwise we wouldn't have an
     * eyespace in the first place.
     */
    value = 0.0;
  }
  else if (board[pos] == other) {
    if (stackp == 0) {
      acode = worm[pos].attack_codes[0];
      apos  = worm[pos].attack_points[0];
      dcode = worm[pos].defense_codes[0];
      dpos  = worm[pos].defense_points[0];
    }
    else
      attack_and_defend(pos, &acode, &apos, &dcode, &dpos);

    /* Must test acode first since dcode only is reliable if acode is
     * non-zero.
     */
    if (acode == 0)
      value = 2.0;
    else if (dcode == 0)
      value = 0.0;
    else if (acode == WIN && dcode == WIN)
      value = 1.0;
    else if (acode == WIN && dcode != WIN)
      value = a;
    else if (acode != WIN && dcode == WIN)
      value = b;
    else if (acode != WIN && dcode != WIN)
      value = 1.0; /* Both contingent on ko. Probably can't happen. */
  }
  
  if (value > 0.0 && value < 2.0) {
    /* FIXME:
     * Usually there are several attack and defense moves that would
     * be equally valid. It's not good that we make an arbitrary
     * choice at this point.
     */
    ASSERT_ON_BOARD1(apos);
    ASSERT_ON_BOARD1(dpos);
    /* Notice:
     * The point to ATTACK the half eye is the point which DEFENDS
     * the stones on the diagonal intersection and vice versa. Thus
     * we must switch attack and defense points here.
     * If the vertex is empty, dpos == apos and it doesn't matter
     * whether we switch.
     */
    *attack_point = dpos;
    *defense_point = apos;
  }

  return value;
}


/* Conservative relative of topological_eye(). Essentially the same
 * algorithm is used, but only tactically safe opponent strings on
 * diagonals are considered. This may underestimate the false/half eye
 * status, but it should never be overestimated.
 */
int
obvious_false_eye(int pos, int color)
{
  int i = I(pos);
  int j = J(pos);
  int k;
  int diagonal_sum = 0;
  for (k = 4; k < 8; k++) {
    int di = deltai[k];
    int dj = deltaj[k];
    
    if (!ON_BOARD2(i+di, j) && !ON_BOARD2(i, j+dj))
      diagonal_sum--;
    
    if (!ON_BOARD2(i+di, j+dj))
      diagonal_sum++;
    else if (BOARD(i+di, j+dj) == OTHER_COLOR(color)
	     && !attack(POS(i+di, j+dj), NULL))
      diagonal_sum += 2;
  }
  
  return diagonal_sum >= 4;
}


/* Set the parameters into struct eyevalue as follows:
a = number of eyes if attacker plays first twice
b = number of eyes if attacker plays first
c = number of eyes if defender plays first
d =number of eyes if defender plays first twice
*/

void
set_eyevalue(struct eyevalue *e, int a, int b, int c, int d)
{
  e->a = a;
  e->b = b;
  e->c = c;
  e->d = d;
}

/* Number of eyes if attacker plays first twice (the threat of the first
 * move by attacker).
 */
int
min_eye_threat(struct eyevalue *e)
{
  return e->a;
}

/* Number of eyes if attacker plays first followed by alternating play. */
int
min_eyes(struct eyevalue *e)
{
  return e->b;
}

/* Number of eyes if defender plays first followed by alternating play. */
int
max_eyes(struct eyevalue *e)
{
  return e->c;
}

/* Number of eyes if defender plays first twice (the threat of the first
 * move by defender).
 */
int
max_eye_threat(struct eyevalue *e)
{
  return e->d;
}

/* Add the eyevalues *e1 and *e2, leaving the result in *sum. It is
 * safe to let sum be the same as e1 or e2.
 */
void
add_eyevalues(struct eyevalue *e1, struct eyevalue *e2, struct eyevalue *sum)
{
  struct eyevalue res;
  res.a = gg_min(gg_min(e1->a + e2->c, e1->c + e2->a),
		 gg_max(e1->a + e2->b, e1->b + e2->a));
  res.b = gg_min(gg_max(e1->b + e2->b, gg_min(e1->a + e2->d, e1->b + e2->c)),
		 gg_max(e1->b + e2->b, gg_min(e1->d + e2->a, e1->c + e2->b)));
  res.c = gg_max(gg_min(e1->c + e2->c, gg_max(e1->d + e2->a, e1->c + e2->b)),
		 gg_min(e1->c + e2->c, gg_max(e1->a + e2->d, e1->b + e2->c)));
  res.d = gg_max(gg_max(e1->d + e2->b, e1->b + e2->d),
		 gg_min(e1->d + e2->c, e1->c + e2->d));

  /* The rules above give 0011 + 0002 = 0012, which is incorrect. Thus
   * we need this annoying exception.
   */
  if ((e1->d - e1->c == 2 && e2->c - e2->b == 1)
      || (e1->c - e1->b == 1 && e2->d - e2->c == 2)) {
    res.d = gg_max(gg_min(e1->c + e2->d, e1->d + e2->b),
		   gg_min(e1->d + e2->c, e1->b + e2->d));
  }

  /* The temporary storage in res is necessary if sum is the same as
   * e1 or e2.
   */
  sum->a = res.a;
  sum->b = res.b;
  sum->c = res.c;
  sum->d = res.d;
}

/* The impact on the number of eyes (counting up to two) if a vital
 * move is made. The possible values are
 * 0 - settled eye, no vital move
 * 2 - 1/2 eye or 3/2 eyes
 * 3 - 3/4 eyes or 5/4 eyes
 * 4 - 1* eyes (a chimera)
 */
int
eye_move_urgency(struct eyevalue *e)
{
  int a = gg_min(e->a, 2);
  int b = gg_min(e->b, 2);
  int c = gg_min(e->c, 2);
  int d = gg_min(e->d, 2);
  if (b == c)
    return 0;
  else
    return d + c - b - a;
}

/* Produces a string representing the eyevalue.
 * 
 * Note: the result string is stored in a statically allocated buffer
 * which will be overwritten the next time this function is called.
 */
char *
eyevalue_to_string(struct eyevalue *e)
{
  static char result[30];
  if (e->a < 10 && e->b < 10 && e->c < 10 && e->d < 10)
    gg_snprintf(result, 29, "%d%d%d%d", e->a, e->b, e->c, e->d);
  else
    gg_snprintf(result, 29, "[%d,%d,%d,%d]", e->a, e->b, e->c, e->d);
  return result;
}



/* Test whether the optics code evaluates an eyeshape consistently. */
void
test_eyeshape(int eyesize, int *eye_vertices)
{
  int k;
  int n, N;
  int mx[BOARDMAX];
  int pos;
  int str = NO_MOVE;
  int attack_code;
  int attack_point;
  int defense_code;
  int defense_point;
  int save_verbose;
  struct board_state starting_position;

  /* Clear the board and initialize the engine properly. */
  clear_board();
  reset_engine();

  /* Mark the eyespace in the mx array. */
  memset(mx, 0, sizeof(mx));
  for (k = 0; k < eyesize; k++) {
    ASSERT_ON_BOARD1(eye_vertices[k]);
    mx[eye_vertices[k]] = 1;
  }

  /* Play white stones surrounding the eyespace, including diagonals. */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (!ON_BOARD(pos) || mx[pos] == 1)
      continue;
    for (k = 0; k < 8; k++) {
      if (ON_BOARD(pos + delta[k]) && mx[pos + delta[k]] == 1) {
	play_move(pos, WHITE);
	str = pos;
	break;
      }
    }
  }

  /* Play black stones surrounding the white group, but leaving all
   * liberties empty.
   */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (mx[pos] == 1 || board[pos] != EMPTY || liberty_of_string(pos, str))
      continue;
    for (k = 0; k < 8; k++) {
      if (ON_BOARD(pos + delta[k])
	  && liberty_of_string(pos + delta[k], str)) {
	play_move(pos, BLACK);
	break;
      }
    }
  }

  /* Show the board if verbose is on. Then turn off traces so we don't
   * get any from make_worms(), make_dragons(), or the owl reading.
   */
  if (verbose)
    showboard(0);
  save_verbose = verbose;
  verbose = 0;
  
  
  /* Store this position so we can come back to it. */
  store_board(&starting_position);

  /* Loop over all configurations of black stones inserted in the
   * eyeshape. There are N = 2^(eyesize) configurations and we can
   * straightforwardly use binary representation to enumerate them.
   */
  N = 1 << eyesize;
  for (n = 0; n < N; n++) {
    int valid = 1;
    int internal_stones = 0;
    
    restore_board(&starting_position);
    /* Play the stones for this configuration. */
    for (k = 0; k < eyesize; k++) {
      if (n & (1 << k)) {
	if (!is_legal(eye_vertices[k], BLACK)) {
	  valid = 0;
	  break;
	}
	play_move(eye_vertices[k], BLACK);
	internal_stones++;
      }
    }

    if (!valid)
      continue;

    if (save_verbose > 1)
      showboard(0);

    /* Now we are ready to test the consistency. This is most easily
     * done with help from the owl code. First we must prepare for
     * this though.
     */
    examine_position(EXAMINE_DRAGONS_WITHOUT_OWL, 0);

    attack_code = owl_attack(str, &attack_point, NULL, NULL);

    if (attack_code == 0) {
      /* The owl code claims there is no attack. We test this by
       * trying to attack on all empty spaces in the eyeshape.
       */
      for (k = 0; k < eyesize; k++) {
	if (board[eye_vertices[k]] == EMPTY
	    && is_legal(eye_vertices[k], BLACK)
	    && owl_does_attack(eye_vertices[k], str, NULL)) {
	  gprintf("%1m alive, but %1m attacks:\n", str, eye_vertices[k]);
	  showboard(0);
	  gprintf("\n");
	}
      }

      /* Furthermore, if the eyespace is almost filled, white should
       * be able to play on the remaining eyespace point and still be
       * alive.
       */
      if (internal_stones == eyesize - 1) {
	for (k = 0; k < eyesize; k++) {
	  if (board[eye_vertices[k]] == EMPTY
	      && !owl_does_defend(eye_vertices[k], str, NULL)) {
	    gprintf("%1m alive, but almost filled with nakade:\n", str);
	    showboard(0);
	  }
	}
      }
    }
    else {
      defense_code = owl_defend(str, &defense_point, NULL, NULL);
      if (defense_code == 0) {
	/* The owl code claims there is no defense. We test this by
	 * trying to defend on all empty spaces in the eyeshape.
	 */
	for (k = 0; k < eyesize; k++) {
	  if (board[eye_vertices[k]] == EMPTY
	      && is_legal(eye_vertices[k], WHITE)
	      && owl_does_defend(eye_vertices[k], str, NULL)) {
	    gprintf("%1m dead, but %1m defends:\n", str, eye_vertices[k]);
	    showboard(0);
	    gprintf("\n");
	  }
	}
      }
      else {
	/* The owl code claims the dragon is critical. Verify the
         * attack and defense points.
	 */
	if (board[attack_point] != EMPTY
	    || !is_legal(attack_point, BLACK)) {
	  gprintf("Bad attack point %1m:\n", attack_point);
	  showboard(0);
	}
	else if (!owl_does_attack(attack_point, str, NULL)) {
	  gprintf("Attack point %1m failed:\n", attack_point);
	  showboard(0);
	}

	if (board[defense_point] != EMPTY
	    || !is_legal(defense_point, WHITE)) {
	  gprintf("Bad defense point %1m:\n", defense_point);
	  showboard(0);
	}
	else if (!owl_does_defend(defense_point, str, NULL)) {
	  gprintf("Defense point %1m failed:\n", defense_point);
	  showboard(0);
	}
      }
    }
  }
  verbose = save_verbose;
}

/********************************************************************
 * The following static functions are helpers for analyze_eyegraph()
 * further down. The purpose is to evaluate eye graphs according to
 * the rules for local games, as described in doc/eyes.texi.
 *
 * The technique to do this is to convert the eye evaluation problem
 * into a tactical style life and death reading problem. Tactical in
 * the sense of needing to decide whether certain stones can be
 * captured, but not in the sense of the tactical reading that five
 * liberties are considered safe.
 *
 * We illustrate how this works with an example. Consider the eye shape
 *
 *   !
 *  .X
 * !...
 *
 * The basic idea is to embed the eyespace in a perfectly connected
 * group without additional eyes or eye potential. This is most easily
 * done by the somewhat brutal trick to fill the entire board with
 * stones. We let the group consist of white stones (O) and get this
 * result, disregarding the two marginal eye vertices:
 *
 *    A B C D E F G H J K L M N O P Q R S T
 * 19 O O O O O O O O O O O O O O O O O O O 19
 * 18 O O O O O O O O O O O O O O O O O O O 18
 * 17 O O O O O O O O O O O O O O O O O O O 17
 * 16 O O O O O O O O O O O O O O O O O O O 16
 * 15 O O O O O O O O O O O O O O O O O O O 15
 * 14 O O O O O O O O O O O O O O O O O O O 14
 * 13 O O O O O O O O O O O O O O O O O O O 13
 * 12 O O O O O O O O . O O O O O O O O O O 12
 * 11 O O O O O O O . X O O O O O O O O O O 11
 * 10 O O O O O O . . . . O O O O O O O O O 10
 *  9 O O O O O O O O O O O O O O O O O O O 9
 *  8 O O O O O O O O O O O O O O O O O O O 8
 *  7 O O O O O O O O O O O O O O O O O O O 7
 *  6 O O O O O O O O O O O O O O O O O O O 6
 *  5 O O O O O O O O O O O O O O O O O O O 5
 *  4 O O O O O O O O O O O O O O O O O O O 4
 *  3 O O O O O O O O O O O O O O O O O O O 3
 *  2 O O O O O O O O O O O O O O O O O O O 2
 *  1 O O O O O O O O O O O O O O O O O O O 1
 *    A B C D E F G H J K L M N O P Q R S T
 *
 * The question now is whether black can capture all the white stones
 * under alternating play where only white may pass. However, first we
 * need to make the top and leftmost eye vertices marginal. This is
 * done by inserting small invincible black groups in the sea of white
 * stones, in contact with the marginal vertices.
 *
 *    A B C D E F G H J K L M N O P Q R S T
 * 19 . O O O O O O O O O O O O O O O O O O 19
 * 18 O O O O O O O O X X X O O O O O O O O 18
 * 17 O O O O O O O O X . X O O O O O O O O 17
 * 16 O O O O O O O O X X X O O O O O O O O 16
 * 15 O O O O O O O O X . X O O O O O O O O 15
 * 14 O O O O O O O O X X X O O O O O O O O 14
 * 13 O O O O O O O O X O O O O O O O O O O 13
 * 12 O O O O O O O O . O O O O O O O O O O 12
 * 11 O O O O O O O . X O O O O O O O O O O 11
 * 10 O O O O O O . . . . O O O O O O O O O 10
 *  9 O O O O O O X O O O O O O O O O O O O 9
 *  8 O O O O X X X O O O O O O O O O O O O 8
 *  7 O O O O X . X O O O O O O O O O O O O 7
 *  6 O O O O X X X O O O O O O O O O O O O 6
 *  5 O O O O X . X O O O O O O O O O O O O 5
 *  4 . O O O X X X O O O O O O O O O O O O 4
 *  3 X X . O O O O O O O O O O O O O O O O 3
 *  2 X . X O O O O O O O O O O O O O O O O 2
 *  1 . X X O O O O O O O O O O O O O O O O 1
 *    A B C D E F G H J K L M N O P Q R S T
 *
 * In this diagram we have also added an invincible black group in the
 * lower left corner in order to add two outer liberties (at A4 and
 * C3) for the white group (this is sometimes needed for the tactical
 * life and death reading to make sense). Furthermore there is an
 * extra eye at A19. This is used when we want to distinguish between
 * 0 and 1 (or 2) eyes since the tactical life and death reading by
 * itself only cares about two eyes or not. When trying to distinguish
 * between 1 (or 0) and 2 eyes we first fill in A19 again.
 *
 * Depending on the tactical life and death status with or without the
 * extra eye we can determine the number of eyes. By evaluating
 * tactical life and death status after having made a move we can also
 * identify ko threats and critical moves.
 *
 * This code is organized as follows:
 *
 * analyze_eyegraph() converts the eyegraph into the tactical board
 * position as demonstrated, then calls evaluate_eyespace() to its eye
 * value.
 *
 * white_area() is a helper to add a small invincible black group on
 * the board.
 *
 * evaluate_eyespace() calls tactical_life() and itself recursively to
 * determine the eye value and the critical points.
 *
 * tactical_life() determines whether the white stones on the board
 * (assumed to be a single string) can be captured under alternating
 * play.
 *
 * tactical_life_attack() and tactical_life_defend() are two mutually
 * recursive functions which perform the actual reading for
 * tactical_life().
 *
 * Worth to mention in this overview is also the cache used for
 * tactical_life_attack() and tactical_life_defend(). Since we have a
 * limited number of vertices (eye space points + two outer liberties
 * + possibly an extra eye) to play on we use a complete cache with a
 * unique entry for every possible configuration of stones on the
 * considered vertices.
 *
 * For each cache entry four bits are used, two for attack results and
 * two four defense results. Each of these can take the values 0-3
 * with the following interpretations:
 * 0 - not yet considered
 * 1 - result is being computed
 * 2 - result has been computed and was a failure (0)
 * 3 - result has been computed and was a success (1)
 */

/* Like trymove() except that it does a superko check. This does,
 * however, only disallow repetition (besides simple ko) if the move
 * does not capture any stones.
 */
static int
eyegraph_trymove(int pos, int color, const char *message, int str)
{
  static Hash_data remembered_board_hashes[MAXSTACK];
  int k;
  int does_capture = does_capture_something(pos, color);
  
  remembered_board_hashes[stackp] = board_hash;
  
  if (!trymove(pos, color, message, str))
    return 0;

  if (does_capture)
    return 1;

  for (k = 0; k < stackp; k++)
    if (hashdata_is_equal(board_hash, remembered_board_hashes[k])) {
      popgo();
      return 0;
    }

  return 1;
}

static int
eyegraph_is_margin_or_outer_liberty(int vertex)
{
  int k;
  int r;
  int num_libs;
  int libs[MAXLIBS];
  int eyes;
  
  for (k = 0; k < 4; k++) {
    if (board[vertex + delta[k]] == BLACK) {
      eyes = 0;
      num_libs = findlib(vertex + delta[k], MAXLIBS, libs);
      
      for (r = 0; r < num_libs; r++)
	if (is_suicide(libs[r], WHITE))
	  eyes++;
      
      if (eyes >= 2)
	return 1;
    }
  }
  return 0;
}

static int
eyegraph_order_moves(int num_vertices, int *vertices, int color_to_move, int *moves)
{
  int num_moves = 0;
  int scores[BOARDMAX];
  int move;
  int score;
  int k;
  int r;

  for (k = 0; k < num_vertices; k++) {
    if (k >= num_vertices - 3) {
      /* Never useful for white to fill in outer liberties or a second eye. */
      if (color_to_move == WHITE)
	break;
      /* No use playing the second outer liberty before the first one. */
      if (k == num_vertices - 2 && board[vertices[num_vertices - 3]] == EMPTY)
	continue;
    }
    
    move = vertices[k];
    score = 0;

    if (board[move] != EMPTY)
      continue;
    
    if (eyegraph_is_margin_or_outer_liberty(move)) {
      if (k < num_vertices - 3)
	score = 5; /* margin */
      else
	score = -10; /* outer liberty */
    }

    if (accuratelib(move, color_to_move, 2, NULL) == 1)
      score -= 3;
    
    for (r = 0; r < 4; r++) {
      if (board[move + delta[r]] == EMPTY)
	score += 2;
      else if (board[move + delta[r]] == BLACK)
	score += 3;
    }
    
    moves[num_moves] = move;
    scores[num_moves] = score;
    num_moves++;
  }

  for (k = 0; k < num_moves; k++) {
    int maxscore = scores[k];
    int max_at = 0;

    /* Find the move with the biggest score. */
    for (r = k + 1; r < num_moves; r++) {
      if (scores[r] > maxscore) {
	maxscore = scores[r];
	max_at = r;
      }
    }

    /* Now exchange the move at k with the move at max_at.
     * Don't forget to exchange the scores as well.
     */
    if (max_at != 0) {
      int temp = moves[max_at];
      moves[max_at] = moves[k];
      moves[k] = temp;
      temp = scores[max_at];
      scores[max_at] = scores[k];
      scores[k] = temp;
    }
  }
  
  return num_moves;
}

/* Place a small invincible black group on the board.
 * It is required that previously there were white stones at all
 * involved vertices and on the surrounding vertices.
 *
 * Returns 1 if a group was placed, 0 otherwise.
 */
static int
white_area(int mx[BOARDMAX], int pos, int up, int right, int marginpos,
	   int distance)
{
  int u, v;
  int k;
  int edge = is_edge_vertex(marginpos);

  for (k = 1; k < distance; k++)
    if (!ON_BOARD(marginpos + k * up)
	|| mx[marginpos + k * up] != WHITE)
      return 0;

  for (u = -1; u <= 4; u++)
    for (v = -1; v <= 4; v++) {
      int pos2 = pos + u * up + v * right;
      if (!ON_BOARD(pos2)) {
	if (!edge)
	  return 0;
	else if (u >= 0 && u <= 3 && v >= 0 && v <= 3)
	  return 0;
	else if (I(pos2) != I(NORTH(marginpos))
		 && I(pos2) != I(SOUTH(marginpos))
		 && J(pos2) != J(WEST(marginpos))
		 && J(pos2) != J(EAST(marginpos)))
	  return 0;
      }
      else if (mx[pos2] != WHITE)
	return 0;
    }
  
  for (u = 0; u <= 3; u++)
    for (v = 0; v <= 3; v++) {
      int pos2 = pos + u * up + v * right;
      mx[pos2] = BLACK;
    }

  mx[pos + up + right] = EMPTY;
  mx[pos + 2 * up + 2 * right] = EMPTY;

  return 1;
}


#define EYEGRAPH_RETURN(result, trace) \
  do { \
    if (sgf_dumptree) \
      sgftreeAddComment(sgf_dumptree, (trace)); \
    return (result); \
  } while (0);

static int tactical_life_defend(int str, int num_vertices, int *vertices,
				unsigned char *results);

/* Determine whether black can capture all white stones. */
static int
tactical_life_attack(int str, int num_vertices, int *vertices,
		     unsigned char *results)
{
  int k;
  int hash = 0;
  int cached_result;
  int result;
  int num_moves;
  int moves[BOARDMAX];

  /* Compute hash value to index the result cache with. */
  for (k = 0; k < num_vertices; k++) {
    hash *= 3;
    hash += board[vertices[k]];
  }
  hash *= 2;
  hash += (board_ko_pos != NO_MOVE);

  /* Is the result known from the cache? */
  cached_result = results[hash] & 3;

  if (0) {
    showboard(0);
    gprintf("%d %d (%d)\n", hash, cached_result, results[hash]);
  }
  
  if (cached_result == 2)
    EYEGRAPH_RETURN(0, "tactical_life_attack: 0 (cached)");
  if (cached_result == 3)
    EYEGRAPH_RETURN(1, "tactical_life_attack: win (cached)");
  if (cached_result == 1)
    EYEGRAPH_RETURN(1, "tactical_life_attack: win (open node in cache)");

  /* Mark this entry in the cache as currently being computed. */
  results[hash] |= 1;

  /* Try to play on all relevant vertices. */
  num_moves = eyegraph_order_moves(num_vertices, vertices,
				   OTHER_COLOR(board[str]), moves);
  for (k = 0; k < num_moves; k++) {
    int move = moves[k];
    if (eyegraph_trymove(move, OTHER_COLOR(board[str]),
	  		 "tactical_life_attack", str)) {
      /* We were successful if the white stones were captured or if no
       * defense can be found.
       */
      if (board[str] == EMPTY)
	result = 1;
      else
	result = !tactical_life_defend(str, num_vertices, vertices, results);
      
      popgo();

      if (result == 1) {
	/* Store the result (success) in the cache. */
	results[hash] = (results[hash] & (~3)) | 3;
	EYEGRAPH_RETURN(1, "tactical_life_attack: win");
      }
    }
  }
  
  /* Store the result (failure) in the cache. */
  results[hash] = (results[hash] & (~3)) | 2;
  EYEGRAPH_RETURN(0, "tactical_life_attack: 0");
}

/* Determine whether white can live with all stones. */
static int
tactical_life_defend(int str, int num_vertices, int *vertices,
		     unsigned char *results)
{
  int k;
  int hash = 0;
  int cached_result;
  int result;
  int num_moves;
  int moves[BOARDMAX];
  
  /* Compute hash value to index the result cache with. */
  for (k = 0; k < num_vertices; k++) {
    hash *= 3;
    ASSERT1(board[vertices[k]] <= 2, vertices[k]);
    hash += board[vertices[k]];
  }
  hash *= 2;
  hash += (board_ko_pos != NO_MOVE);
  
  /* Is the result known from the cache? */
  cached_result = (results[hash] >> 2) & 3;

  if (0) {
    showboard(0);
    gprintf("%d %d (%d)\n", hash, cached_result, results[hash]);
  }

  if (cached_result == 2)
    EYEGRAPH_RETURN(0, "tactical_life_defend: 0 (cached)");
  if (cached_result == 3)
    EYEGRAPH_RETURN(1, "tactical_life_defend: win (cached)");
  if (cached_result == 1)
    EYEGRAPH_RETURN(1, "tactical_life_defend: win (node open in cache)");

  /* Mark this entry in the cache as currently being computed. */
  results[hash] |= (1 << 2);

  /* Try to play on all relevant vertices. */
  num_moves = eyegraph_order_moves(num_vertices, vertices, board[str], moves);
  for (k = 0; k < num_moves; k++) {
    int move = moves[k];
    if ((!is_suicide(move, OTHER_COLOR(board[str]))
	 || does_capture_something(move, board[str]))
	&& eyegraph_trymove(move, board[str], "tactical_life_defend", str)) {
      /* We were successful if no attack can be found. */
      result = !tactical_life_attack(str, num_vertices, vertices, results);
      
      popgo();

      if (result == 1) {
	/* Store the result (success) in the cache. */
	results[hash] = (results[hash] & (~12)) | (3 << 2);
	EYEGRAPH_RETURN(1, "tactical_life_defend: win");
      }
    }
  }

  /* If no move worked, also try passing. */
  if (!tactical_life_attack(str, num_vertices, vertices, results)) {
    /* Store the result (success) in the cache. */
    results[hash] = (results[hash] & (~12)) | (3 << 2);
    EYEGRAPH_RETURN(1, "tactical_life_defend: win");
  }
  
  /* Store the result (failure) in the cache. */
  results[hash] = (results[hash] & (~12)) | (2 << 2);
  EYEGRAPH_RETURN(0, "tactical_life_defend: 0");
}

/* Determine the tactical life and death status of all white stones.
 * Also find all attack and defense moves. The parameter have_eye
 * determines whether the extra eye in the upper left corner should be
 * used or filled in before starting reading.
 */
static void
tactical_life(int have_eye, int num_vertices, int *vertices,
	      int *attack_code, int *num_attacks, int *attack_points,
	      int *defense_code, int *num_defenses, int *defense_points,
	      unsigned char *results)
{
  int k;
  int str;
  int num_moves;
  int moves[BOARDMAX];

  gg_assert(attack_code != NULL && defense_code != NULL);

  /* We know that the large white group includes A18. This is the
   * vertex we test to determine whether the white stones have been
   * captured.
   */
  str = POS(1, 0);

  if (board[str] == EMPTY) {
    /* The stones have already been captured, too late to defend. */
    *attack_code = WIN;
    *defense_code = 0;
    return;
  }

  /* Fill in the extra eye if have_eye is 0. If filling in would be
   * suicide the white stones can be considered dead.
   */
  if (!have_eye) {
    if (!eyegraph_trymove(POS(0, 0), WHITE, "tactical_life-A", NO_MOVE)) {
      *attack_code = WIN;
      *defense_code = 0;
      return;
    }
  }
  
  *attack_code = 0;
  *defense_code = 0;

  /* Call tactical_life_attack() and tactical_life_defend() to
   * determine status.
   */
  if (tactical_life_attack(str, num_vertices, vertices, results)) {
    *attack_code = WIN;
    if (tactical_life_defend(str, num_vertices, vertices, results))
      *defense_code = WIN;
  }
  else
    *defense_code = WIN;


  /* If the status is critical, try to play at each relevant vertex
   * and call tactical_life_defend() or tactical_life_attack() to
   * determine whether the move works as attack or defense.
   */
  if (*attack_code != 0 && *defense_code != 0) {
    if (num_attacks != NULL && attack_points != NULL) {
      *num_attacks = 0;
      num_moves = eyegraph_order_moves(num_vertices, vertices,
				       OTHER_COLOR(board[str]), moves);
      for (k = 0; k < num_moves; k++) {
	int move = moves[k];
	if (eyegraph_trymove(move, OTHER_COLOR(board[str]), "tactical_life-B",
			     str)) {
	  if (board[str] == EMPTY
	      || !tactical_life_defend(str, num_vertices, vertices, results))
	    attack_points[(*num_attacks)++] = move;
	  popgo();
	}
      }
    }

    if (num_defenses != NULL && defense_points != NULL) {
      *num_defenses = 0;
      num_moves = eyegraph_order_moves(num_vertices, vertices, board[str],
				       moves);
      for (k = 0; k < num_moves; k++) {
	int move = moves[k];
	if (eyegraph_trymove(move, board[str], "tactical_life-C", str)) {
	  if (!tactical_life_attack(str, num_vertices, vertices, results))
	    defense_points[(*num_defenses)++] = move;
	  popgo();
	}
      }
    }
  }

  /* Unfill the extra eye if we didn't use it. */
  if (!have_eye)
    popgo();
}

/* Determine the eye value of the eyespace for the big white group on
 * the board and vital moves. The possible eye values are documented
 * in the preamble to eyes.db. By calling tactical_life() multiple
 * times, with and without using an extra eye, we can compute the eye
 * values. To determine ko threats and vital moves, tactical_life() is
 * called again after trying to play on one of the relevant vertices.
 * In order to find out whether ko threats really are effective and to
 * distinguish between 0122/1122 and 0012/0011 eye values (see
 * discussion on pattern 6141 in the preamble of eyes.db), we may also
 * need to recursively call ourselves after a move has been made.
 */
static void
evaluate_eyespace(struct eyevalue *result, int num_vertices, int *vertices,
		  int *num_vital_attacks, int *vital_attacks,
		  int *num_vital_defenses, int *vital_defenses,
		  unsigned char *tactical_life_results)
{
  int k;
  int attack_code;
  int num_attacks;
  int attack_points[BOARDMAX];
  int defense_code;
  int num_defenses;
  int defense_points[BOARDMAX];
  int attack_code2;
  int num_attacks2;
  int attack_points2[BOARDMAX];
  int defense_code2;
  struct eyevalue result2;
  int num_vital_attacks2;
  int vital_attacks2[BOARDMAX];
  int num_vital_defenses2;
  int vital_defenses2[BOARDMAX];
  int num_moves;
  int moves[BOARDMAX];

  *num_vital_attacks = 0;
  *num_vital_defenses = 0;

  /* Determine tactical life without an extra eye. */
  tactical_life(0, num_vertices, vertices,
		&attack_code, &num_attacks, attack_points,
		&defense_code, &num_defenses, defense_points,
		tactical_life_results);

  if (attack_code == 0) {
    /* Alive without extra eye.
     * Possible results: 0222, 1222, 2222
     *
     * Determine whether there are ko threats and how serious.
     */
    int a = 2;

    if (sgf_dumptree)
      sgftreeAddComment(sgf_dumptree, "Alive without extra eye.\n");
    
    num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves);
    for (k = 0; k < num_moves; k++) {
      int acode, dcode;
      int move = moves[k];
      if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-A", NO_MOVE)) {
	tactical_life(0, num_vertices, vertices, &acode, NULL, NULL,
		      &dcode, NULL, NULL, tactical_life_results);
	if (acode != 0) {
	  tactical_life(1, num_vertices, vertices, &acode, NULL, NULL,
			&dcode, NULL, NULL, tactical_life_results);
	  if (acode != 0) {
	    if (a == 1)
	      *num_vital_attacks = 0;
	    a = 0;
	    vital_attacks[(*num_vital_attacks)++] = move;
	    if (sgf_dumptree)
	      sgftreeAddComment(sgf_dumptree,
				"Ko threat to remove both eyes.\n");
	  }
	  else {
	    if (a != 0) {
	      vital_attacks[(*num_vital_attacks)++] = move;
	      a = 1;
	    }
	    if (sgf_dumptree)
	      sgftreeAddComment(sgf_dumptree, "Ko threat to remove one eye.\n");
	  }
	}
	popgo();
      }
    }
    set_eyevalue(result, a, 2, 2, 2);
    if (sgf_dumptree) {
      if (a == 0)
	sgftreeAddComment(sgf_dumptree, "Eyevalue 0222.\n");
      else if (a == 1)
	sgftreeAddComment(sgf_dumptree, "Eyevalue 1222.\n");
      else
	sgftreeAddComment(sgf_dumptree, "Eyevalue 2222.\n");
    }
  }
  else if (defense_code != 0) {
    /* Critical without extra eye.
     * Possible results: 0022, 0122, 1122
     */
    if (sgf_dumptree)
      sgftreeAddComment(sgf_dumptree, "Critical without extra eye.\n");
    tactical_life(1, num_vertices, vertices,
		  &attack_code2, &num_attacks2, attack_points2,
		  &defense_code2, NULL, NULL, tactical_life_results);
    for (k = 0; k < num_defenses; k++)
      vital_defenses[(*num_vital_defenses)++] = defense_points[k];
    if (attack_code2 == WIN) {
      /* A chimera. 0022. */
      set_eyevalue(result, 0, 0, 2, 2);
      for (k = 0; k < num_attacks2; k++)
	vital_attacks[(*num_vital_attacks)++] = attack_points2[k];
      if (sgf_dumptree)
	sgftreeAddComment(sgf_dumptree, "Eyevalue: 0022.\n");
    }
    else {
      int a = 1;
      for (k = 0; k < num_attacks; k++) {
	int move = attack_points[k];
	if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-B", NO_MOVE)) {
	  evaluate_eyespace(&result2, num_vertices, vertices,
			    &num_vital_attacks2, vital_attacks2,
			    &num_vital_defenses2, vital_defenses2,
			    tactical_life_results);
	  /* If result2 is 0011 for some move we have 0122 as final
           * result, otherwise 1122.
	   */
	  if (min_eyes(&result2) == 0
	      && max_eyes(&result2) == 1
	      && max_eye_threat(&result2) == 1) {
	    if (a == 1)
	      *num_vital_attacks = 0;
	    a = 0;
	    vital_attacks[(*num_vital_attacks)++] = move;
	  }
	  else if (a == 1)
	    vital_attacks[(*num_vital_attacks)++] = move;
	  popgo();
	}
      }
      set_eyevalue(result, a, 1, 2, 2);
      if (sgf_dumptree) {
	if (a == 0)
	  sgftreeAddComment(sgf_dumptree, "Eyevalue: 0122.\n");
	else
	  sgftreeAddComment(sgf_dumptree, "Eyevalue: 1122.\n");
      }	  
    }
  }
  else {
    /* Dead without extra eye.
     * Possible results: 0000, 0001, 0002, 0011, 0012, 0111, 0112, 1111, 1112
     *
     * Now determine tactical life with an extra eye.
     */
    if (sgf_dumptree)
      sgftreeAddComment(sgf_dumptree, "Dead without extra eye.\n");
    tactical_life(1, num_vertices, vertices,
		  &attack_code, &num_attacks, attack_points,
		  &defense_code, &num_defenses, defense_points,
		  tactical_life_results);
    if (attack_code == 0) {
      /* Alive with extra eye.
       * Possible results: 0111, 0112, 1111, 1112
       */
      int a = 1;
      int d = 1;
      if (sgf_dumptree)
	sgftreeAddComment(sgf_dumptree, "Alive with extra eye.\n");
      num_moves = eyegraph_order_moves(num_vertices, vertices, BLACK, moves);
      for (k = 0; k < num_moves; k++) {
	int acode, dcode;
	int move = moves[k];
	if (eyegraph_trymove(move, BLACK, "evaluate_eyespace-C", NO_MOVE)) {
	  tactical_life(1, num_vertices, vertices, &acode, NULL, NULL,
			&dcode, NULL, NULL, tactical_life_results);
	  if (acode != 0) {
	    evaluate_eyespace(&result2, num_vertices, vertices,
			      &num_vital_attacks2, vital_attacks2,
			      &num_vital_defenses2, vital_defenses2,
			      tactical_life_results);
	    /* This is either 0011 or 0012. Only the first is acceptable. */
	    if (max_eye_threat(&result2) == 1) {
	      vital_attacks[(*num_vital_attacks)++] = move;
	      a = 0;
	      if (sgf_dumptree)
		sgftreeAddComment(sgf_dumptree, "Attacking ko threat.\n");
	    }
	  }
	  popgo();
	}
      }
      
      num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves);
      for (k = 0; k < num_moves; k++) {
	int acode, dcode;
	int move = moves[k];
	if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-D", NO_MOVE)) {
	  tactical_life(0, num_vertices, vertices, &acode, NULL, NULL,
			&dcode, NULL, NULL, tactical_life_results);
	  if (dcode != 0) {
	    evaluate_eyespace(&result2, num_vertices, vertices,
			      &num_vital_attacks2, vital_attacks2,
			      &num_vital_defenses2, vital_defenses2,
			      tactical_life_results);
	    /* This is either 1122 or 0122. Only the first is acceptable. */
	    if (min_eye_threat(&result2) == 1) {
	      vital_defenses[(*num_vital_defenses)++] = move;
	      d = 2;
	      if (sgf_dumptree)
		sgftreeAddComment(sgf_dumptree, "Defending ko threat.\n");
	    }
	  }
	  popgo();
	}
      }
      set_eyevalue(result, a, 1, 1, d);
      if (sgf_dumptree) {
	if (a == 0 && d == 1)
	  sgftreeAddComment(sgf_dumptree, "Eyevalue 0111.\n");
	else if (a == 0 && d == 2)
	  sgftreeAddComment(sgf_dumptree, "Eyevalue 0112.\n");
	else if (a == 1 && d == 1)
	  sgftreeAddComment(sgf_dumptree, "Eyevalue 1111.\n");
	else
	  sgftreeAddComment(sgf_dumptree, "Eyevalue 1112.\n");
      }
    }
    else if (defense_code != 0) {
      /* Critical with extra eye.
       * Possible results: 0011, 0012
       */
      int d = 1;
      if (sgf_dumptree)
	sgftreeAddComment(sgf_dumptree, "Critical with extra eye.\n");
      for (k = 0; k < num_attacks; k++)
	vital_attacks[(*num_vital_attacks)++] = attack_points[k];
      for (k = 0; k < num_defenses; k++) {
	int move = defense_points[k];
	if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-E", NO_MOVE)) {
	  evaluate_eyespace(&result2, num_vertices, vertices,
			    &num_vital_attacks2, vital_attacks2,
			    &num_vital_defenses2, vital_defenses2,
			    tactical_life_results);
	  /* If result2 is 1122 for some move we have 0012 as final
           * result, otherwise 0011.
	   */
	  if (min_eye_threat(&result2) == 1
	      && min_eyes(&result2) == 1
	      && max_eyes(&result2) == 2) {
	    if (d == 1)
	      *num_vital_defenses = 0;
	    d = 2;
	    vital_defenses[(*num_vital_defenses)++] = move;
	  }
	  else if (d == 1)
	    vital_defenses[(*num_vital_defenses)++] = move;
	  popgo();
	}
      }
      set_eyevalue(result, 0, 0, 1, d);
      if (sgf_dumptree) {
	if (d == 1)
	  sgftreeAddComment(sgf_dumptree, "Eyevalue: 0011.\n");
	else
	  sgftreeAddComment(sgf_dumptree, "Eyevalue: 0012.\n");
      }	  
    }
    else {
      /* Dead with extra eye.
       * Possible results: 0000, 0001, 0002
       *
       * Determine whether there are ko threats and how serious.
       */
      int d = 0;
      if (sgf_dumptree)
	sgftreeAddComment(sgf_dumptree, "Dead with extra eye.\n");
      num_moves = eyegraph_order_moves(num_vertices, vertices, WHITE, moves);
      for (k = 0; k < num_moves; k++) {
	int acode, dcode;
	int move = moves[k];
	if (eyegraph_trymove(move, WHITE, "evaluate_eyespace-F", NO_MOVE)) {
	  tactical_life(1, num_vertices, vertices, &acode, NULL, NULL,
			&dcode, NULL, NULL, tactical_life_results);
	  if (dcode != 0) {
	    tactical_life(0, num_vertices, vertices, &acode, NULL, NULL,
			  &dcode, NULL, NULL, tactical_life_results);
	    if (dcode != 0) {
	      if (d == 1)
		*num_vital_defenses = 0;
	      d = 2;
	      vital_defenses[(*num_vital_defenses)++] = move;
	      if (sgf_dumptree)
		sgftreeAddComment(sgf_dumptree,
				  "Ko threat to make two eyes.\n");
	    }
	    else {
	      if (d != 2) {
		vital_defenses[(*num_vital_defenses)++] = move;
		d = 1;
	      }
	      if (sgf_dumptree)
		sgftreeAddComment(sgf_dumptree,
				  "Ko threat to make one eye.\n");
	    }
	  }
	  popgo();
	}
      }
      set_eyevalue(result, 0, 0, 0, d);
      if (sgf_dumptree) {
	if (d == 0)
	  sgftreeAddComment(sgf_dumptree, "Eyevalue 0000.\n");
	else if (d == 1)
	  sgftreeAddComment(sgf_dumptree, "Eyevalue 0001.\n");
	else
	  sgftreeAddComment(sgf_dumptree, "Eyevalue 0002.\n");
      }
    }
  }
}

/* Add small invincible black groups in contact with the marginal
 * vertices, without destroying the connectivity of the white stones.
 *
 */
static int
add_margins(int num_margins, int *margins, int mx[BOARDMAX])
{
  int k;
  int i, j;
  int old_mx[BOARDMAX];
  int pos;

  if (num_margins == 0)
    return 1;
  
  memcpy(old_mx, mx, sizeof(old_mx));
  
  pos = margins[num_margins - 1];

  for (k = 0; k < 4; k++) {
    int up = delta[k];
    int right = delta[(k + 1) % 4];
    
    if (!ON_BOARD(pos + up))
      continue;
    
    if (mx[pos + up] == WHITE
	&& (!ON_BOARD(pos + up + right) || mx[pos + up + right] == WHITE)
	&& (!ON_BOARD(pos + up - right) || mx[pos + up - right] == WHITE)) {
      for (i = -3; i <= 0; i++) {
	for (j = 2; j < 6; j++) {
	  if (white_area(mx, pos + j * up + i * right, up, right, pos, j)) {
	    int s = 1;
	    while (mx[pos + s * up] == WHITE) {
	      mx[pos + s * up] = BLACK;
	      s++;
	    }
	    if (add_margins(num_margins - 1, margins, mx))
	      return 1;
	    else
	      memcpy(mx, old_mx, sizeof(old_mx));
	  }
	}
      }
    }
  }

  return 0;
}

/* Analyze an eye graph to determine the eye value and vital moves.
 *
 * The eye graph is given by a string which is encoded with "%" for
 * newlines and "O" for spaces. E.g., the eye graph
 *
 *   !
 *  .X
 * !...
 *
 * is encoded as "OO!%O.X%!...". (The encoding is needed for the GTP
 * interface to this function.)
 *
 * The result is an eye value and a (nonencoded) pattern showing the
 * vital moves, using the same notation as eyes.db. In the example above
 * we would get the eye value 0112 and the graph (showing ko threat moves)
 *
 *   @  
 *  .X  
 * !.*.
 *
 * If the eye graph cannot be realized, 0 is returned, 1 otherwise.
 */
int
analyze_eyegraph(const char *coded_eyegraph, struct eyevalue *value,
		 char *analyzed_eyegraph)
{
  int k;
  int i, j;
  int mini, minj;
  int mx[BOARDMAX];
  char mg[BOARDMAX];
  int pos;

  int num_vital_attacks;
  int vital_attacks[BOARDMAX]; /* Way larger than necessary. */
  int num_vital_defenses;
  int vital_defenses[BOARDMAX]; /* Way larger than necessary. */
  
  int maxwidth;
  int current_width;
  int num_rows;
  int horizontal_edge;
  int vertical_edge;

  int num_margins;
  int margins[BOARDMAX]; /* Way larger than necessary. */

  int num_vertices;
  int vertices[BOARDMAX]; /* Way larger than necessary. */

  int table_size;
  unsigned char *tactical_life_results;

  if (0)
    gprintf("Analyze eyegraph %s\n", coded_eyegraph);
  
  /* Mark the eyespace in the mx array. We construct the position in
   * the mx array and copy it to the actual board later.
   */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (ON_BOARD(pos))
      mx[pos] = WHITE;

  /* Find out the size of the eye graph pattern so that we can center
   * it properly.
   */
  maxwidth = 0;
  current_width = 0;
  num_rows = 1;
  horizontal_edge = -1;
  vertical_edge = -1;
  for (k = 0; k < (int) strlen(coded_eyegraph); k++) {
    if (coded_eyegraph[k] == '\n')
      continue;
    if (coded_eyegraph[k] == '%') {
      num_rows++;
      if (current_width > maxwidth)
	maxwidth = current_width;
      current_width = 0;
    }
    else {
      if (coded_eyegraph[k] == '-')
	horizontal_edge = num_rows - 1;
      else if (coded_eyegraph[k] == '|')
	vertical_edge = current_width;
      current_width++;
    }
  }
  if (current_width > maxwidth)
    maxwidth = current_width;

  /* Cut out the eyespace from the solid white string. */
  num_margins = 0;
  num_vertices = 0;
  
  if (horizontal_edge == 0)
    mini = -1;
  else if (horizontal_edge > 0)
    mini = board_size - num_rows + 1;
  else
    mini = (board_size - num_rows) / 2;

  if (vertical_edge == 0)
    minj = -1;
  else if (vertical_edge > 0)
    minj = board_size - maxwidth + 1;
  else
    minj = (board_size - maxwidth) / 2;
  
  i = mini;
  j = minj;
  for (k = 0; k < (int) strlen(coded_eyegraph); k++) {
    char c = coded_eyegraph[k];
    if (c == '\n')
      continue;
    if (c == '%') {
      i++;
      j = minj - 1;
    }
    else if (c == 'X' || c == '$')
      mx[POS(i, j)] = BLACK;
    else if (c == '.' || c == '*' || c == '<' || c == '>'
	     || c == '!' || c == '@' || c == '(' || c == ')')
      mx[POS(i, j)] = EMPTY;
    if (c == '!' || c == '@' || c == '(' || c == ')' || c == '$')
      margins[num_margins++] = POS(i, j);
    if (c != '|' && c != '-' && c != '+' && c != '%'
	&& ON_BOARD(POS(i, j)) && mx[POS(i, j)] != WHITE)
      vertices[num_vertices++] = POS(i, j);
    j++;
  }

  /* Add an invincible black group in the lower left plus two outer
   * liberties for the white string. However, if the eyespace is
   * placed in or near the lower left corner, we put this group in the
   * upper right instead.
   */
  pos = POS(board_size - 2, 1);
  if ((vertical_edge == 0 && horizontal_edge != 0)
      || (horizontal_edge > 0 && vertical_edge <= 0))
    pos = POS(1, board_size - 2);
  mx[pos] = EMPTY;
  mx[NORTH(pos)] = BLACK;
  mx[NW(pos)] = BLACK;
  mx[NE(pos)] = EMPTY;
  mx[WEST(pos)] = BLACK;
  mx[EAST(pos)] = BLACK;
  mx[SW(pos)] = EMPTY;
  mx[SOUTH(pos)] = BLACK;
  mx[SE(pos)] = BLACK;
  if (ON_BOARD(NN(pos)))
    mx[NN(pos)] = EMPTY;
  else
    mx[SS(pos)] = EMPTY;

  /* Add the two outer liberties in the lower left or upper right to
   * the list of vertices.
   */
  if (ON_BOARD(NN(pos))) {
    vertices[num_vertices++] = NE(pos);
    vertices[num_vertices++] = NN(pos);
  }
  else {
    vertices[num_vertices++] = SW(pos);
    vertices[num_vertices++] = SS(pos);
  }

  /* Add an extra eye in the upper left corner. */
  mx[POS(0, 0)] = EMPTY;
  vertices[num_vertices++] = POS(0, 0);

  if (!add_margins(num_margins, margins, mx))
    return 0;

  /* Copy the mx array over to the board. */
  clear_board();
  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (ON_BOARD(pos)) {
      if (mx[pos] == WHITE)
	add_stone(pos, WHITE);
      else if (mx[pos] == BLACK)
	add_stone(pos, BLACK);
    }

  if (verbose)
    showboard(0);

  /* If there are any isolated O stones, those should also be added to
   * the playable vertices.
   */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (board[pos] == WHITE && !same_string(pos, POS(1, 0))) {
      vertices[num_vertices] = vertices[num_vertices - 1];
      vertices[num_vertices - 1] = vertices[num_vertices - 2];
      vertices[num_vertices - 2] = vertices[num_vertices - 3];
      vertices[num_vertices - 3] = pos;
      num_vertices++;
    }

  if (verbose) {
    int k;
    gprintf("\nPlayable vertices:\n");
    for (k = 0; k < num_vertices; k++)
      gprintf("%1m ", vertices[k]);
    gprintf("\n\n");
  }
  
  /* Disable this test if you need to evaluate larger eyespaces, have
   * no shortage of memory, and know what you're doing.
   */
  if (num_vertices > 17) {
    gprintf("analyze_eyegraph: too large eyespace, %d vertices\n",
	    num_vertices);
    gg_assert(num_vertices <= 17);
  }

  /* The cache must have 2*3^num_vertices entries. */
  table_size = 2;
  for (k = 0; k < num_vertices; k++)
    table_size *= 3;

  /* Allocate memory for the cache. */
  tactical_life_results = malloc(table_size);
  if (!tactical_life_results) {
    gprintf("analyze_eyegraph: failed to allocate %d bytes\n", table_size);
    gg_assert(tactical_life_results != NULL);
  }
  memset(tactical_life_results, 0, table_size);

  if (sgf_dumptree)
    sgffile_printboard(sgf_dumptree);
  
  /* Evaluate the eyespace on the board. */
  evaluate_eyespace(value, num_vertices, vertices,
		    &num_vital_attacks, vital_attacks,
		    &num_vital_defenses, vital_defenses,
		    tactical_life_results);

  /* Return the cache memory. */
  free(tactical_life_results);

  if (verbose) {
    gprintf("Eyevalue: %s\n", eyevalue_to_string(value));
    for (k = 0; k < num_vital_attacks; k++)
      gprintf("  vital attack point %1m\n", vital_attacks[k]);
    for (k = 0; k < num_vital_defenses; k++)
      gprintf("  vital defense point %1m\n", vital_defenses[k]);
  }

  /* Encode the attack and defense points with symbols in the mg[] array. */
  memset(mg, ' ', sizeof(mg));

  for (k = 0; k < num_vertices - 2; k++)
    mg[vertices[k]] = (board[vertices[k]] == BLACK ? 'X' : '.');

  for (k = 0; k < num_margins; k++)
    mg[margins[k]] = (mg[margins[k]] == 'X' ? '$' : '!');

  for (k = 0; k < num_vital_attacks; k++)
    mg[vital_attacks[k]] = (mg[vital_attacks[k]] == '!' ? '(' : '<');

  for (k = 0; k < num_vital_defenses; k++) {
    int pos = vital_defenses[k];
    if (mg[pos] == '.')
      mg[pos] = '>';
    else if (mg[pos] == '!')
      mg[pos] = ')';
    else if (mg[pos] == '<')
      mg[pos] = '*';
    else if (mg[pos] == '(')
      mg[pos] = '@';
  }

  /* Return the central part of the mg[] array (corresponding to the
   * input eye graph).
   */
  k = 0;
  for (i = mini; i < mini + num_rows; i++) {
    for (j = minj; j < minj + maxwidth; j++) {
      if ((i < 0 || i >= board_size) && (j < 0 || j >= board_size))
	analyzed_eyegraph[k++] = '+';
      else if (i < 0 || i >= board_size)
	analyzed_eyegraph[k++] = '-';
      else if (j < 0 || j >= board_size)
	analyzed_eyegraph[k++] = '|';
      else
	analyzed_eyegraph[k++] = mg[POS(i, j)];
    }
    analyzed_eyegraph[k++] = '\n';
  }
  analyzed_eyegraph[k - 1] = 0;
  
  return 1;
}


/*
 * Local Variables:
 * tab-width: 8
 * c-basic-offset: 2
 * End:
 */
