/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 * 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 "influence.h"
#include "patterns.h"
#include "gg_utils.h"

static void add_influence_source(int pos, int color, float strength,
                                 float attenuation,
                                 struct influence_data *q);
static void print_influence(const struct influence_data *q,
			    const char *info_string);
static void print_numeric_influence(const struct influence_data *q,
				    const float values[BOARDMAX],
				    const char *format, int width,
				    int draw_stones, int mark_epsilon);
static void print_influence_areas(const struct influence_data *q);
 
static void value_territory(struct influence_data *q);
static void enter_intrusion_source(int source_pos, int strength_pos,
                                   float strength, float attenuation,
                                   struct influence_data *q);
static void add_marked_intrusions(struct influence_data *q);
 

/* Influence computed for the initial position, i.e. before making
 * some move.
 */
struct influence_data initial_black_influence;
struct influence_data initial_white_influence;

/* Influence computed after some move has been made. */
struct influence_data move_influence;
struct influence_data followup_influence;

/* Influence used for estimation of escape potential. */
static struct influence_data escape_influence;

/* Pointer to influence data used during pattern matching. */
static struct influence_data *current_influence = NULL;


/* Thresholds values used in the whose_moyo() functions */
static struct moyo_determination_data moyo_data;
static struct moyo_determination_data moyo_restricted_data;
 
/* Thresholds value used in the whose_territory() function */
static float territory_determination_value; 
 


/* This curve determines how much influence is needed at least to claim
 * an intersection as territory, in dependence of the "center value".
 * (In the center, more effort is needed to get territory!)
 * The center value is at the moment defined as follows:
 * If d1, d2 are the distance to vertical and horizontal border, resp.,
 * with d1<d2, then
 * central = 3 * d1 + min(d2, 4)
 * So this is mainly a function of the distance to the border; the
 * distance to the second-nearest border gives a small correction of at
 * most 4. This distinguishes edge and corner positions.
 *
 * The values for intersections close to a corner or to the edge have
 * to be consistent such that standard corner enclosure etc. are
 * sufficient to claim territory. The center values are more arbitrary
 * suspect to tuning.
 */

static struct interpolation_data min_infl_for_territory =
  { 6,  0.0, 24.0, { 6.0, 15.0, 26.0, 36.0, 45.0, 50.0, 55.0 }};

/* Determines the territory correction factor in dependence of the ratio
 * ( influence of stronger color / min_infl_for_territory(intersection))
 */
static struct interpolation_data territory_correction = 
  { 5, (float) 0.0, 1.0, {0.0, 0.25, 0.45, 0.65, 0.85, 1.0}};





/* If set, print influence map when computing this move. Purely for
 * debugging.
 */
static int debug_influence = NO_MOVE;

/* Assigns an id to all influence computations for reference in the
 * delta territory cache.
 */
static int influence_id = 0;

/* This is the core of the influence function. Given the coordinates
 * and color of an influence source, it radiates the influence
 * outwards until it hits a barrier or the strength of the influence
 * falls under a certain threshold.
 *
 * The radiation is performed by a breadth first propagation,
 * implemented by means of an internal queue.
 *
 * Since this function has turned out be one of the bottlenecks, loop
 * unrolling makes a noticeable performance difference. It does,
 * however, make the code much harder to read and maintain. Therefore
 * we include both the original and the unrolled versions.
 */

#define EXPLICIT_LOOP_UNROLLING 1

#if EXPLICIT_LOOP_UNROLLING
/* In addition to the parameters, this macro expects
 *  m,n = original source of influence
 *  ii = point influence is being spread from
 *  delta_i = I(ii) - m
 *  delta_j = J(ii) - n
 *  current_strength combines strength and damping factor
 *  b is 1/(square of distance from m,n to i,j) ; or halved
 *    for diagonals
 * 
 *  arg is i + arg_di ; arg_j is j + arg_dj
 *  arg_d is 1 for diagonal movement
 *
 */


#define code1(arg_di, arg_dj, arg, arg_d) do { \
      if (!q->safe[arg] \
	  && ((arg_di)*(delta_i) + (arg_dj)*(delta_j) > 0 \
	      || queue_start == 1)) { \
	float contribution; \
	float permeability = permeability_array[ii]; \
	if (arg_d) { \
	  permeability *= gg_max(permeability_array[ii + DELTA(arg_di, 0)], \
			         permeability_array[ii + DELTA(0, arg_dj)]); \
	  if (permeability == 0.0) \
	    continue; \
	} \
	contribution = current_strength * permeability; \
	if (queue_start != 1) { \
	  int a = (arg_di)*(delta_i) + (arg_dj)*(delta_j); \
	  contribution *= (a*a) * b; /* contribution *= cos(phi) */ \
	} \
	if (contribution <= INFLUENCE_CUTOFF) \
	  continue; \
	if (working[arg] == 0.0) { \
	  q->queue[queue_end] = (arg); \
	  queue_end++; \
	} \
	working[arg] += contribution; \
      } } while (0) 
#endif


static void
accumulate_influence(struct influence_data *q, int pos, int color)
{
  int ii;
  int m = I(pos);
  int n = J(pos);
  int k;
#if !EXPLICIT_LOOP_UNROLLING
  int d;
#endif
  float b;
  float inv_attenuation;
  float inv_diagonal_damping;
  float *permeability_array;

  /* Clear the queue. Entry 0 is implicitly (m, n). */
  int queue_start = 0;
  int queue_end = 1;

  static float working[BOARDMAX];
  static int working_area_initialized = 0;

  if (!working_area_initialized) {
    for (ii = 0; ii < BOARDMAX; ii++)
      working[ii] = 0.0;
    working_area_initialized = 1;
  }

  if (0)
    gprintf("Accumulating influence for %s at %m\n",
	    color_to_string(color), m, n);

  /* Attenuation only depends on the influence origin. */
  if (color == WHITE)
    inv_attenuation = 1.0 / q->white_attenuation[pos];
  else
    inv_attenuation = 1.0 / q->black_attenuation[pos];

  if (q->is_territorial_influence)
    inv_diagonal_damping = 1.0 / TERR_DIAGONAL_DAMPING;
  else
    inv_diagonal_damping = 1.0 / DIAGONAL_DAMPING;

  if (color == WHITE)
    permeability_array = q->white_permeability;
  else
    permeability_array = q->black_permeability;

  /* We put the original source into slot 0.  */
  q->queue[0] = pos;
    
  if (color == WHITE)
    working[pos] = q->white_strength[pos];
  else
    working[pos] = q->black_strength[pos];


  /* Spread influence until the stack is empty. */
  while (queue_start < queue_end) {
    float current_strength;
    int delta_i, delta_j;

    ii = q->queue[queue_start];
    delta_i = I(ii) - m;
    delta_j = J(ii) - n;
    queue_start++;
    if (permeability_array[ii] == 0.0)
      continue;
    if (0)
      gprintf("Picked %1m from queue. w=%f start=%d end=%d\n",
	      ii, working[ii], queue_start, queue_end);
    if (queue_start == 1)
      b = 1.0;
    else
      b = 1.0 / ((delta_i)*(delta_i) + (delta_j)*(delta_j));

    current_strength = working[ii] * inv_attenuation;

#if !EXPLICIT_LOOP_UNROLLING
    /* Try to spread influence in each of the eight directions. */    
    for (d = 0; d < 8; d++) {
      int di = deltai[d];
      int dj = deltaj[d];
      int d_ii = delta[d];

      /* Verify that (ii + d_ii) is
       * 1. Inside the board.
       * 2. Not occupied.
       * 3. Directed outwards. For the origin all directions are outwards.
       */
      if (ON_BOARD(ii + d_ii)
      	  && (!q->safe[ii + d_ii])
	  && (di*(delta_i) + dj*(delta_j) > 0
	      || queue_start == 1)) {

	float contribution;
	float permeability = permeability_array[ii];
	float dfactor;
	float inv_damping;

	/* Now compute the damping of the influence.
	 * First we have the permeability at the point we are
	 * spreading from. For diagonal movement we also take the
	 * permeability of the vertices we are "passing by" into
	 * account.
	 */
	if (d > 3) { /* diagonal movement */
	  permeability *= gg_max(permeability_array[ii + DELTA(di, 0)],
				 permeability_array[ii + DELTA(0, dj)]);
	  inv_damping = inv_diagonal_damping;
	  dfactor = 0.5;
	}
	else {
	  inv_damping = 1.0;
	  dfactor = 1.0;
	}

	if (permeability == 0.0)
	  continue;

	contribution = permeability * current_strength * inv_damping;

	/* Finally direction dependent damping. */
	if (ii != pos) {
	  int a = di*(delta_i) + dj*(delta_j);
	  gg_assert(a > 0);
	  contribution *= (a*a) * b * dfactor;
	}

	/* Stop spreading influence if the contribution becomes too low. */
	if (contribution <= INFLUENCE_CUTOFF)
	  continue;
	
	/* If no influence here before, add the point to the queue for
	 * further spreading.
	 */
	if (0)
	  gprintf("  Spreading %s influence from %1m to %1m, d=%d\n",
		  color_to_string(color), ii, ii + d_ii, d);
	if (working[ii + d_ii] == 0.0) {
	  q->queue[queue_end] = ii + d_ii;
	  queue_end++;
	}
	working[ii + d_ii] += contribution;
      }
    }
#else
    if (ON_BOARD(ii + delta[0]))
      code1(deltai[0], deltaj[0], ii + delta[0], 0);
    if (ON_BOARD(ii + delta[1]))
      code1(deltai[1], deltaj[1], ii + delta[1], 0);
    if (ON_BOARD(ii + delta[2]))
      code1(deltai[2], deltaj[2], ii + delta[2], 0);
    if (ON_BOARD(ii + delta[3]))
      code1(deltai[3], deltaj[3], ii + delta[3], 0);

    /* Update factors for diagonal movement. */
    b *= 0.5;
    current_strength *= inv_diagonal_damping;

    if (ON_BOARD(ii + delta[4]))
      code1(deltai[4], deltaj[4], ii + delta[4], 1);
    if (ON_BOARD(ii + delta[5]))
      code1(deltai[5], deltaj[5], ii + delta[5], 1);
    if (ON_BOARD(ii + delta[6]))
      code1(deltai[6], deltaj[6], ii + delta[6], 1);
    if (ON_BOARD(ii + delta[7]))
      code1(deltai[7], deltaj[7], ii + delta[7], 1);
#endif
  }
  
  /* Add the values in the working area to the accumulated influence
   * and simultaneously reset the working area. We know that all
   * influenced points were stored in the queue, so we just traverse
   * it.
   */
  for (k = 0; k < queue_end; k++) {
    ii = q->queue[k];

    if (color == WHITE) {
      if (working[ii] > 1.01 * INFLUENCE_CUTOFF
	  || q->white_influence[ii] == 0.0)
	q->white_influence[ii] += working[ii];
    }
    else {
      if (working[ii] > 1.01 * INFLUENCE_CUTOFF
	  || q->black_influence[ii] == 0.0)
	q->black_influence[ii] += working[ii];
    }
    
    working[ii] = 0.0;
  }
}



/* Initialize the influence_data structure.  */

static void
init_influence(struct influence_data *q,
	       const signed char safe_stones[BOARDMAX], 
	       const float strength[BOARDMAX])
{
  int ii;
  float attenuation;
  
  /* Initialisation of some global positional values, based on 
   * game stage. 
   */
  if (cosmic_gnugo) {
    float t;
    if ((board_size != 19) || (movenum <= 2) || ((movenum / 2) % 2))
      cosmic_importance = 0.0;
    else {
      cosmic_importance = 1.0 - (movenum / 150.0)*(movenum / 150.0); 
      cosmic_importance = gg_max(0.0, cosmic_importance);
    }

    t = cosmic_importance;
    
    moyo_data.influence_balance     = t * 15.0  +  (1.0-t) * 5.0;  
    moyo_data.my_influence_minimum  = t * 5.0   +  (1.0-t) * 5.0;
    moyo_data.opp_influence_maximum = t * 30.0  +  (1.0-t) * 30.0;
    
    /* we use the same values for moyo and moyo_restricted */
    moyo_restricted_data = moyo_data;

    territory_determination_value   = t * 0.95 +  (1.0-t) * 0.95; 
      
    min_infl_for_territory.values[0] = t * 6.0   +  (1.0-t) * 10.0;
    min_infl_for_territory.values[1] = t * 10.0  +  (1.0-t) * 15.0;
    min_infl_for_territory.values[2] = t * 20.0  +  (1.0-t) * 15.0;
    min_infl_for_territory.values[3] = t * 20.0  +  (1.0-t) * 20.0;
    min_infl_for_territory.values[4] = t * 20.0  +  (1.0-t) * 20.0;
    min_infl_for_territory.values[5] = t * 15.0  +  (1.0-t) * 15.0;
    min_infl_for_territory.values[6] = t * 10.0  +  (1.0-t) * 15.0;   
  }
  else {  
    /* non-cosmic values */
    cosmic_importance = 0.0;
  
    moyo_data.influence_balance     = 7.0;
    moyo_data.my_influence_minimum  = 5.0;
    moyo_data.opp_influence_maximum = 10.0;
    
    moyo_restricted_data.influence_balance     = 10.0;
    moyo_restricted_data.my_influence_minimum  = 10.0;
    moyo_restricted_data.opp_influence_maximum = 10.0;
    
    territory_determination_value = 0.95;
    
    min_infl_for_territory.values[0] = 6.0;
    min_infl_for_territory.values[1] = 15.0;
    min_infl_for_territory.values[2] = 26.0;
    min_infl_for_territory.values[3] = 36.0;
    min_infl_for_territory.values[4] = 45.0;
    min_infl_for_territory.values[5] = 50.0;
    min_infl_for_territory.values[6] = 55.0; 
  }
  
  if (q->is_territorial_influence)
    attenuation = TERR_DEFAULT_ATTENUATION;
  else
    attenuation = 2 * DEFAULT_ATTENUATION;
  
  q->intrusion_counter = 0;

  /* Remember this for later. */
  memcpy(q->safe, safe_stones, BOARDMAX * sizeof(*safe_stones));
  q->captured = black_captured - white_captured;
  
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)) {
      /* Initialize. */
      q->white_influence[ii] = 0.0;
      q->black_influence[ii] = 0.0;
      q->white_attenuation[ii] = attenuation;
      q->black_attenuation[ii] = attenuation;
      q->white_permeability[ii] = 1.0;
      q->black_permeability[ii] = 1.0;
      q->white_strength[ii] = 0.0;
      q->black_strength[ii] = 0.0;
      q->non_territory[ii] = EMPTY;

      if (IS_STONE(board[ii])) {
	if (!safe_stones[ii]) {
	  if (board[ii] == WHITE)
	    q->white_permeability[ii] = 0.0;
	  else
	    q->black_permeability[ii] = 0.0;
	}
	else {
	  if (board[ii] == WHITE) {
	    if (strength)
	      q->white_strength[ii] = strength[ii];
	    else
	      q->white_strength[ii] = DEFAULT_STRENGTH;
	    q->black_permeability[ii] = 0.0;
	  }
	  else {
	    if (strength)
	      q->black_strength[ii] = strength[ii];
	    else
	      q->black_strength[ii] = DEFAULT_STRENGTH;
	    q->white_permeability[ii] = 0.0;
	  }
	}
      }
      else
	/* Ideally, safe_stones[] should always be zero for empty
	 * intersections. This is currently, however, sometimes not true
	 * when an inessential worm gets captured. So we revise this
	 * in our private copy here.
	 */
	q->safe[ii] = 0;
    }
}


/* Adds an influence source at position pos with prescribed strength
 * and attenuation. color can be BLACK, WHITE or both. If there
 * already exists an influence source of the respective color at pos
 * that is stronger than the new one, we do nothing.
 */
static void
add_influence_source(int pos, int color, float strength, float attenuation,
                     struct influence_data *q)
{
  if ((color & WHITE) && (q->white_strength[pos] < strength)) {
    q->white_strength[pos] = strength;
    q->white_attenuation[pos] = attenuation;
  }
  
  if ((color & BLACK) && (q->black_strength[pos] < strength)) {
    q->black_strength[pos] = strength;
    q->black_attenuation[pos] = attenuation;
  }
}

/* Adds an intrusion as an entry in the list q->intrusions.  */
static void
enter_intrusion_source(int source_pos, int strength_pos,
                       float strength, float attenuation,
                       struct influence_data *q)
{
  if (q->intrusion_counter >= MAX_INTRUSIONS) {
    DEBUG(DEBUG_INFLUENCE, "intrusion list exhausted\n");
    return;
  }
  q->intrusions[q->intrusion_counter].source_pos = source_pos;
  q->intrusions[q->intrusion_counter].strength_pos = strength_pos;
  q->intrusions[q->intrusion_counter].strength = strength;
  q->intrusions[q->intrusion_counter].attenuation = attenuation;
  q->intrusion_counter++;
}

/* Comparison of intrusions datas, to sort them. */
static int
compare_intrusions(const void *p1, const void *p2)
{
  const struct intrusion_data *intr1 = p1;
  const struct intrusion_data *intr2 = p2;
  if (intr1->source_pos - intr2->source_pos != 0)
    return (intr1->source_pos - intr2->source_pos);
  else if (intr1->strength_pos - intr2->strength_pos != 0)
    return (intr1->strength_pos - intr2->strength_pos);
  else if (intr1->strength > intr2->strength)
    return 1;
  else
    return -1;
}

/* It may happen that we have a low intensity influence source at a
 * blocked intersection (due to an intrusion). This function resets the
 * permeabilities.
 */
static void
reset_unblocked_blocks(struct influence_data *q)
{
  int pos;
  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (ON_BOARD(pos)) {
      if (!q->safe[pos] && q->white_strength[pos] > 0.0
	  && q->white_permeability[pos] != 1.0) {
	DEBUG(DEBUG_INFLUENCE, "  black block removed from %1m\n", pos);
	q->white_permeability[pos] = 1.0;
      }
      if (!q->safe[pos] && q->black_strength[pos] > 0.0
	  && q->black_permeability[pos] != 1.0) {
	DEBUG(DEBUG_INFLUENCE, "  white block removed from %1m\n", pos);
	q->black_permeability[pos] = 1.0;
      }
    }
}


/* This function goes through the list of intrusion sources, and adds
 * the intrusion as influence sources for color. The strength is
 * corrected so that each stone's intrusions sources can have total
 * strength of at most 60%/100% of the strength of the stone.
 * (100% is if q == &followup_influence, 60% otherwise).
 */
static void
add_marked_intrusions(struct influence_data *q)
{
  int i;
  int j = 0;
  int source_pos;
  float strength_sum;
  float correction;
  float source_strength;
  float allowed_strength;
  int color = q->color_to_move;

  gg_sort(q->intrusions, q->intrusion_counter, sizeof(q->intrusions[0]),
          compare_intrusions);

  /* Go through all intrusion sources. */
  for (i = 0; i < q->intrusion_counter; i = j) {
    strength_sum = 0.0;
    source_pos = q->intrusions[i].source_pos;
    /* "Anonymous" intrusios go in uncorrected. */
    if (source_pos == NO_MOVE) {
      add_influence_source(q->intrusions[i].strength_pos, color,
                           q->intrusions[j].strength,
                           q->intrusions[j].attenuation, q);
      DEBUG(DEBUG_INFLUENCE, "Adding %s intrusion at %1m, value %f\n",
	    (color == BLACK) ? "black" : "white",
	    q->intrusions[j].strength_pos, q->intrusions[j].strength);
      j = i+1;
      continue;
    }
    if (color == BLACK)
      source_strength = q->black_strength[source_pos];
    else
      source_strength = q->white_strength[source_pos];

    /* First loop: Determine correction factor. */
    for (j = i; (j < q->intrusion_counter)
                 && (q->intrusions[j].source_pos == source_pos); j++) {
      /* Of identical strength positions, only take strongest value. */
      if (j == i
          || q->intrusions[j].strength_pos != q->intrusions[j-1].strength_pos)
        strength_sum += q->intrusions[j].strength;
    }
    if (q == &followup_influence)
      allowed_strength = source_strength;
    else
      allowed_strength = 0.6 * source_strength;
    if (strength_sum > allowed_strength)
      correction = (allowed_strength / strength_sum);
    else
      correction = 1.0;

    /* Second loop: Add influence sources. */
    for (j = i; (j < q->intrusion_counter)
                 && (q->intrusions[j].source_pos == source_pos); j++) {
      /* Of identical strenght positions, only take strongest value. */
      if (j == i || q->intrusions[j].strength_pos
                    != q->intrusions[j-1].strength_pos) {
        add_influence_source(q->intrusions[j].strength_pos, color,
                             correction * q->intrusions[j].strength,
                             q->intrusions[j].attenuation, q);
        DEBUG(DEBUG_INFLUENCE,
              "Adding %s intrusion for %1m at %1m, value %f (correction %f)\n",
              (color == BLACK) ? "black" : "white", source_pos,
              q->intrusions[j].strength_pos,
              correction * q->intrusions[j].strength, correction);
      }
    }
  }
}

/* Callback for the matched patterns in influence.db and barriers.db.
 * The pattern classes used here are:
 * A - Barrier pattern, where O plays first and X tries to block influence.
 * D - Barrier pattern, where O plays first and O tries to block influence.
 * B - Intrusion patterns, adding a low intensity influence source.
 * E - Enhance patterns, FIXME: document this one!
 * t - Non-territory patterns, marking vertices as not territory.
 * I - Invasion patterns, adding a low intensity influence source. 
 * e - Escape bonus. Used together with I to increase the value substantially
 *     if escape influence is being computed.
 *
 * Classes A, D, and B are matched with color as O, and it is assumed
 * that O is in turn to move. Classes E and I are matched with either
 * color as O.
 */
static void
influence_callback(int anchor, int color, struct pattern *pattern, int ll,
		   void *data)
{
  int pos = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
  int k;
  struct influence_data *q = data;
  
  /* We also ignore enhancement patterns in territorial influence. */
  if ((pattern->class & CLASS_E) && q->is_territorial_influence)
    return;

  /* Don't use invasion (I) patterns when scoring. */
  if (doing_scoring && (pattern->class & CLASS_I))
    return;
  
  /* Loop through pattern elements to see if an A or D pattern
   * can possibly have any effect. If not we can skip evaluating
   * constraint and/or helper.
   */
  if (pattern->class & (CLASS_A | CLASS_D)) {
    int something_to_do = 0;
    gg_assert(q->is_territorial_influence);
    for (k = 0; k < pattern->patlen; ++k) { /* match each point */
      int blocking_color;
      int ii;
      /* The order of elements is: All commas, all "!", then other. */
      if (pattern->patn[k].att != ATT_comma
	  && pattern->patn[k].att != ATT_not)
	break;  

      ii = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);

      if (pattern->class & CLASS_D)
	blocking_color = color;
      else
	blocking_color = OTHER_COLOR(color);
      if ((blocking_color == WHITE
	   && q->black_permeability[ii] != 0.0)
	  || (blocking_color == BLACK
	      && q->white_permeability[ii] != 0.0)) {
	something_to_do = 1;
	break;
      }
    }
    if (!something_to_do)
      return;
  }

  /* Require that all O stones in the pattern have non-zero influence
   * strength for patterns of type D, E, B, t, and all X stones have
   * non-zero strength for patterns of type A and t.
   *
   * Patterns also having class s are an exception from this rule.
   */
  if ((pattern->class & (CLASS_D | CLASS_A | CLASS_B | CLASS_E | CLASS_t))
      && !(pattern->class & CLASS_s)) {
    for (k = 0; k < pattern->patlen; ++k) { /* match each point */
      int ii = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
      if (pattern->patn[k].att == ATT_O) {
	if ((pattern->class & (CLASS_B | CLASS_t | CLASS_E | CLASS_D))
	    && ((color == WHITE && q->white_strength[ii] == 0.0)
	        || (color == BLACK && q->black_strength[ii] == 0.0)))
	  return;
      }
      else if (pattern->patn[k].att == ATT_X) {
	if ((pattern->class & (CLASS_A | CLASS_t))
	    && ((color == BLACK && q->white_strength[ii] == 0.0)
	        || (color == WHITE && q->black_strength[ii] == 0.0)))
	  return; /* Match failed. */
      }
    }
  }

  /* If the pattern has a constraint, call the autohelper to see
   * if the pattern must be rejected.
   */
  if ((pattern->autohelper_flag & HAVE_CONSTRAINT)
      && !pattern->autohelper(ll, pos, color, 0))
    return;

  DEBUG(DEBUG_INFLUENCE, "influence pattern '%s'+%d matched at %1m\n",
	pattern->name, ll, anchor);

  /* For t patterns, everything happens in the action. */
  if ((pattern->class & CLASS_t)
      && (pattern->autohelper_flag & HAVE_ACTION)) {
    pattern->autohelper(ll, pos, color, INFLUENCE_CALLBACK);
    return;
  }
  
  /* For I patterns, add a low intensity, both colored, influence
   * source at *.
   */
  if (pattern->class & CLASS_I) {
    int this_color = EMPTY;
    float strength;
    float attenuation;

    if (q->color_to_move == EMPTY || (pattern->class & CLASS_s))
      this_color = BLACK | WHITE;
    else if (q->color_to_move != color)
      this_color = q->color_to_move;
      
    if (cosmic_gnugo) {
      float t = 0.15 + (1.0 - cosmic_importance);
      t = gg_min(1.0, t);
      t = gg_max(0.0, t);
      strength = t * pattern->value;  
      attenuation = 1.6;
    }
    else {
      strength = pattern->value;  
      attenuation = 1.5;
    }

    /* Increase strength if we're computing escape influence. */
    if (!q->is_territorial_influence && (pattern->class & CLASS_e))
      add_influence_source(pos, this_color, 20 * strength, attenuation, q);
    else
      add_influence_source(pos, this_color, strength, attenuation, q);

    DEBUG(DEBUG_INFLUENCE,
	  "  low intensity influence source at %1m, strength %f, color %C\n",
	  pos, strength, this_color);
    return;
  }
    
  /* For E patterns, add a new influence source of the same color and
   * pattern defined strength at *.
   */
  if (pattern->class & CLASS_E) {
    add_influence_source(pos, color, pattern->value, DEFAULT_ATTENUATION, q);
    DEBUG(DEBUG_INFLUENCE,
	  "  extra %C source at %1m, strength %f\n", color,
	  pos, pattern->value);
    return;
  }

  /* For B patterns add intrusions sources at "!" points. */
  if (pattern->class & CLASS_B) {
    float strength;
    if (cosmic_gnugo) {
      float t = 0.15 + (1.0 - cosmic_importance);
      t = gg_min(1.0, t);
      t = gg_max(0.0, t);
      strength = t * pattern->value;
    }
    else 
      strength = pattern->value;
    
    for (k = 0; k < pattern->patlen; ++k)  /* match each point */
      if (pattern->patn[k].att == ATT_not) {
	/* transform pattern real coordinate */
	int ii = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);

	/* Low intensity influence source for the color in turn to move. */  
	if (q->is_territorial_influence)
	  enter_intrusion_source(anchor, ii, strength, 
				 TERR_DEFAULT_ATTENUATION, q);
	else
	  add_influence_source(ii, color, strength, DEFAULT_ATTENUATION, q); 
	DEBUG(DEBUG_INFLUENCE, "  intrusion at %1m\n", ii);
      }
    return;
  }
  

  gg_assert(pattern->class & (CLASS_D | CLASS_A));
  /* For A, D patterns, add blocks for all "," or "!" points.  */
  for (k = 0; k < pattern->patlen; ++k) { /* match each point */
    if (pattern->patn[k].att == ATT_comma
	|| pattern->patn[k].att == ATT_not) {
      /* transform pattern real coordinate */
      int ii = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
      int blocking_color;
      if (pattern->class & CLASS_D)
	blocking_color = color;
      else
	blocking_color = OTHER_COLOR(color);
      DEBUG(DEBUG_INFLUENCE, "  barrier for %s influence at %1m\n",
	    color_to_string(OTHER_COLOR(blocking_color)), ii);
      if (pattern->patn[k].att == ATT_comma) {
	if (blocking_color == WHITE)
	  q->black_permeability[ii] = 0.0;
	else
	  q->white_permeability[ii] = 0.0;
      }
      /* Weak barrier at !-marked points. */
      else {
	if (blocking_color == WHITE)
	  q->black_permeability[ii] *= 0.7;
	else
	  q->white_permeability[ii] *= 0.7;
	
      }
    }
  }
}

/* Callback for matched barriers patterns in followup influence.
 * This adds an intrusion source for all B patterns in barriers.db for
 * the color that has made a move if all the following conditions are
 * fulfilled:
 * - the anchor ("Q") is adjacent (directly or diagonally) to a "saved stone"
 *  (this is ensured by matchpat before calling back here)
 * - at least one of the O stones in the pattern is a saved stone.
 * - the usual pattern constraint ("; oplay_attack_either(...)") is fulfilled
 * - the pattern action (typically ">return (!xplay_attack(...))") returns
 *   true if  called with parameter action = FOLLOWUP_INFLUENCE_CALLBACK.
 * "Saved stones" are: the move played + tactically rescued stones + stones
 *                     in a critcal dragon brought to life by this move
 */
static void
followup_influence_callback(int anchor, int color, struct pattern *pattern,
                            int ll, void *data)
{
  int k;
  int t;
  struct influence_data *q = data;
  UNUSED(color);
 
  /* We use only B  patterns in followup influence. */
  if (!(pattern->class & CLASS_B))
    return;

  t = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);

  /* If the pattern has a constraint, call the autohelper to see
   * if the pattern must be rejected.
   */
  if (pattern->autohelper_flag & HAVE_CONSTRAINT
      && !pattern->autohelper(ll, t, color, 0))
    return;

  /* Actions in B patterns are used as followup specific constraints. */
  if ((pattern->autohelper_flag & HAVE_ACTION)
      && !pattern->autohelper(ll, t, color, FOLLOWUP_INFLUENCE_CALLBACK))
    return;

  DEBUG(DEBUG_INFLUENCE, "influence pattern '%s'+%d matched at %1m\n",
	pattern->name, ll, anchor);

  for (k = 0; k < pattern->patlen; ++k)  /* match each point */
    if (pattern->patn[k].att == ATT_not) {
      /* transform pattern real coordinate */
      int ii = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);

      /* Low intensity influence source for the color in turn to move. */
      enter_intrusion_source(anchor, ii, pattern->value,
			     TERR_DEFAULT_ATTENUATION, q);
      DEBUG(DEBUG_INFLUENCE, "  followup for %1m: intrusion at %1m\n",
            anchor, ii);
    }
}

/* Called from actions for t patterns. Marks (pos) as not being
 * territory for (color).
 */
void
influence_mark_non_territory(int pos, int color)
{
  DEBUG(DEBUG_INFLUENCE, "  non-territory for %C at %1m\n", color, pos);
  current_influence->non_territory[pos] |= color;
}

/* Erases all territory for color at (pos), and all directly neighboring
 * fields.
 */
void
influence_erase_territory(struct influence_data *q, int pos, int color)
{
  int k;
  ASSERT1((color == WHITE && q->territory_value[pos] >= 0.0)
          || (color == BLACK && q->territory_value[pos] <= 0.0), pos);

  current_influence = q;

  q->territory_value[pos] = 0.0;
  influence_mark_non_territory(pos, color);
  for (k = 0; k < 4; k++) {
    if (ON_BOARD(pos + delta[k])) {
      q->territory_value[pos + delta[k]] = 0.0;
      influence_mark_non_territory(pos + delta[k], color);
    }
  }
}

/* Match the patterns in influence.db and barriers.db in order to add:
 * - influence barriers,
 * - extra influence sources at possible invasion and intrusion points, and
 * - extra influence induced by strong positions.
 * Reduce permeability around each living stone.
 * Reset permeability to 1.0 at intrusion points.
 */
static void
find_influence_patterns(struct influence_data *q)
{
  int ii;

  current_influence = q;
  matchpat(influence_callback, ANCHOR_COLOR, &influencepat_db, q, NULL);
  if (q->color_to_move != EMPTY)
    matchpat(influence_callback, q->color_to_move, &barrierspat_db, q, NULL);

  if (q->is_territorial_influence)
    add_marked_intrusions(q);

  /* Additionally, we introduce a weaker kind of barriers around living
   * stones.
   */
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii) && !q->safe[ii]) {
      int k;
      float black_reduction = 1.0;
      float white_reduction = 1.0;
      for (k = 0; k < 8; k++) {
	int d = delta[k];
	if (IS_STONE(board[ii + d]) && q->safe[ii + d]) {
	  /* Reduce less diagonally. */
	  float reduction = (k < 4) ? 0.25 : 0.65;
	  if (board[ii + d] == BLACK)
	    white_reduction *= reduction;
	  else
	    black_reduction *= reduction;
	}
	else if (IS_STONE(board[ii + d]) && !q->safe[ii + d]) {
	  if (board[ii + d] == BLACK)
	    white_reduction = -100.0;
	  else
	    black_reduction = -100.0;
	}
      }
      if (black_reduction > 0.0)
	q->black_permeability[ii] *= black_reduction;
      if (white_reduction > 0.0)
	q->white_permeability[ii] *= white_reduction;
    }

  reset_unblocked_blocks(q);
}

/* This function checks whether we have two or more adjacent blocks for
 * influence of color next to pos. If yes, it returns the position of the
 * least valuable blocks; otherwise, it returns NO_MOVE.
 */
static int
check_double_block(int color, int pos, const struct influence_data *q)
{
  int k;
  int block_neighbors = 0;
  const float *permeability = ((color == BLACK) ? q->black_permeability :
						  q->white_permeability);

  /* Count neighboring blocks. */
  for (k = 0; k < 4; k++)
    if (board[pos + delta[k]] == EMPTY && permeability[pos + delta[k]] == 0.0)
      block_neighbors++;

  if (block_neighbors >= 2) {
    /* Search for least valuable block. */
    float smallest_value = 4.0 * MAX_BOARD * MAX_BOARD;
    int smallest_block = NO_MOVE;
    /* We count opponent's territory as positive. */
    float sign = ((color == WHITE) ? -1.0 : 1.0);
    for (k = 0; k < 4; k++) {
      int neighbor = pos + delta[k];
      if (board[neighbor] == EMPTY && permeability[neighbor] == 0.0) {
	/* Value is sum of opponents territory at this and all 4 neighboring
	 * intersections.
	 */
	float this_value = sign * q->territory_value[neighbor];
	int j;
	for (j = 0; j < 4; j++)
	  if (ON_BOARD(neighbor + delta[j]))
	    this_value += sign * q->territory_value[neighbor + delta[j]];
	/* We use an artifical tie breaker to avoid possible platform
	 * dependency.
	 */
	if (this_value + 0.0005 < smallest_value) {
	  smallest_block = neighbor;
	  smallest_value = this_value;
	}
      }
    }
    ASSERT1(ON_BOARD1(smallest_block), pos);
    return smallest_block;
  }
  return NO_MOVE;
}

#define MAX_DOUBLE_BLOCKS 20 


/* This function checks for the situation where an influence source for
 * the color to move is direclty neighbored by 2 or more influence blocks.
 * It then removes the least valuable of these blocks, and re-runs the
 * influence accumulation for this position.
 *
 * See endgame:840 for an example where this is essential.
 */
static void
remove_double_blocks(struct influence_data *q,
    		     const signed char inhibited_sources[BOARDMAX])
{
  int ii;
  float *strength = ((q->color_to_move == WHITE) ? q->white_strength :
      						   q->black_strength);
  int double_blocks[MAX_DOUBLE_BLOCKS];
  int num_blocks = 0;
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (board[ii] == EMPTY
	&& !(inhibited_sources && inhibited_sources[ii])
	&& strength[ii] > 0.0) {
      double_blocks[num_blocks] = check_double_block(q->color_to_move, ii, q);
      if (double_blocks[num_blocks] != NO_MOVE) {
	num_blocks++;
	if (num_blocks == MAX_DOUBLE_BLOCKS)
	  break;
      }
    }
  {
    int k;
    float *permeability = ((q->color_to_move == BLACK)
			   ? q->black_permeability : q->white_permeability);
    for (k = 0; k < num_blocks; k++) {
      DEBUG(DEBUG_INFLUENCE, "Removing block for %s at %1m.\n",
	    color_to_string(q->color_to_move), double_blocks[k]);
      permeability[double_blocks[k]] = 1.0;
      accumulate_influence(q, double_blocks[k], q->color_to_move);
    }
  }
}


/* Do the real work of influence computation. This is called from
 * compute_influence and compute_escape_influence.
 *
 * q->is_territorial_influence and q->color_to_move must be set by the caller.
 */
static void
do_compute_influence(const signed char safe_stones[BOARDMAX],
		     const signed char inhibited_sources[BOARDMAX],
    		     const float strength[BOARDMAX], struct influence_data *q,
		     int move, const char *trace_message)
{
  int ii;
  init_influence(q, safe_stones, strength);

  modify_depth_values(stackp - 1);
  find_influence_patterns(q);
  modify_depth_values(1 - stackp);
  
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii) && !(inhibited_sources && inhibited_sources[ii])) {
      if (q->white_strength[ii] > 0.0)
	accumulate_influence(q, ii, WHITE);
      if (q->black_strength[ii] > 0.0)
	accumulate_influence(q, ii, BLACK);
    }

  value_territory(q);
  remove_double_blocks(q, inhibited_sources);

  value_territory(q);
  
  if ((move == NO_MOVE
       && (printmoyo & PRINTMOYO_INITIAL_INFLUENCE))
      || (debug_influence && move == debug_influence))
    print_influence(q, trace_message);
}


/* Compute the influence values for both colors.
 * 
 * The caller must
 * - set up the board[] state
 * - mark safe stones with INFLUENCE_SAFE_STONE, dead stones with 0
 * - mark stones newly saved by a move with INFLUENCE_SAVED_STONE
 *   (this is relevant if the influence_data *q is reused to compute
 *   a followup value for this move).
 *
 * Results will be stored in q.
 *
 * (move) has no effects except toggling debugging. Set it to -1
 * for no debug output at all (otherwise it will be controlled by
 * the -m command line option).
 *
 * It is assumed that color is in turn to move. (This affects the
 * barrier patterns (class A, D) and intrusions (class B)). Color
 */

void
compute_influence(int color, const signed char safe_stones[BOARDMAX],
    	          const float strength[BOARDMAX], struct influence_data *q,
		  int move, const char *trace_message)
{
  int save_debug = debug;
  VALGRIND_MAKE_WRITABLE(q, sizeof(*q));

  q->is_territorial_influence = 1;
  q->color_to_move = color;

  /* Turn off DEBUG_INFLUENCE for influence computations we are not
   * interested in.
   */
  if ((move == NO_MOVE
       && !(printmoyo & PRINTMOYO_INITIAL_INFLUENCE))
      || (move != NO_MOVE && move != debug_influence))
    debug = debug &~ DEBUG_INFLUENCE;

  influence_id++;
  q->id = influence_id;

  do_compute_influence(safe_stones, NULL, strength,
		       q, move, trace_message);

  debug = save_debug;
}

/* Return the color of the territory at (pos). If it's territory for
 * neither color, EMPTY is returned.
 */
int
whose_territory(const struct influence_data *q, int pos)
{
  float bi = q->black_influence[pos];
  float wi = q->white_influence[pos];
  float terr = q->territory_value[pos];

  ASSERT_ON_BOARD1(pos);

  if (bi > 0.0 && wi == 0.0 && terr < -territory_determination_value)
     return BLACK;
  if (wi > 0.0 && bi == 0.0 && terr > territory_determination_value)
     return WHITE;

  return EMPTY;
}


/* Return the color who has a moyo at (pos). If neither color has a
 * moyo there, EMPTY is returned. The definition of moyo in terms of the
 * influences is totally ad hoc.
 */
int
whose_moyo(const struct influence_data *q, int pos)
{
  float bi = q->black_influence[pos];
  float wi = q->white_influence[pos];

  int territory_color = whose_territory(q, pos);
  if (territory_color != EMPTY)
    return territory_color;
    
  if (bi > moyo_data.influence_balance * wi
      && bi > moyo_data.my_influence_minimum
      && wi < moyo_data.opp_influence_maximum)
    return BLACK;
  if (wi > moyo_data.influence_balance * bi
      && wi > moyo_data.my_influence_minimum
      && bi < moyo_data.opp_influence_maximum)
    return WHITE;
  
  return EMPTY;
}

/* Return the color who has a moyo at (pos). If neither color has a
 * moyo there, EMPTY is returned.
 * The definition of moyo in terms of the influences is totally ad
 * hoc.
 *
 * It has a slightly different definition of moyo than whose_moyo.
 */
int
whose_moyo_restricted(const struct influence_data *q, int pos)
{
  float bi = q->black_influence[pos];
  float wi = q->white_influence[pos];

  int territory_color = whose_territory(q, pos);

  /* default */
  if (territory_color != EMPTY)
    return territory_color;
  else if (bi > moyo_restricted_data.influence_balance * wi
           && bi > moyo_restricted_data.my_influence_minimum
           && wi < moyo_restricted_data.opp_influence_maximum)
    return BLACK;
  else if (wi > moyo_restricted_data.influence_balance * bi
           && wi > moyo_restricted_data.my_influence_minimum
           && bi < moyo_restricted_data.opp_influence_maximum)
    return WHITE; 
  else
    return EMPTY;
}


/* Return the color who has dominating influence ("area") at (pos).
 * If neither color dominates the influence there, EMPTY is returned.
 * The definition of area in terms of the influences is totally ad
 * hoc.
 */
int
whose_area(const struct influence_data *q, int pos)
{
  float bi = q->black_influence[pos];
  float wi = q->white_influence[pos];

  int moyo_color = whose_moyo(q, pos);
  if (moyo_color != EMPTY)
    return moyo_color;
  
  if (bi > 3.0 * wi && bi > 1.0 && wi < 40.0)
    return BLACK;

  if (wi > 3.0 * bi && wi > 1.0 && bi < 40.0)
    return WHITE;
  
  return EMPTY;
}

 
static void
value_territory(struct influence_data *q)
{
  int ii;
  int dist_i, dist_j;
  float central;
  float first_guess[BOARDMAX];
  float ratio;
  int k;

  memset(first_guess, 0, BOARDMAX*sizeof(float));
  memset(q->territory_value, 0, BOARDMAX*sizeof(float));
  /* First loop: guess territory directly from influence. */
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)
	&& !q->safe[ii]) {
      float diff = 0.0;
      if (q->white_influence[ii] + q->black_influence[ii] > 0)
	diff = (q->white_influence[ii] - q->black_influence[ii])
	       / (q->white_influence[ii] + q->black_influence[ii]);
      first_guess[ii] = diff * diff * diff;

      /* If both side have small influence, we have to reduce this value.
       * What we consider "small influence" depends on how central this
       * intersection lies.
       *
       * The values of central on an 11x11 board become:
       *
       *  4  5  6  7  7  7  7  7  6  5  4
       *  5  8  9 10 10 10 10 10  9  8  5
       *  6  9 12 13 13 13 13 13 12  9  6
       *  7 10 13 16 16 16 16 16 13 10  7
       *  7 10 13 16 17 17 17 16 13 10  7
       *  7 10 13 16 17 18 17 16 13 10  7
       *  7 10 13 16 17 17 17 16 13 10  7
       *  7 10 13 16 16 16 16 16 13 10  7
       *  6  9 12 13 13 13 13 13 12  9  6
       *  5  8  9 10 10 10 10 10  9  8  5
       *  4  5  6  7  7  7  7  7  6  5  4
       */
      dist_i = gg_min(I(ii), board_size - I(ii) - 1);
      dist_j = gg_min(J(ii), board_size - J(ii) - 1);
      if (dist_i > dist_j)
	dist_i = gg_min(4, dist_i);
      else
	dist_j = gg_min(4, dist_j);
      central = (float) 2 * gg_min(dist_i, dist_j) + dist_i + dist_j;
      ratio = gg_max(q->black_influence[ii], q->white_influence[ii])
	      / gg_interpolate(&min_infl_for_territory, central);

      /* Do not make this adjustment when scoring unless both
       * players have non-zero influence.
       */
      if (doing_scoring && (q->black_influence[ii] == 0.0
			    || q->white_influence[ii] == 0.0))
	ratio = 1.0;
      
      first_guess[ii] *= gg_interpolate(&territory_correction, ratio);

      /* Dead stone, upgrade to territory. Notice that this is not
       * the point for a prisoner, which is added later. Instead
       * this is to make sure that the vertex is not regarded as
       * moyo or area. Also notice that the non-territory
       * degradation below may over-rule this decision.
       */
      if (board[ii] == BLACK)
	first_guess[ii] = 1.0;
      else if (board[ii] == WHITE)
	first_guess[ii] = -1.0;
      q->territory_value[ii] = first_guess[ii];
    }

  /* Second loop: Correct according to neighbour vertices. Each territory
   * value is degraded to the minimum value of its neighbors (unless this
   * neighbor has reduced permeability for the opponent's influence).
   */
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)
	/* Do not overrule dead stone territory above.
	 * FIXME: This does not do what it claims to do. Correcting it
	 * seems to break some tests, though.
	 */
	&& !q->safe[ii]) {
      /* Loop over all neighbors. */
      for (k = 0; k < 4; k++) {
	if (!ON_BOARD(ii + delta[k]))
	  continue;
	if (q->territory_value[ii] > 0.0) {
	  /* White territory. */
	  if (!q->safe[ii + delta[k]]) {
	    float neighbor_val =
	      q->black_permeability[ii + delta[k]]
		* first_guess[ii + delta[k]]
	      + (1.0 - q->black_permeability[ii + delta[k]])
		* first_guess[ii];
	    q->territory_value[ii]
	      = gg_max(0, gg_min(q->territory_value[ii], neighbor_val));
	  }
	}
	else {
	  /* Black territory. */
	  if (!q->safe[ii + delta[k]]) {
	    float neighbor_val =
	      q->white_permeability[ii + delta[k]]
		* first_guess[ii + delta[k]]
	      + (1 - q->white_permeability[ii + delta[k]])
		* first_guess[ii];
	    q->territory_value[ii]
	      = gg_min(0, gg_max(q->territory_value[ii], neighbor_val));
	  }
	}
      }
    }

  /* Third loop: Nonterritory patterns, points for prisoners. */
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)
	&& !q->safe[ii]) {
      /* If marked as non-territory for the color currently owning
       * it, reset the territory value.
       */
      if (q->territory_value[ii] > 0.0
	  && (q->non_territory[ii] & WHITE))
	q->territory_value[ii] = 0.0;

      if (q->territory_value[ii] < 0.0
	  && (q->non_territory[ii] & BLACK))
	q->territory_value[ii] = 0.0;
      
      /* Dead stone, add one to the territory value. */
      if (board[ii] == BLACK)
	q->territory_value[ii] += 1.0;
      else if (board[ii] == WHITE)
	q->territory_value[ii] -= 1.0;
    }
}


/* Segment the influence map into connected regions of territory,
 * moyo, or area. What to segment on is determined by the the function
 * pointer region_owner. The segmentation is performed for both
 * colors. The connected regions may include stones of the own color,
 * but only empty intersections (and dead opponent stones) count
 * toward the region size.
 */
static void
segment_region(struct influence_data *q, owner_function_ptr region_owner,
	       struct moyo_data *regions)
{
  int ii;
  static signed char marked[BOARDMAX];
  regions->number = 0;

  /* Reset the markings. */
  for (ii = BOARDMIN; ii < BOARDMAX; ii++) {
    marked[ii] = 0;
    regions->segmentation[ii] = 0;
  }

  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)
	&& !marked[ii]
	&& region_owner(q, ii) != EMPTY) {
      /* Found an unlabelled intersection. Use flood filling to find
       * the rest of the region.
       */
      int size = 0;
      float terr_val = 0.0;
      int queue_start = 0;
      int queue_end = 1;
      int color = region_owner(q, ii);
      regions->number++;
      marked[ii] = 1;
      q->queue[0] = ii;
      while (queue_start < queue_end) {
	int tt = q->queue[queue_start];
	int k;
	queue_start++;
	if (!q->safe[tt] || board[tt] != color) {
	  size++;
	  if (q->is_territorial_influence)
	    terr_val += gg_abs(q->territory_value[tt]);
	}
	regions->segmentation[tt] = regions->number;
	for (k = 0; k < 4; k++) {
	  int d = delta[k];
	  if (ON_BOARD(tt + d)
	      && !marked[tt + d]
	      && region_owner(q, tt + d) == color) {
	    q->queue[queue_end] = tt + d;
	    queue_end++;
	    marked[tt + d] = 1;
	  }
	}
      }
      regions->size[regions->number] = size;
      regions->territorial_value[regions->number] = terr_val;
      regions->owner[regions->number] = color;
    }
}



/* Export a territory segmentation. */
void
influence_get_territory_segmentation(struct influence_data *q,
    			             struct moyo_data *moyos)
{
  segment_region(q, whose_territory, moyos);
}


/* Export the territory valuation at an intersection from initial_influence;
 * it is given from (color)'s point of view.
 */
float
influence_territory(const struct influence_data *q, int pos, int color)
{
  if (color == WHITE)
    return q->territory_value[pos];
  else
    return -q->territory_value[pos];
}

int
influence_considered_lively(const struct influence_data *q, int pos)
{
  int color = board[pos];
  ASSERT1(IS_STONE(color), pos);
  return (q->safe[pos]
          && ((color == WHITE && q->white_strength[pos] > 0)
	      || (color == BLACK && q->black_strength[pos] > 0)));
}


/* Compute a followup influence. It is assumed that the stones that
 * deserve a followup have been marked INFLUENCE_SAVED_STONE in
 * base->safe.
 */
void
compute_followup_influence(const struct influence_data *base,
    			   struct influence_data *q,
			   int move, const char *trace_message) 
{
  int ii;
  signed char goal[BOARDMAX];
  /* This is the color that will get a followup value. */
  int color = OTHER_COLOR(base->color_to_move);
  int save_debug = debug;

  memcpy(q, base, sizeof(*q));
  ASSERT1(IS_STONE(q->color_to_move), move);
  q->color_to_move = color;
 
  /* We mark the saved stones and their neighbors in the goal array.
   */
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)) {
      if (q->safe[ii] == INFLUENCE_SAVED_STONE)
        goal[ii] = 1;
      else
	goal[ii] = 0;
    }


  /* Turn off DEBUG_INFLUENCE for influence computations we are not
   * interested in.
   */
  if ((move == NO_MOVE
       && !(printmoyo & PRINTMOYO_INITIAL_INFLUENCE))
      || (move != debug_influence))
    debug = debug &~ DEBUG_INFLUENCE;

  q->intrusion_counter = 0;
  current_influence = q;
  /* Match B patterns for saved stones. */
  matchpat_goal_anchor(followup_influence_callback, color, &barrierspat_db, 
           	       q, goal, 1);

  debug = save_debug;
 
  /* Now add the intrusions. */
  add_marked_intrusions(q);

  reset_unblocked_blocks(q);
  
  /* Spread influence for new influence sources. */
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii))
      if ((color == BLACK
            && q->black_strength[ii] > base->black_strength[ii])
          || (color == WHITE
              && q->white_strength[ii] > base->white_strength[ii]))
        accumulate_influence(q, ii, color);

  value_territory(q);

  if (debug_influence && debug_influence == move)
    print_influence(q, trace_message);
}


/* Compute influence based escape values and return them in the
 * escape_value array.  
 */

void
compute_escape_influence(int color, const signed char safe_stones[BOARDMAX],
			 const signed char goal[BOARDMAX],
    			 const float strength[BOARDMAX],
    			 signed char escape_value[BOARDMAX])
{
  int k;
  int ii;
  int save_debug = debug;

  /* IMPORTANT: The caching relies on the fact that safe_stones[] and
   * strength[] will currently always be identical for identical board[]
   * states. Better check for these, too.
   */
  static int cached_board[BOARDMAX];
  static signed char escape_values[BOARDMAX][2];
  static int active_caches[2] = {0, 0};

  int cache_number = (color == WHITE);

  VALGRIND_MAKE_WRITABLE(&escape_influence, sizeof(escape_influence));

  if (!goal) {
    /* Encode the values of color and dragons_known into an integer
     * between 0 and 3.
     */
    int board_was_cached = 1;

    /* Notice that we compare the out of board markers as well, in
     * case the board size should have changed between calls.
     */
    for (ii = BOARDMIN; ii < BOARDMAX; ii++) {
      if (cached_board[ii] != board[ii]) {
	cached_board[ii] = board[ii];
	board_was_cached = 0;
      }
    }

    if (!board_was_cached)
      for (k = 0; k < 2; k++)
	active_caches[k] = 0;

    if (active_caches[cache_number]) {
      for (ii = BOARDMIN; ii < BOARDMAX; ii++)
	if (ON_BOARD(ii))
	  escape_value[ii] = escape_values[ii][cache_number];

      return;
    }
  }

  /* Use enhance pattern and higher attenuation for escape influence. */
  escape_influence.is_territorial_influence = 0;
  escape_influence.color_to_move = EMPTY;

  /* Turn off DEBUG_INFLUENCE unless we are specifically interested in
   * escape computations.
   */
  if (!(debug & DEBUG_ESCAPE))
    debug &= ~DEBUG_INFLUENCE;

  do_compute_influence(safe_stones, goal, strength,
      		       &escape_influence, -1, NULL);

  debug = save_debug;
  
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)) {
      if (whose_moyo(&escape_influence, ii) == color)
	escape_value[ii] = 4;
      else if (whose_area(&escape_influence, ii) == color)
	escape_value[ii] = 2;
      else if (whose_area(&escape_influence, ii) == EMPTY) {
	if (goal) {
	  escape_value[ii] = 0;

	  if (!goal[ii]) {
	    int goal_proximity = 0;

	    for (k = 0; k < 8; k++) {
	      if (ON_BOARD(ii + delta[k])) {
		goal_proximity += 2 * goal[ii + delta[k]];
		if (k < 4 && ON_BOARD(ii + 2 * delta[k]))
		  goal_proximity += goal[ii + delta[k]];
	      }
	      else
		goal_proximity += 1;
	    }

	    if (goal_proximity < 6)
	      escape_value[ii] = 1;
	  }
	}
	else
	  escape_value[ii] = 1;
      }
      else
	escape_value[ii] = 0;
    }

  if (0 && (debug & DEBUG_ESCAPE) && verbose > 0)
    print_influence(&escape_influence, "escape influence");

  if (!goal) {
    /* Save the computed values in the cache. */
    for (ii = BOARDMIN; ii < BOARDMAX; ii++)
      if (ON_BOARD(ii))
	escape_values[ii][cache_number] = escape_value[ii];
    active_caches[cache_number] = 1;
  }
}


/* Cache of delta_territory_values. */
static float delta_territory_cache[BOARDMAX];
static float followup_territory_cache[BOARDMAX];
static Hash_data delta_territory_cache_hash[BOARDMAX];
static int territory_cache_position_number = -1;
static int territory_cache_influence_id = -1;
static int territory_cache_color = -1;

/* We cache territory computations. This avoids unnecessary re-computations
 * when review_move_reasons is run a second time for the endgame patterns.
 *
 * (*base) points to the initial_influence data that would be used
 * to make the territory computation against.
 */
int 
retrieve_delta_territory_cache(int pos, int color, float *move_value,
    			       float *followup_value,
			       const struct influence_data *base,
			       Hash_data safety_hash)
{
  ASSERT_ON_BOARD1(pos);
  ASSERT1(IS_STONE(color), pos);

  /* We check whether the color, the board position, or the base influence
   * data has changed since the cache entry got entered.
   */
  if (territory_cache_position_number == position_number
      && territory_cache_color == color
      && territory_cache_influence_id == base->id
      && delta_territory_cache[pos] != NOT_COMPUTED) {
    int i;
    for (i = 0; i < NUM_HASHVALUES; i++)
      if (delta_territory_cache_hash[pos].hashval[i]
	  != safety_hash.hashval[i])
	return 0;
    *move_value = delta_territory_cache[pos];
    *followup_value = followup_territory_cache[pos];
    if (0) 
      gprintf("%1m: retrieved territory value from cache: %f, %f\n", pos,
	      *move_value, *followup_value);
    return 1;
  }
  return 0;
}

void 
store_delta_territory_cache(int pos, int color,
			    float move_value, float followup_value,
			    const struct influence_data *base,
			    Hash_data safety_hash)
{
  int i;

  ASSERT_ON_BOARD1(pos);
  ASSERT1(IS_STONE(color), pos);

  if (territory_cache_position_number != position_number
      || territory_cache_color != color
      || territory_cache_influence_id != base->id) {
    int ii;
    for (ii = BOARDMIN; ii < BOARDMAX; ii++)
      delta_territory_cache[ii] = NOT_COMPUTED;
    territory_cache_position_number = position_number;
    territory_cache_influence_id = base->id;
    territory_cache_color = color;
    if (0)
      gprintf("Cleared delta territory cache.\n");
  }
  delta_territory_cache[pos] = move_value;
  followup_territory_cache[pos] = followup_value;
  for (i = 0; i < NUM_HASHVALUES; i++)
    delta_territory_cache_hash[pos].hashval[i] = safety_hash.hashval[i];
  if (0)
    gprintf("%1m: Stored delta territory cache: %f, %f\n", pos, move_value,
	    followup_value);
}

/* Compute the difference in territory between two influence data,
 * from the point of view of (color).
 * (move) is only passed for debugging output.
 */
float
influence_delta_territory(const struct influence_data *base,
    			  const struct influence_data *q, int color,
			  int move)
{
  int ii;
  float total_delta = 0.0;
  float this_delta;
  ASSERT_ON_BOARD1(move);
  ASSERT1(IS_STONE(color), move);

  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)) {
      float new_value = q->territory_value[ii];
      float old_value = base->territory_value[ii];
      this_delta = new_value - old_value;
      /* Negate values if we are black. */
      if (color == BLACK) {
	new_value = -new_value;
	old_value = -old_value;
	this_delta = -this_delta;
      }
      
      if (move != -1
	  && (this_delta > 0.02 || -this_delta > 0.02))
	DEBUG(DEBUG_TERRITORY,
	      "  %1m:   - %1m territory change %f (%f -> %f)\n",
	      move, ii, this_delta, old_value, new_value);
      total_delta += this_delta;
    }

  /* Finally, captured stones: */
  this_delta = q->captured - base->captured;
  if (color == BLACK)
    this_delta = -this_delta;
  if (move != -1
      && this_delta != 0.0)
    DEBUG(DEBUG_TERRITORY, "  %1m:   - captured stones %f\n",
	  move, this_delta);
  total_delta += this_delta;

  return total_delta;
}


/* Estimate the score. A positive value means white is ahead. The
 * score is estimated influence data *q, which must have been
 * computed in advance.
 */
float
influence_score(const struct influence_data *q, int use_chinese_rules)
{
  float score = 0.0;
  int ii;

  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii))
      score += q->territory_value[ii];
  
  if (use_chinese_rules)
    score += stones_on_board(WHITE) - stones_on_board(BLACK) + komi + handicap;
  else
    score += black_captured - white_captured + komi;

  return score;
}


/* Uses initial_influence to estimate the game advancement (fuseki,
 * chuban, yose) returned as a value between 0.0 (start) and 1.0 (game
 * over)
 */
float
game_status(int color)
{
  struct influence_data *iq = INITIAL_INFLUENCE(color);
  struct influence_data *oq = OPPOSITE_INFLUENCE(color);
  int count = 0;
  int ii;

  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)) {
      if (iq->safe[ii])
	count += WEIGHT_TERRITORY;
      else if (whose_territory(iq, ii) != EMPTY
	       && whose_territory(oq, ii) != EMPTY)
	count += WEIGHT_TERRITORY;
      else if (whose_moyo(oq, ii) != EMPTY)
	count += WEIGHT_MOYO;
      else if (whose_area(oq, ii) != EMPTY)
	count += WEIGHT_AREA;
    }

  return (float) count / (WEIGHT_TERRITORY * board_size * board_size);
}


/* Print the influence map when we have computed influence for the
 * move at (i, j).
 */
void
debug_influence_move(int move)
{
  debug_influence = move;
}


/* One more way to export influence data. This should only be used
 * for debugging.
 */
void
get_influence(const struct influence_data *q,
	      float white_influence[BOARDMAX],
	      float black_influence[BOARDMAX],
	      float white_strength[BOARDMAX],
	      float black_strength[BOARDMAX],
	      float white_attenuation[BOARDMAX], 
	      float black_attenuation[BOARDMAX],
	      float white_permeability[BOARDMAX],
	      float black_permeability[BOARDMAX],
	      float territory_value[BOARDMAX],
	      int influence_regions[BOARDMAX],
	      int non_territory[BOARDMAX])
{
  int ii;
  
  for (ii = BOARDMIN; ii < BOARDMAX; ii++) {
    white_influence[ii] = q->white_influence[ii];
    black_influence[ii] = q->black_influence[ii];
    white_strength[ii] = q->white_strength[ii];
    black_strength[ii] = q->black_strength[ii];
    white_attenuation[ii] = q->white_attenuation[ii];
    black_attenuation[ii] = q->black_attenuation[ii];
    white_permeability[ii] = q->white_permeability[ii];
    black_permeability[ii] = q->black_permeability[ii];
    territory_value[ii] = q->territory_value[ii];
    non_territory[ii] = q->non_territory[ii];

    if (board[ii] == EMPTY) {
      if (whose_territory(q, ii) == WHITE)
	influence_regions[ii] = 3;
      else if (whose_territory(q, ii) == BLACK)
	influence_regions[ii] = -3;
      else if (whose_moyo(q, ii) == WHITE)
	influence_regions[ii] = 2;
      else if (whose_moyo(q, ii) == BLACK)
	influence_regions[ii] = -2;
      else if (whose_area(q, ii) == WHITE)
	influence_regions[ii] = 1;
      else if (whose_area(q, ii) == BLACK)
	influence_regions[ii] = -1;
      else
	influence_regions[ii] = 0;
    }
    else if (board[ii] == WHITE)
      influence_regions[ii] = 4;
    else if (board[ii] == BLACK)
      influence_regions[ii] = -4;
  }
}
  


/* Print influence for debugging purposes, according to
 * printmoyo bitmap (controlled by -m command line option).
 */
void
print_influence(const struct influence_data *q, const char *info_string)
{
  if (printmoyo & PRINTMOYO_ATTENUATION) {
    /* Print the attenuation values. */
    fprintf(stderr, "white attenuation (%s):\n", info_string);
    print_numeric_influence(q, q->white_attenuation, "%3.2f", 3, 0, 0);
    fprintf(stderr, "black attenuation (%s):\n", info_string);
    print_numeric_influence(q, q->black_attenuation, "%3.2f", 3, 0, 0);
  }

  if (printmoyo & PRINTMOYO_PERMEABILITY) {
    /* Print the white permeability values. */
    fprintf(stderr, "white permeability:\n");
    print_numeric_influence(q, q->white_permeability, "%3.1f", 3, 0, 0);
    
    /* Print the black permeability values. */
    fprintf(stderr, "black permeability:\n");
    print_numeric_influence(q, q->black_permeability, "%3.1f", 3, 0, 0);
  }

  if (printmoyo & PRINTMOYO_STRENGTH) {
    /* Print the strength values. */
    fprintf(stderr, "white strength:\n");
    if (q->is_territorial_influence)
      print_numeric_influence(q, q->white_strength, "%5.1f", 5, 0, 0);
    else
      print_numeric_influence(q, q->white_strength, "%3.0f", 3, 0, 1);
    fprintf(stderr, "black strength:\n");
    if (q->is_territorial_influence)
      print_numeric_influence(q, q->black_strength, "%5.1f", 5, 0, 0);
    else
      print_numeric_influence(q, q->black_strength, "%3.0f", 3, 0, 1);
  }

  if (printmoyo & PRINTMOYO_NUMERIC_INFLUENCE) {
    /* Print the white influence values. */
    fprintf(stderr, "white influence (%s):\n", info_string);
    print_numeric_influence(q, q->white_influence, "%5.1f", 5, 1, 0);
    /* Print the black influence values. */
    fprintf(stderr, "black influence (%s):\n", info_string);
    print_numeric_influence(q, q->black_influence, "%5.1f", 5, 1, 0);
  }

  if (printmoyo & PRINTMOYO_PRINT_INFLUENCE) {
    fprintf(stderr, "influence regions (%s):\n", info_string);
    print_influence_areas(q);
  }
  if (printmoyo & PRINTMOYO_VALUE_TERRITORY) {
    fprintf(stderr, "territory (%s)", info_string);
    print_numeric_influence(q, q->territory_value, "%5.2f", 5, 1, 0);
  }
}



/*
 * Print numeric influence values.
 */
static void
print_numeric_influence(const struct influence_data *q,
			const float values[BOARDMAX],
			const char *format, int width,
			int draw_stones, int mark_epsilon)
{
  int i, j;
  char ch;
  char format_stone[20];

  memset(format_stone, ' ', 20);
  format_stone[(width + 1) / 2] = '%';
  format_stone[(width + 3) / 2] = 'c';
  format_stone[width + 2] = 0;

  fprintf(stderr, "   ");
  for (i = 0, ch = 'A'; i < board_size; i++, ch++) {
    if (ch == 'I')
      ch++;
    fprintf(stderr, format_stone, ch);
  }
  fprintf(stderr, "\n");

  for (i = 0; i < board_size; i++) {
    int ii = board_size - i;
    fprintf(stderr, "%2d ", ii);
    for (j = 0; j < board_size; j++) {
      int ii = POS(i, j);
      if (draw_stones && q->safe[ii]) {
        if (board[ii] == WHITE)
	  fprintf(stderr, format_stone, 'O');
	else 
	  fprintf(stderr, format_stone, 'X');
      }
      else {
	if (mark_epsilon && values[ii] > 0.0 && values[ii] < 1.0)
	  fprintf(stderr, "eps");
	else
	  fprintf(stderr, format, values[ii]);
	fprintf(stderr, " ");
      }
    }
    fprintf(stderr, "%2d\n", ii);
  }

  fprintf(stderr, "   ");
  for (i = 0, ch = 'A'; i < board_size; i++, ch++) {
    if (ch == 'I')
      ch++;
    fprintf(stderr, format_stone, ch);
  }
  fprintf(stderr, "\n");
}

/* Draw colored board illustrating territory, moyo, and area. */
static void
print_influence_areas(const struct influence_data *q)
{
  int ii;
  start_draw_board();
  for (ii = BOARDMIN; ii < BOARDMAX; ii++)
    if (ON_BOARD(ii)) {
      int c = EMPTY;
      int color = GG_COLOR_BLACK;
      if (q->safe[ii]) {
	color = GG_COLOR_BLACK;
        if (board[ii] == WHITE)
	  c = 'O';
        else
	  c = 'X';
      }
      else if (whose_territory(q, ii) == WHITE) {
	c = 'o';
	color = GG_COLOR_CYAN;
      }
      else if (whose_territory(q, ii) == BLACK) {
	c = 'x';
	color = GG_COLOR_CYAN;
      }
      else if (whose_moyo(q, ii) == WHITE) {
	c = 'o';
	color = GG_COLOR_YELLOW;
      }
      else if (whose_moyo(q, ii) == BLACK) {
	c = 'x';
	color = GG_COLOR_YELLOW;
      }
      else if (whose_area(q, ii) == WHITE) {
	c = 'o';
	color = GG_COLOR_RED;
      }
      else if (whose_area(q, ii) == BLACK) {
	c = 'x';
	color = GG_COLOR_RED;
      }
      draw_color_char(I(ii), J(ii), c, color);
    }
  end_draw_board();
}


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