/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 * 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, 2009 and 2010 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 <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>

#include "liberty.h"
#include "sgftree.h"
#include "random.h"
#include "gg_utils.h"
#include "patterns.h"

/*
 * Change the status of all the stones in the dragon at (dr).
 */

void
change_dragon_status(int dr, enum dragon_status status)
{
  int pos;
  int origin = dragon[dr].origin;

  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
    if (ON_BOARD(pos)) {
      if (dragon[pos].origin == origin)
	dragon[pos].status = status;
    }
}


/*
 * Check whether a move at (move) stops the enemy from playing at (apos).
 */

int
defend_against(int move, int color, int apos)
{
  if (trymove(move, color, "defend_against", NO_MOVE)) {
    if (safe_move(apos, OTHER_COLOR(color)) == 0) {
      popgo();
      return 1;
    }
    popgo();
  }
  return 0;
}


/* 
 * Returns true if color can cut at (pos), or if connection through (pos)
 * is inhibited. This information is collected by find_cuts(), using the B
 * patterns in the connections database.
 */

int
cut_possible(int pos, int color)
{
  return (cutting_points[pos] & OTHER_COLOR(color)) != 0;
}


/*
 * does_attack(move, str) returns the result code for an attack on the
 * string 'str' by the move 'move'. However, if the move does not
 * improve the attack result compared to tenuki, 0 is returned. In
 * particular if the string is already captured, does_attack() always
 * returns 0.
 */

int
does_attack(int move, int str)
{
  int color = board[str];
  int other = OTHER_COLOR(color);
  int result = 0;
  int acode = 0;
  int dcode = 0;
  int spos = NO_MOVE;
  
  attack_and_defend(str, &acode, NULL, &dcode, &spos);
  if (acode != 0 && dcode == 0)
    return 0;
  
  if (trymove(move, other, "does_attack-A", str)) {
    if (!board[str])
      result = WIN;
    else
      result = REVERSE_RESULT(find_defense(str, NULL));
    if (result != 0) {
      increase_depth_values();
      if (spos != NO_MOVE && trymove(spos, color, "does_attack-B", str)) {
	if (board[str]) {
	  int new_result = attack(str, NULL);
	  if (new_result < result)
	    result = new_result;
	}
	popgo();
      }
      decrease_depth_values();
    }
    popgo();
  }

  if (result < acode)
    result = 0;
  
  return result;
}


/*
 * does_defend(move, str) returns true if the move at (move)
 * defends (str). This means that it defends the string, and that
 * (str) can be captured if no defense is made.
 *
 * FIXME: Make does_defend() ko aware like does_attack().
 */

int
does_defend(int move, int str)
{
  int color = board[str];
  int other = OTHER_COLOR(color);
  int result = 0;
  int spos = NO_MOVE;

  if (!attack(str, &spos))
    return 0;

  gg_assert(spos != NO_MOVE);
  
  if (trymove(move, color, "does_defend-A", str)) {
    if (!attack(str, NULL)) {
      result = 1;
      increase_depth_values();
      if (trymove(spos, other, "does_defend-B", str)) {
	if (!board[str] || !find_defense(str, NULL))
	  result = 0;
	popgo();
      }
      decrease_depth_values();
    }
    popgo();
  }

  return result;
}


/* 
 * Example: somewhere(WHITE, 2, apos, bpos, cpos).
 * 
 * Returns true if one of the vertices listed
 * satisfies board[pos]==color. Here num_moves is the
 * number of moves. If check_alive is true, the dragon is not allowed
 * to be dead. This check is only valid if stackp==0.
 */

int
somewhere(int color, int check_alive, int num_moves, ...)
{
  va_list ap;
  int pos;
  int k;

  gg_assert(stackp == 0 || !check_alive);
  
  va_start(ap, num_moves);
  for (k = 0; k < num_moves; k++) {
    pos = va_arg(ap, int);

    if (board[pos] == color
	&& (!check_alive || dragon[pos].status != DEAD)) {
      va_end(ap);
      return 1;
    }
  }

  va_end(ap);
  return 0;
}

/* Search along the edge for the first visible stone. Start at apos
 * and move in the direction of bpos. Return 1 if the first visible
 * stone is of the given color. It is required that apos and bpos are
 * at the same distance from the edge.
 *
 * FIXME: The detection of the first visible stone is quite crude and
 * probably needs to be improved.
 */
int
visible_along_edge(int color, int apos, int bpos)
{
  int ai = I(apos);
  int aj = J(apos);
  int bi = I(bpos);
  int bj = J(bpos);
  int pos;
  int forward;
  int up;
  ASSERT1((ai == bi) ^ (aj == bj), apos);

  if (ai == bi) {
    if (aj > bj)
      forward = WEST(0);
    else
      forward = EAST(0);

    if (ai < board_size/2) {
      pos = POS(0, bj);
      up = SOUTH(0);
    }
    else {
      pos = POS(board_size - 1, bj);
      up = NORTH(0);
    }
  }
  else {
    if (ai > bi)
      forward = NORTH(0);
    else
      forward = SOUTH(0);

    if (aj < board_size/2) {
      pos = POS(bi, 0);
      up = EAST(0);
    }
    else {
      pos = POS(bi, board_size - 1);
      up = WEST(0);
    }
  }
  
  for (; ON_BOARD(pos); pos += forward) {
    int k;
    for (k = 4; k >= 0; k--) {
      ASSERT_ON_BOARD1(pos + k * up);
      if (board[pos + k * up] == color)
	return 1;
      else if (board[pos + k * up] == OTHER_COLOR(color))
	return 0;
    }
  }

  return 0;
}

/* Is the board symmetric (or rather antisymmetric) with respect to
 * mirroring in tengen after a specific move has been played? If the
 * move is PASS_MOVE, check the current board.
 *
 * If strict is set we require that each stone is matched by a stone
 * of the opposite color at the mirrored vertex. Otherwise we only
 * require that each stone is matched by a stone of either color.
 */
int
test_symmetry_after_move(int move, int color, int strict)
{
  int pos;
  int result = 1;

  if (move != PASS_MOVE) {
    if (board[move] != EMPTY)
      return 0;
    if (!trymove(move, color, "find_mirror_move", NO_MOVE))
      return 0;
  }
  
  for (pos = BOARDMIN; pos < MIRROR_MOVE(pos); pos++) {
    int sum;
    if (!ON_BOARD(pos))
      continue;
    
    sum = board[pos] + board[MIRROR_MOVE(pos)];
    if (sum != EMPTY + EMPTY && sum != BLACK + WHITE) {
      if (strict || sum == EMPTY + WHITE || sum == EMPTY + BLACK) {
	result = 0;
	break;
      }
    }
  }

  if (move != PASS_MOVE)
    popgo();
  
  return result;
}


/* The function play_break_through_n() plays a sequence of moves,
 * alternating between the players and starting with color. After
 * having played through the sequence, the three last coordinate pairs
 * gives a position to be analyzed by break_through(), to see whether
 * either color has managed to enclose some stones and/or connected
 * his own stones. If any of the three last positions is empty, it's
 * assumed that the enclosure has failed, as well as the attempt to
 * connect.
 *
 * If one or more of the moves to play turns out to be illegal for
 * some reason, the rest of the sequence is played anyway, and
 * break_through() is called as if nothing special happened.
 *
 * Like break_through(), this function returns 1 if the attempt to
 * break through was succesful and 2 if it only managed to cut
 * through.
 */
   
int
play_break_through_n(int color, int num_moves, ...)
{
  va_list ap;
  int mcolor = color;
  int success = 0;
  int i;
  int played_moves = 0;
  int apos;
  int xpos;
  int ypos;
  int zpos;
  
  va_start(ap, num_moves);

  /* Do all the moves with alternating colors. */
  for (i = 0; i < num_moves; i++) {
    apos = va_arg(ap, int);

    if (apos != NO_MOVE
	&& (trymove(apos, mcolor, "play_break_through_n", NO_MOVE)
	    || tryko(apos, mcolor, "play_break_through_n")))
      played_moves++;
    mcolor = OTHER_COLOR(mcolor);
  }

  /* Now do the real work. */
  xpos = va_arg(ap, int);
  ypos = va_arg(ap, int);
  zpos = va_arg(ap, int);
    
  /* Temporarily increase the depth values with the number of explicitly
   * placed stones.
   */
#if 0
  modify_depth_values(played_moves);
#endif
  
  if (board[xpos] == EMPTY
      || board[ypos] == EMPTY
      || board[zpos] == EMPTY)
    success = 1;
  else
    success = break_through(xpos, ypos, zpos);

#if 0
  modify_depth_values(-played_moves);
#endif
  
  /* Pop all the moves we could successfully play. */
  for (i = 0; i < played_moves; i++)
    popgo();

  va_end(ap);
  return success;
}


/* The function play_attack_defend_n() plays a sequence of moves,
 * alternating between the players and starting with color. After
 * having played through the sequence, the last coordinate pair gives
 * a target to attack or defend, depending on the value of do_attack.
 * If there is no stone present to attack or defend, it is assumed
 * that it has already been captured. If one or more of the moves to
 * play turns out to be illegal for some reason, the rest of the
 * sequence is played anyway, and attack/defense is tested as if
 * nothing special happened.
 *
 * A typical use for these functions is to set up a ladder in an
 * autohelper and see whether it works or not.
 */
   
int
play_attack_defend_n(int color, int do_attack, int num_moves, ...)
{
  va_list ap;
  int mcolor = color;
  int success = 0;
  int i;
  int played_moves = 0;
  int apos;
  int zpos;
  
  va_start(ap, num_moves);

  /* Do all the moves with alternating colors. */
  for (i = 0; i < num_moves; i++) {
    apos = va_arg(ap, int);

    if (apos != NO_MOVE
	&& (trymove(apos, mcolor, "play_attack_defend_n", NO_MOVE)
	    || tryko(apos, mcolor, "play_attack_defend_n")))
      played_moves++;
    mcolor = OTHER_COLOR(mcolor);
  }

  /* Now do the real work. */
  zpos = va_arg(ap, int);

  /* Temporarily increase the depth values with the number of explicitly
   * placed stones.
   *
   * This improves the reading of pattern constraints but
   * unfortunately tends to be too expensive. For the time being it is
   * disabled.
   */
#if 0
  modify_depth_values(played_moves);
#endif
  
  if (do_attack) {
    if (board[zpos] == EMPTY)
      success = WIN;
    else
      success = attack(zpos, NULL);
  }
  else {
    if (board[zpos] == EMPTY)
      success = 0;
    else {
      int dcode = find_defense(zpos, NULL);
      if (dcode == 0 && !attack(zpos, NULL))
	success = WIN;
      else
	success = dcode;
    }
  }

#if 0
  modify_depth_values(-played_moves);
#endif
  
  /* Pop all the moves we could successfully play. */
  for (i = 0; i < played_moves; i++)
    popgo();

  va_end(ap);
  return success;
}


/* The function play_attack_defend2_n() plays a sequence of moves,
 * alternating between the players and starting with color. After
 * having played through the sequence, the two last coordinate pairs
 * give two targets to simultaneously attack or defend, depending on
 * the value of do_attack. If there is no stone present to attack or
 * defend, it is assumed that it has already been captured. If one or
 * more of the moves to play turns out to be illegal for some reason,
 * the rest of the sequence is played anyway, and attack/defense is
 * tested as if nothing special happened.
 *
 * A typical use for these functions is to set up a crosscut in an
 * autohelper and see whether at least one cutting stone can be
 * captured.
 */
   
int
play_attack_defend2_n(int color, int do_attack, int num_moves, ...)
{
  va_list ap;
  int mcolor = color;
  int success = 0;
  int i;
  int played_moves = 0;
  int apos;
  int ypos;
  int zpos;
  
  va_start(ap, num_moves);

  /* Do all the moves with alternating colors. */
  for (i = 0; i < num_moves; i++) {
    apos = va_arg(ap, int);

    if (apos != NO_MOVE
	&& (trymove(apos, mcolor, "play_attack_defend_n", NO_MOVE)
	    || tryko(apos, mcolor, "play_attack_defend_n")))
      played_moves++;
    mcolor = OTHER_COLOR(mcolor);
  }

  /* Now do the real work. */
  ypos = va_arg(ap, int);
  zpos = va_arg(ap, int);

  /* Temporarily increase the depth values with the number of explicitly
   * placed stones.
   */
#if 0
  modify_depth_values(played_moves);
#endif
  

  /* FIXED: tm - returns ko results correctly (3.1.22) */
  if (do_attack) {
    if (board[ypos] == EMPTY || board[zpos] == EMPTY)
      success = WIN;
    else
      success = attack_either(ypos, zpos);
  }
  else {
    if (board[ypos] == EMPTY || board[zpos] == EMPTY)
      success = 0;
    else
      success = defend_both(ypos, zpos);
  }

#if 0
  modify_depth_values(-played_moves);
#endif
  
  /* Pop all the moves we could successfully play. */
  for (i = 0; i < played_moves; i++)
    popgo();

  va_end(ap);
  return success;
}


/* The function play_connect_n() plays a sequence of moves,
 * alternating between the players and starting with color. After
 * having played through the sequence, the two last coordinates
 * give two targets that should be connected or disconnected, depending on
 * the value of do_connect. If there is no stone present to connect or
 * disconnect, it is assumed that the connection has failed. If one or
 * more of the moves to play turns out to be illegal for some reason,
 * the rest of the sequence is played anyway, and connection/disconnection
 * is tested as if nothing special happened.
 */

int 
play_connect_n(int color, int do_connect, int num_moves, ...)
{
  va_list ap;
  int mcolor = color;
  int success = 0;
  int i;
  int played_moves = 0;
  int apos;
  int ypos;
  int zpos;

  va_start(ap, num_moves);

  /* Do all the moves with alternating colors. */
  for (i = 0; i < num_moves; i++) {
    apos = va_arg(ap, int);

    if (apos != NO_MOVE
	&& (trymove(apos, mcolor, "play_connect_n", NO_MOVE)
	    || tryko(apos, mcolor, "play_connect_n")))
      played_moves++;
    mcolor = OTHER_COLOR(mcolor);
  }

  /* Now do the real work. */
  ypos = va_arg(ap, int);
  zpos = va_arg(ap, int);

  /* Temporarily increase the depth values with the number of explicitly
   * placed stones.
   *
   * This improves the reading of pattern constraints but
   * unfortunately tends to be too expensive. For the time being it is
   * disabled.
   */
#if 0
  modify_depth_values(played_moves);
#endif
  
  /* See if ypos and zpos can be connected (or disconnected). */
  if (do_connect) {
    if (board[ypos] == EMPTY || board[zpos] == EMPTY)
      success = 0;
    else
      success = string_connect(ypos, zpos, NULL);
  }
  else {
    if (board[ypos] == EMPTY || board[zpos] == EMPTY)
      success = WIN;
    else
      success = disconnect(ypos, zpos, NULL);
  }

#if 0
  modify_depth_values(-played_moves);
#endif
  
  /* Pop all the moves we could successfully play. */
  for (i = 0; i < played_moves; i++)
    popgo();

  va_end(ap);
  return success;
}


/* The function play_lib_n() plays a sequence of moves, alternating
 * between the players and starting with color. After having played
 * through the sequence, the last coordinate gives a target for liberty
 * counting. The number of liberties is returned.
 *
 * If only one move is to be played and that stone is the target,
 * accuratelib (or approxlib if appropriate) is more efficient.
 */

int 
play_lib_n(int color, int num_moves, ...)
{
  va_list ap;
  int mcolor = color;
  int libs = 0;
  int i;
  int played_moves = 0;
  int apos;
  int ypos;

  va_start(ap, num_moves);

  /* Do all the moves with alternating colors. */
  for (i = 0; i < num_moves; i++) {
    apos = va_arg(ap, int);

    if (apos != NO_MOVE
	&& (trymove(apos, mcolor, "play_connect_n", NO_MOVE)
	    || tryko(apos, mcolor, "play_connect_n")))
      played_moves++;
    mcolor = OTHER_COLOR(mcolor);
  }

  /* Now do the real work. */
  ypos = va_arg(ap, int);
  if (board[ypos] == EMPTY)
    libs = 0;
  else
    libs = countlib(ypos);
  
  /* Pop all the moves we could successfully play. */
  for (i = 0; i < played_moves; i++)
    popgo();

  va_end(ap);
  return libs;
}


/* Helper function to compute a * pow(b, e) with some safety nets to
 * handle overflow robustly.
 */
static int
exponential_level(int a, double b, double e)
{
  double x = pow(b, e);

  if (x > (double) INT_MAX / (double) a)
    return INT_MAX;

  return (int) (a * x);
}


/* 
 * It is assumed in reading a ladder if stackp >= depth that
 * as soon as a bounding stone is in atari, the string is safe.
 * It is used similarly at other places in reading.c to implement simplifying
 * assumptions when stackp is large. DEPTH is the default value of depth.
 *
 * Unfortunately any such scheme invites the ``horizon effect.'' Increasing
 * DEPTH will make the program stronger and slower.
 *
 */

/* Tactical reading using C functions */
#define DEPTH                16
#define BRANCH_DEPTH         13
#define BACKFILL_DEPTH       12
#define BACKFILL2_DEPTH       5
#define BREAK_CHAIN_DEPTH     7
#define SUPERSTRING_DEPTH     7
#define FOURLIB_DEPTH         7
#define KO_DEPTH              8

#if 0
#undef FOURLIB_DEPTH
#define FOURLIB_DEPTH         9
#endif


#define AA_DEPTH              6

/* Pattern based reading */
#define OWL_DISTRUST_DEPTH    6
#define OWL_BRANCH_DEPTH      8
#define OWL_READING_DEPTH    20
#define SEMEAI_BRANCH_DEPTH  12
#define SEMEAI_BRANCH_DEPTH2  6

/* Connecton reading */
#define CONNECT_NODE_LIMIT 2000
#define CONNECT_DEPTH        64
#define CONNECT_DEPTH2       20

#define BREAKIN_NODE_LIMIT  400
#define BREAKIN_DEPTH	     14

/* Set the various reading depth parameters. If mandated_depth_value
 * is not -1 that value is used; otherwise the depth values are
 * set as a function of level. The parameter mandated_depth_value
 * can be set at the command line to force a particular value of
 * depth; normally it is -1.
 */

void
set_depth_values(int level, int report_levels)
{
  static int node_limits[] = {500, 500, 450, 400, 400, 325, 275,
			      200, 150, 100, 75, 50};
  int depth_level;

  /*
   * Other policies depending on level:
   * owl.c:         >=  9: use vital attack pattern database
   *                >=  8: increase depth values in owl_substantial
   *                >=  8: don't turn off owl_phase in semeai reading
   * reading.c:     >=  8: Use superstrings and do more backfilling.
   * value_moves.c: >=  6: try to find more owl attacks/defenses
   * breakin.c:     >= 10: try to find break-ins. (*)
   * worm.c:        >= 10: detect unconditionally meaningless moves
   *
   * The break-in code (*) is particularly expensive. 
   *
   * Speedups between levels 9 and 10 and between levels 7 and 8
   * are obtained by turning off services, and between these
   * levels no changes are made in the depths. The parameter
   * depth_level is the correction compared to the default settings at level
   * 10 for most reading depths.
   */
  if (level >= 10)
    depth_level = level - 10;
  else if (level == 9)
    depth_level = 0;
  else if (level == 8)
    depth_level = -1;
  else 
    depth_level = level - 8;

  depth                = gg_max(6, DEPTH 	    + depth_level);
  branch_depth         = gg_max(3, BRANCH_DEPTH	    + depth_level);
  backfill_depth       = gg_max(2, BACKFILL_DEPTH    + depth_level);
  backfill2_depth      = gg_max(1, BACKFILL2_DEPTH   + depth_level);
  break_chain_depth    = gg_max(2, BREAK_CHAIN_DEPTH + depth_level);
  if (level >= 8)
    owl_distrust_depth = gg_max(1, (2 * OWL_DISTRUST_DEPTH + depth_level) / 2);
  else
    owl_distrust_depth = gg_max(1, (2 * OWL_DISTRUST_DEPTH - 1
				    + depth_level) / 2);
  owl_branch_depth     = gg_max(2, (2 * OWL_BRANCH_DEPTH   + depth_level) / 2);
  owl_reading_depth    = gg_max(5, (2 * OWL_READING_DEPTH  + depth_level) / 2);

  /* Atari-atari depth levels are unchanged only between levels 7/8, 9/10: */
  if (level >= 10)
    aa_depth = gg_max(0, AA_DEPTH + (level - 10));
  else if (level == 9)
    aa_depth = gg_max(0, AA_DEPTH);
  else if (level >= 7)
    aa_depth = gg_max(0, AA_DEPTH - 1);
  else
    aa_depth = gg_max(0, AA_DEPTH - (8 - level));

  /* Exceptions:
   * fourlib_depth: This is constant from levels 7 to 10.
   * superstring_depth: set to 0 below level 8.
   */
  if (level >= 10)
    ko_depth            = gg_max(1, KO_DEPTH + (level - 10));
  else if (level == 9)
    ko_depth            = gg_max(1, KO_DEPTH);
  else if (level >= 7)
    ko_depth            = gg_max(1, KO_DEPTH - 1);
  else
    ko_depth            = gg_max(1, KO_DEPTH + (level - 8));

  if (level >= 10)
    fourlib_depth       = gg_max(1, FOURLIB_DEPTH + (level - 10));
  else if (level >= 7)
    fourlib_depth       = gg_max(1, FOURLIB_DEPTH);
  else
    fourlib_depth       = gg_max(1, FOURLIB_DEPTH + (level - 7));

  if (level >= 8)
    superstring_depth = gg_max(1, SUPERSTRING_DEPTH);
  else
    superstring_depth = 0;

  if (level >= 10)
    owl_node_limit      = exponential_level(OWL_NODE_LIMIT, 1.5, depth_level);
  else {
    owl_node_limit      = (OWL_NODE_LIMIT * node_limits[10 - level] /
			   node_limits[0]);
    owl_node_limit      = gg_max(20, owl_node_limit);
  }

  semeai_branch_depth  = gg_max(2, (2*SEMEAI_BRANCH_DEPTH  + depth_level) / 2);
  semeai_branch_depth2 = gg_max(2, (2*SEMEAI_BRANCH_DEPTH2 + depth_level) / 2);
  semeai_node_limit    = exponential_level(SEMEAI_NODE_LIMIT, 1.5, depth_level);

  connect_depth         = gg_max(2, CONNECT_DEPTH  + 2 * depth_level);
  connect_depth2        = gg_max(2, CONNECT_DEPTH2 + 2 * depth_level);
  connection_node_limit = exponential_level(CONNECT_NODE_LIMIT, 1.45, depth_level);
  breakin_depth 	= gg_max(2, BREAKIN_DEPTH + 2 * depth_level);
  breakin_node_limit 	= exponential_level(BREAKIN_NODE_LIMIT, 1.5, depth_level);

  if (mandated_depth != -1)
    depth = mandated_depth;
  if (mandated_backfill_depth != -1)
    backfill_depth = mandated_backfill_depth;
  if (mandated_backfill2_depth != -1)
    backfill2_depth = mandated_backfill2_depth;
  if (mandated_break_chain_depth != -1)
    break_chain_depth = mandated_break_chain_depth;
  if (mandated_superstring_depth != -1)
    superstring_depth = mandated_superstring_depth;
  if (mandated_branch_depth != -1)
    branch_depth = mandated_branch_depth;
  if (mandated_fourlib_depth != -1)
    fourlib_depth = mandated_fourlib_depth;
  if (mandated_ko_depth != -1)
    ko_depth = mandated_ko_depth;
  if (mandated_aa_depth != -1)
    aa_depth = mandated_aa_depth;
  if (mandated_owl_distrust_depth != -1)
    owl_distrust_depth = mandated_owl_distrust_depth;
  if (mandated_owl_branch_depth != -1)
    owl_branch_depth = mandated_owl_branch_depth;
  if (mandated_owl_reading_depth != -1)
    owl_reading_depth = mandated_owl_reading_depth;
  if (mandated_owl_node_limit != -1)
    owl_node_limit = mandated_owl_node_limit;
  if (mandated_semeai_node_limit != -1)
    semeai_node_limit = mandated_semeai_node_limit;

  depth_offset = 0;
  
  if (report_levels) {
    fprintf(stderr, "at level %d:\n\n\
depth: %d\n\
branch_depth: %d\n\
backfill_depth: %d\n\
backfill2_depth: %d\n\
break_chain_depth: %d\n\
owl_distrust_depth: %d\n\
owl_branch_depth: %d\n\
owl_reading_depth: %d\n\
aa_depth: %d\n\
ko_depth: %d\n\
fourlib_depth: %d\n\
superstring_depth: %d\n\
owl_node_limit: %d\n\
semeai_branch_depth: %d\n\
semeai_branch_depth2: %d\n\
semeai_node_limit: %d\n\
connect_depth: %d\n\
connect_depth2: %d\n\
connection_node_limit: %d\n\
breakin_depth: %d\n\
breakin_node_limit: %d\n\n",
	    level, depth, branch_depth, backfill_depth, backfill2_depth,
	    break_chain_depth, owl_distrust_depth, owl_branch_depth,
	    owl_reading_depth, aa_depth, ko_depth, fourlib_depth,
	    superstring_depth, owl_node_limit, semeai_branch_depth, 
	    semeai_branch_depth2, semeai_node_limit, connect_depth, 
            connect_depth2, connection_node_limit, breakin_depth, 
	    breakin_node_limit);
  }
}


static int depth_modification = 0;

/*
 * Modify the various tactical reading depth parameters. This is
 * typically used to avoid horizon effects. By temporarily increasing
 * the depth values when trying some move, one can avoid that an
 * irrelevant move seems effective just because the reading hits a
 * depth limit earlier than it did when reading only on relevant
 * moves.
 */

void
modify_depth_values(int n)
{
  depth              += n;
  backfill_depth     += n;
  backfill2_depth    += n;
  break_chain_depth  += n;
  superstring_depth  += n;
  branch_depth       += n;
  fourlib_depth      += n;
  ko_depth           += n;
  breakin_depth	     += n;
  depth_offset       += n;
  depth_modification += n;
}

void
increase_depth_values(void)
{
  modify_depth_values(1);
}

void
decrease_depth_values(void)
{
  modify_depth_values(-1);
}

int
get_depth_modification(void)
{
  return depth_modification;
}


/*******************
 * Detect blunders *
 *******************/

static int detect_owl_blunder(int move, int color, int *defense_point,
			      signed char safe_stones[BOARDMAX], int liberties,
			      float *return_value, int save_verbose);

static void detect_tactical_blunder(int move, int color, int *defense_point,
				    signed char safe_stones[BOARDMAX],
				    int liberties, int *libs,
				    float *return_value, int save_verbose);

/* Check that the move at color doesn't involve any kind of blunder,
 * regardless of size.
 */
int
confirm_safety(int move, int color, int *defense_point,
	       signed char safe_stones[BOARDMAX])
{
  return (blunder_size(move, color, defense_point, safe_stones) == 0.0);
}

/* This function will detect some blunders. If the move reduces the
 * number of liberties of an adjacent friendly string, there is a
 * danger that the move could backfire, so the function checks that no
 * friendly worm which was formerly not attackable becomes attackable,
 * and it checks that no opposing worm which was not defendable
 * becomes defendable.
 *
 * It returns the estimated size of the blunder, or 0.0 if nothing
 * bad has happened.
 *
 * The array safe_stones[] contains the stones that are supposedly
 * safe after (move). It may be NULL.
 *
 * For use when called from fill_liberty, this function may optionally
 * return a point of defense, which, if taken, will presumably make
 * the move at (move) safe on a subsequent turn.
 */

float
blunder_size(int move, int color, int *defense_point,
	     signed char safe_stones[BOARDMAX])
{
  int libs[5];
  int liberties = accuratelib(move, color, 5, libs);
  int trouble = 0;
  int save_verbose = verbose;
  float return_value = 0.0;
  int atari;
  signed char defense_moves[BOARDMAX];
  
  if (defense_point)
    *defense_point = NO_MOVE;

  TRACE("Checking safety of a %s move at %1m\n", color_to_string(color), move);

  if (verbose > 0)
    verbose--;

  /* We start by checking whether we have accidentally killed an own
   * dragon.
   */
  trouble = detect_owl_blunder(move, color, defense_point,
			       safe_stones, liberties,
			       &return_value, save_verbose);
  

  /* Next we see whether the move has caused tactical complications.
   * The trouble variable is set if a string next to the move with few
   * liberties has not gained liberties by the move.
   */
  if (trouble)
    detect_tactical_blunder(move, color, defense_point, safe_stones,
			    liberties, libs, &return_value, save_verbose);

  /* FIXME: We would also need a detect_semeai_blunder() to check
   * against moves which make the outcome of a semeai worse, e.g. by
   * letting the opponent live in seki.
   */

  
  /* Finally we call the atari-atari code to see whether the move has
   * set up some combination attack that didn't exist before. We do
   * this last to avoid duplicate blunder reports.
   */
  atari = atari_atari_blunder_size(color, move, defense_moves, safe_stones);
  if (atari) {
    if (defense_point) {
      /* FIXME: Choose defense point more systematically. */
      int pos;
      *defense_point = NO_MOVE;
      for (pos = BOARDMIN; pos < BOARDMAX; pos++)
	if (ON_BOARD(pos) && defense_moves[pos]) {
	  *defense_point = pos;
	  break;
	}
    }
    verbose = save_verbose;
    TRACE("Combination attack appears.\n");
    return_value += (float) atari;
  }

  verbose = save_verbose;
  return return_value;
}

/* Check whether we have accidentally killed an own dragon adjacent to
 * move. If this happens, we mark its stones as no longer safe, and
 * remember the dragon's size.
 */

static int
detect_owl_blunder(int move, int color, int *defense_point,
		   signed char safe_stones[BOARDMAX], int liberties,
		   float *return_value, int save_verbose)
{
  int k;
  int ii;
  int trouble = 0;
  int dragon_analyzed[4] = {0, 0, 0, 0};
  int current_verbose = verbose;
  
  for (k = 0; k < 4; k++) {
    int bpos = move + delta[k];
    int j;
    /* We get worried if there is a liberty problem (and in this case
     * there might also be tactical trouble), or if we play inside
     * our eye space and the dragon is only just alive.
     */
    if (board[bpos] != color)
      continue;
    if (liberties <= worm[bpos].liberties
	&& liberties <= 4)
      trouble = 1;
    else
      if (min_eyes(&(DRAGON2(bpos).genus)) > 2
	  || !is_proper_eye_space(move))
	continue;

    /* Don't test the same dragon twice. */
    for (j = 0; j < k; j++)
      if (dragon_analyzed[j] == dragon[bpos].origin)
	break;
    if (j < k)
      continue;
    dragon_analyzed[k] = dragon[bpos].origin;

    /* Don't reanalyze if (move) is an owl defense for (bpos). */
    if (safe_stones && safe_stones[bpos] == OWL_SAVED_STONE)
      continue;

    if ((dragon[bpos].status == ALIVE
	 || (safe_stones 
	     && safe_stones[bpos]))
	&& DRAGON2(bpos).safety != INVINCIBLE
	&& DRAGON2(bpos).safety != STRONGLY_ALIVE) {
      int kworm = NO_MOVE;
      int acode = owl_confirm_safety(move, bpos, defense_point, &kworm);

      /* If owl couldn't confirm safety, maybe semeai can. */
      if (acode != WIN) {
	int r;
	for (r = 0; r < DRAGON2(bpos).neighbors; r++) {
	  int neighbor = dragon2[DRAGON2(bpos).adjacent[r]].origin;
	  int resultb;
	  if (board[neighbor] == color)
	    continue;
	  owl_analyze_semeai_after_move(move, color, neighbor, bpos,
					NULL, &resultb, NULL, 1, NULL, 0);
	  if (resultb == 0)
	    acode = WIN;
	}
      }
      
      if (acode == 0) {
	verbose = save_verbose;
	TRACE("Dragon at %1m becomes attackable.\n", bpos);
	verbose = current_verbose;
	*return_value += 2.0 * dragon[bpos].effective_size;
	if (safe_stones)
	  mark_dragon(bpos, safe_stones, 0);
      }
      else if (acode == LOSS) {
	verbose = save_verbose;
	TRACE("Dragon at %1m becomes attackable.\n", bpos);
	verbose = current_verbose;
	if (kworm == move) {
	  int l;
	  /* the worm origin was messed by our own move */
	  for (l = 0; l < 4; l++) {
	    int kworm = move + delta[l];
	    if (board[kworm] == color) {
	      *return_value += 2.0 * worm[kworm].effective_size;
	      if (safe_stones)
		for (ii = BOARDMIN; ii < BOARDMAX; ii++)
		  if (ON_BOARD(ii) && worm[ii].origin == worm[kworm].origin)
		    safe_stones[ii] = 0;
	    }
	  }
	}
	else {
	  *return_value += 2.0 * worm[kworm].effective_size;
	  if (safe_stones)
	    for (ii = BOARDMIN; ii < BOARDMAX; ii++)
	      if (ON_BOARD(ii) && worm[ii].origin == worm[kworm].origin)
		safe_stones[ii] = 0;
	}
      }
    }
  }

  return trouble;
}

/* Check whether a move causes any unexpected and unwelcome changes in
 * the tactical status of worms all over the board.
 */
static void
detect_tactical_blunder(int move, int color, int *defense_point,
			signed char safe_stones[BOARDMAX],
			int liberties, int *libs,
			float *return_value, int save_verbose)
{
  int other = OTHER_COLOR(color);
  int pos;
  int ii;
  int current_verbose = verbose;

  if (!trymove(move, color, NULL, NO_MOVE))
    return;
  
  /* Need to increase the depth values during this reading to avoid
   * horizon effects.
   */
  increase_depth_values();
  
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (!IS_STONE(board[pos])
	|| worm[pos].origin != pos
	|| pos == move)
      continue;
    
    /* First, we look for a new tactical attack.
     * FIXME: Verify that the tactically attacked stone matters. See
     *        e.g. the D6 move in filllib:51 which invites a harmless
     *        tactical attack of A4.
     */
    if (board[pos] == color
	&& ((safe_stones && safe_stones[pos])
	    || (!safe_stones && worm[pos].attack_codes[0] == 0))
	&& attack(pos, NULL)) {
      /* A safe worm of ours has become attackable. */
      if (defense_point) {
	find_defense(pos, defense_point);
	/* Check that this move is legal and effective also on the
	 * original board, otherwise find a tactical defense there
	 * instead.
	 */
	popgo();
	
	if (!is_legal(*defense_point, color)
	    || play_attack_defend_n(color, 1, 1, *defense_point, pos))
	  find_defense(pos, defense_point);
	
	/* Redo the move, we know that it won't fail. */
	trymove(move, color, NULL, NO_MOVE);
      }
      verbose = save_verbose;
      TRACE("After %1m Worm at %1m becomes attackable.\n", move, pos);
      verbose = current_verbose;
      *return_value += worm[pos].effective_size;
      if (safe_stones) /* Can't use mark_string. */
	for (ii = BOARDMIN; ii < BOARDMAX; ii++)
	  if (worm[ii].origin == worm[pos].origin)
	    safe_stones[ii] = 0;
    }
    else if (board[pos] == other
	     && worm[pos].origin == pos
	     && worm[pos].attack_codes[0] != 0
	     && worm[pos].defense_codes[0] == 0
	     && find_defense(pos, NULL)) {
      /* A dead opponent's worm has become defendable.
       * Also ask the owl code whether the string can live
       * strategically. To do this we need to temporarily undo
       * the trymove().
       */
      int owl_attacks;
      int defense_effective = 0;
      
      popgo();
      decrease_depth_values();
      owl_attacks = owl_does_attack(move, pos, NULL);
      if (owl_attacks != WIN) {
	*return_value += 2 * worm[pos].effective_size;
	defense_effective = 1;
	verbose = save_verbose;
	TRACE("After %1m worm at %1m becomes defendable - A.\n", move, pos);
	verbose = current_verbose;
      }
      else if (dragon[pos].status != ALIVE) {
	/* Before redoing the trymove we also check whether the worm now
	 * has a semeai defense. See blunder:26 for an example.
	 *
	 * If the worm already was alive in seki, it is generally okay
	 * that it also becomes tactically safe when the outer
	 * liberties are filled, see e.g. blunder:32,34. Thus the
	 * check above.
	 */
	int k;
	int adj[MAXCHAIN];
	int num_adj;
	num_adj = extended_chainlinks(pos, adj, 0);
	for (k = 0; k < num_adj; k++) {
	  int neighbor = adj[k];
	  int resulta;
	  owl_analyze_semeai_after_move(move, color, pos, neighbor,
					&resulta, NULL, NULL, 1, NULL, 1);
	  if (resulta != 0) {
	    *return_value += 2 * worm[pos].effective_size;
	    defense_effective = 1;
	    verbose = save_verbose;
	    TRACE("After %1m worm at %1m becomes defendable - B.\n",
		  move, pos);
	    verbose = current_verbose;
	    break;
	  }
	}
      }
      
      trymove(move, color, NULL, NO_MOVE);
      increase_depth_values();
      
      if (defense_effective && defense_point) {
	int dpos;
	if (attack(pos, &dpos)) {
	  *defense_point = dpos;
	  /* Check that this move is legal and effective also on the
           * original board, otherwise find a tactical attack there
           * instead.
	   */
	  popgo();
	  
	  if (!is_legal(dpos, color)
	      || play_attack_defend_n(color, 0, 1, dpos, pos))
	    attack(pos, defense_point);

	  /* Redo the move, we know that it won't fail. */
	  trymove(move, color, NULL, NO_MOVE);
	}
	else {
	  verbose = save_verbose;
	  TRACE("No attack found (unexpectedly) on %1m after move at %1m.\n",
		pos, move);
	  verbose = current_verbose;
	}
      }
    }
  }

  /* Look for double atari style complications of the move.
   *
   * FIXME: Since we have an atari_atari check in blunder_size(), do
   * we still need to do this step?
   */
  if (liberties == 2) {
    float d_a_blunder_size;
    if (double_atari(libs[0], other, &d_a_blunder_size, safe_stones)) {
      if (defense_point && safe_move(libs[0], color) == WIN)
	*defense_point = libs[0];
      *return_value += d_a_blunder_size;
      verbose = save_verbose;
      TRACE("Double threat appears at %1m.\n", libs[0]);
      verbose = current_verbose;
    }
    else if (double_atari(libs[1], other, &d_a_blunder_size, safe_stones)) {
      if (defense_point && safe_move(libs[1], color) == WIN)
	*defense_point = libs[1];
      *return_value += d_a_blunder_size;
      verbose = save_verbose;
      TRACE("Double threat appears at %1m.\n", libs[1]);
      verbose = current_verbose;
    }
  }
  
  /* Reset the depth values. */
  decrease_depth_values();

  popgo();
}


/* Returns true if a move by (color) fits the following shape:
 * 
 *
 *    X*        (O=color)
 *    OX
 * 
 * capturing one of the two X strings. The name is a slight
 * misnomer since this includes attacks which are not necessarily
 * double ataris, though the common double atari is the most
 * important special case.
 * 
 * If safe_stones != NULL, then only attacks on stones marked as safe are
 * tried.
 *
 * The value of the double atari attack is returned in *value (unless
 * value is NULL), and the attacked stones are marked unsafe.
 */

int
double_atari(int move, int color, float *value,
	     signed char safe_stones[BOARDMAX])
{
  int other = OTHER_COLOR(color);
  int k;
  int m = I(move);
  int n = J(move);

  if (!ON_BOARD(move))
    return 0;

  /* Loop over the diagonal directions. */
  for (k = 4; k < 8; k++) {
    int dm = deltai[k];
    int dn = deltaj[k];
    
    /* because (m, n) and (m+dm, n+dn) are opposite
     * corners of a square, ON_BOARD2(m, n) && ON_BOARD2(m+dm, n+dn)
     * implies ON_BOARD2(m+dm, n) and ON_BOARD2(n, n+dn)
     *
     * Only try to attack supposedly safe stones.
     */
    if (BOARD(m+dm, n+dn) == color
	&& BOARD(m, n+dn) == other
	&& BOARD(m+dm, n) == other
	&& (!safe_stones
	    || (safe_stones[POS(m, n+dn)] && safe_stones[POS(m+dm, n)]))
	&& trymove(move, color, "double_atari", NO_MOVE)) {
      if (countlib(move) > 1
	  && (BOARD(m, n+dn) == EMPTY || BOARD(m+dm, n) == EMPTY 
	      || !defend_both(POS(m, n+dn), POS(m+dm, n)))) {
	popgo();
	if (value) {
	  if (worm[POS(m, n+dn)].effective_size
	      > worm[POS(m+dm, n)].effective_size) {
	    *value = 2.0 * worm[POS(m, n+dn)].effective_size;
	    if (safe_stones)
	      mark_string(POS(m, n+dn), safe_stones, 0);
	  }
	  else {
	    *value = 2.0 * worm[POS(m+dm, n)].effective_size;
	    if (safe_stones)
	      mark_string(POS(m+dm, n), safe_stones, 0);
	  }
	}
	return 1;
      }
      popgo();
    }
  }
  
  return 0;
}
    

/* Returns true if a move by (color) plays into a snapback. */
int
playing_into_snapback(int move, int color)
{
  int libs[2];
  int k;
  
  if (approxlib(move, color, 1, NULL) != 0
      || accuratelib(move, color, 2, libs) != 1)
    return 0;

  for (k = 0; k < 4; k++)
    if (board[move + delta[k]] == color
	&& adjacent_strings(libs[0], move + delta[k]))
      return 1;

  return 0;
}


/* Score the game and determine the winner */

void
who_wins(int color, FILE *outfile)
{
  float result;

  silent_examine_position(EXAMINE_DRAGONS);

#if 0
  float white_score;
  float black_score;
  int winner;
#endif

  if (color != BLACK && color != WHITE)
    color = BLACK;

#if 0
  /* Use the aftermath code to compute the final score. (Slower but
   * more reliable.) 
   */
  result = aftermath_compute_score(color, NULL);
  if (result > 0.0)
    winner = WHITE;
  else {
    winner = BLACK;
    result = -result;
  }
#endif

  result = (white_score + black_score)/2.0;
  if (result == 0.0)
    fprintf(outfile, "Result: jigo   ");
  else
    fprintf(outfile, "Result: %c+%.1f   ",
	    (result > 0.0) ? 'W' : 'B', gg_abs(result));
}



/* Find the stones of an extended string, where the extensions are
 * through the following kinds of connections:
 *
 * 1. Solid connections (just like ordinary string).
 *
 *    OO
 *
 * 2. Diagonal connection or one space jump through an intersection
 *    where an opponent move would be suicide or self-atari.
 *
 *    ...
 *    O.O
 *    XOX
 *    X.X
 *
 * 3. Bamboo joint.
 *
 *    OO
 *    ..
 *    OO
 *
 * 4. Diagonal connection where both adjacent intersections are empty.
 *
 *    .O
 *    O.
 *
 * 5. Connection through adjacent or diagonal tactically captured stones.
 *    Connections of this type are omitted when the superstring code is
 *    called from reading.c, but included when the superstring code is
 *    called from owl.c
 */

static void
do_find_superstring(int str, int *num_stones, int *stones,
		    int *num_lib, int *libs, int maxlibs,
		    int *num_adj, int *adjs, int liberty_cap,
		    int proper, int type);

static void
superstring_add_string(int str,
		       int *num_my_stones, int *my_stones,
		       int *num_stones, int *stones,
		       int *num_libs, int *libs, int maxlibs,
		       int *num_adj, int *adjs, int liberty_cap,
		       signed char mx[BOARDMAX],
		       signed char ml[BOARDMAX],
		       signed char ma[BOARDMAX],
		       int do_add);

void
find_superstring(int str, int *num_stones, int *stones)
{
  do_find_superstring(str, num_stones, stones,
		      NULL, NULL, 0,
		      NULL, NULL, 0,
		      0, 1);
}

/* This is the same as find_superstring, except that connections of
 * type 5 are omitted. This is used in semeai analysis.
 */
void
find_superstring_conservative(int str, int *num_stones, int *stones)
{
  do_find_superstring(str, num_stones, stones,
		      NULL, NULL, 0,
		      NULL, NULL, 0,
		      0, 0);
}


/* This function computes the superstring at (str) as described above,
 * but omitting connections of type 5. Then it constructs a list of
 * liberties of the superstring which are not already liberties of
 * (str).
 *
 * If liberty_cap is nonzero, only liberties of substrings of the
 * superstring which have fewer than liberty_cap liberties are
 * generated.
 */

void
find_superstring_liberties(int str,
			   int *num_libs, int *libs, int liberty_cap)
{
  do_find_superstring(str, NULL, NULL,
		      num_libs, libs, MAX_LIBERTIES,
		      NULL, NULL, liberty_cap,
		      0, 0);
}

/* This function is the same as find_superstring_liberties, but it
 * omits those liberties of the string (str), presumably since
 * those have already been treated elsewhere.
 *
 * If liberty_cap is nonzero, only liberties of substrings of the
 * superstring which have at most liberty_cap liberties are
 * generated.
 */

void
find_proper_superstring_liberties(int str, 
				  int *num_libs, int *libs, 
				  int liberty_cap)
{
  do_find_superstring(str, NULL, NULL,
		      num_libs, libs, MAX_LIBERTIES,
		      NULL, NULL, liberty_cap,
		      1, 0);
}

/* This function computes the superstring at (str) as described above,
 * but omitting connections of type 5. Then it constructs a list of
 * liberties of the superstring which are not already liberties of
 * (str).
 *
 * If liberty_cap is nonzero, only liberties of substrings of the
 * superstring which have fewer than liberty_cap liberties are
 * generated.
 */

void
find_superstring_stones_and_liberties(int str,
				      int *num_stones, int *stones,
				      int *num_libs, int *libs,
				      int liberty_cap)
{
  do_find_superstring(str, num_stones, stones,
		      num_libs, libs, MAX_LIBERTIES,
		      NULL, NULL, liberty_cap,
		      0, 0);
}

/* analogous to chainlinks, this function finds boundary chains of the
 * superstring at (str), including those which are boundary chains of
 * (str) itself. If liberty_cap != 0, only those boundary chains with
 * <= liberty_cap liberties are reported.
 */

void
superstring_chainlinks(int str, 
		       int *num_adj, int adjs[MAXCHAIN],
		       int liberty_cap)
{
  do_find_superstring(str, NULL, NULL,
		      NULL, NULL, 0,
		      num_adj, adjs, liberty_cap,
		      0, 2);
}


/* analogous to chainlinks, this function finds boundary chains of the
 * superstring at (str), omitting those which are boundary chains of
 * (str) itself. If liberty_cap != 0, only those boundary chains with
 * <= liberty_cap liberties are reported.
 */

void
proper_superstring_chainlinks(int str,
			      int *num_adj, int adjs[MAXCHAIN],
			      int liberty_cap)
{
  do_find_superstring(str, NULL, NULL,
		      NULL, NULL, 0,
		      num_adj, adjs, liberty_cap,
		      1, 2);
}

/* Do the real work finding the superstring and recording stones,
 * liberties, and/or adjacent strings.
 */
static void
do_find_superstring(int str, int *num_stones, int *stones,
		    int *num_libs, int *libs, int maxlibs,
		    int *num_adj, int *adjs, int liberty_cap,
		    int proper, int type)
{
  int num_my_stones;
  int my_stones[MAX_BOARD * MAX_BOARD];
  
  signed char mx[BOARDMAX]; /* stones */
  signed char ml[BOARDMAX]; /* liberties */
  signed char ma[BOARDMAX]; /* adjacent strings */

  int k, l, r;
  int color = board[str];
  int other = OTHER_COLOR(color);

  memset(mx, 0, sizeof(mx));
  memset(ml, 0, sizeof(ml));
  memset(ma, 0, sizeof(ma));

  if (num_stones)
    *num_stones = 0;
  if (num_libs)
    *num_libs = 0;
  if (num_adj)
    *num_adj = 0;

  /* Include the string itself in the superstring. Only record stones,
   * liberties, and/or adjacent strings if proper==0.
   */
  num_my_stones = 0;
  superstring_add_string(str, &num_my_stones, my_stones,
			 num_stones, stones,
			 num_libs, libs, maxlibs,
			 num_adj, adjs, liberty_cap,
			 mx, ml, ma,
			 !proper);

  /* Loop over all found stones, looking for more strings to include
   * in the superstring. The loop is automatically extended over later
   * found stones as well.
   */
  for (r = 0; r < num_my_stones; r++) {
    int pos = my_stones[r];

    for (k = 0; k < 4; k++) {
      /* List of relative coordinates. (pos) is marked by *.
       *
       *  ef.
       *  gb.
       *  *ac
       *  .d.
       *
       */
      int right = delta[k];
      int up = delta[(k+1)%4];
      
      int apos = pos + right;
      int bpos = pos + right + up;
      int cpos = pos + 2*right;
      int dpos = pos + right - up;
      int epos = pos + 2*up;
      int fpos = pos + right + 2*up;
      int gpos = pos + up;
      int unsafe_move;
      
      if (!ON_BOARD(apos))
	continue;
      
      /* Case 1. Nothing to do since stones are added string by string. */
            
      /* Case 2. */
      if (board[apos] == EMPTY) {
	if (type == 2)
	  unsafe_move = (approxlib(apos, other, 2, NULL) < 2);
	else
	  unsafe_move = is_self_atari(apos, other);
	
	if (unsafe_move && type == 1 && is_ko(apos, other, NULL))
	  unsafe_move = 0;
	
	if (unsafe_move) {
	  if (board[bpos] == color && !mx[bpos])
	    superstring_add_string(bpos, &num_my_stones, my_stones,
				   num_stones, stones,
				   num_libs, libs, maxlibs,
				   num_adj, adjs, liberty_cap,
				   mx, ml, ma, 1);
	  if (board[cpos] == color && !mx[cpos])
	    superstring_add_string(cpos, &num_my_stones, my_stones,
				   num_stones, stones,
				   num_libs, libs, maxlibs,
				   num_adj, adjs, liberty_cap,
				   mx, ml, ma, 1);
	  if (board[dpos] == color && !mx[dpos])
	    superstring_add_string(dpos, &num_my_stones, my_stones,
				   num_stones, stones,
				   num_libs, libs, maxlibs,
				   num_adj, adjs, liberty_cap,
				   mx, ml, ma, 1);
	}
      }
      
      /* Case 3. */
      /* Notice that the order of these tests is significant. We must
       * check bpos before fpos and epos to avoid accessing memory
       * outside the board array. (Notice that fpos is two steps away
       * from pos, which we know is on the board.)
       */
      if (board[apos] == color && board[bpos] == EMPTY
	  && board[fpos] == color && board[epos] == color && !mx[epos]
	  && board[gpos] == EMPTY)
	superstring_add_string(epos, &num_my_stones, my_stones,
			       num_stones, stones,
			       num_libs, libs, maxlibs,
			       num_adj, adjs, liberty_cap,
			       mx, ml, ma, 1);
      /* Don't bother with f, it is part of the string just added. */
      
      /* Case 4. */
      if (board[bpos] == color && !mx[bpos]
	  && board[apos] == EMPTY && board[gpos] == EMPTY)
	superstring_add_string(bpos, &num_my_stones, my_stones,
			       num_stones, stones,
			       num_libs, libs, maxlibs,
			       num_adj, adjs, liberty_cap,
			       mx, ml, ma, 1);
      
      /* Case 5. */
      if (type == 1)
	for (l = 0; l < 2; l++) {
	  int upos;
	  
	  if (l == 0) {
	    /* adjacent lunch */
	    upos = apos;
	  }
	  else {
	    /* diagonal lunch */
	    upos = bpos;
	  }
	  
	  if (board[upos] != other)
	    continue;
	  
	  upos = find_origin(upos);
	  
	  /* Only do the reading once. */
	  if (mx[upos] == 1)
	    continue;
	  
	  mx[upos] = 1;
	  
	  if (attack(upos, NULL)
	      && !find_defense(upos, NULL)) {
	    int lunch_stones[MAX_BOARD*MAX_BOARD];
	    int num_lunch_stones = findstones(upos, MAX_BOARD*MAX_BOARD,
					      lunch_stones);
	    int m, n;
	    for (m = 0; m < num_lunch_stones; m++)
	      for (n = 0; n < 8; n++) {
		int vpos = lunch_stones[m] + delta[n];
		if (board[vpos] == color && !mx[vpos])
		  superstring_add_string(vpos,
					 &num_my_stones, my_stones,
					 num_stones, stones,
					 num_libs, libs, maxlibs,
					 num_adj, adjs, liberty_cap,
					 mx, ml, ma, 1);
	      }
	  }
	}
      if (num_libs && maxlibs > 0 && *num_libs >= maxlibs)
	return;
    }
  }
}

/* Add a new string to a superstring. Record stones, liberties, and
 * adjacent strings as asked for.
 */
static void
superstring_add_string(int str,
		       int *num_my_stones, int *my_stones,
		       int *num_stones, int *stones,
		       int *num_libs, int *libs, int maxlibs,
		       int *num_adj, int *adjs, int liberty_cap,
		       signed char mx[BOARDMAX],
		       signed char ml[BOARDMAX],
		       signed char ma[BOARDMAX],
		       int do_add)
{
  int num_my_libs;
  int my_libs[MAXLIBS];
  int num_my_adj;
  int my_adjs[MAXCHAIN];
  int new_stones;
  int k;
  
  ASSERT1(mx[str] == 0, str);

  /* Pick up the stones of the new string. */
  new_stones = findstones(str, board_size * board_size,
			  &(my_stones[*num_my_stones]));
  
  mark_string(str, mx, 1);
  if (stones) {
    gg_assert(num_stones);
    for (k = 0; k < new_stones; k++) {
      if (do_add) {
	stones[*num_stones] = my_stones[*num_my_stones + k];
	(*num_stones)++;
      }
    }
  }
  (*num_my_stones) += new_stones;

  /* Pick up the liberties of the new string. */
  if (libs) {
    gg_assert(num_libs);
    /* Get the liberties of the string. */
    num_my_libs = findlib(str, MAXLIBS, my_libs);

    /* Remove this string from the superstring if it has too many
     * liberties.
     */
    if (liberty_cap > 0 && num_my_libs > liberty_cap)
      (*num_my_stones) -= new_stones;

    for (k = 0; k < num_my_libs; k++) {
      if (ml[my_libs[k]])
	continue;
      ml[my_libs[k]] = 1;
      if (do_add && (liberty_cap == 0 || num_my_libs <= liberty_cap)) {
	libs[*num_libs] = my_libs[k];
	(*num_libs)++;
	if (*num_libs == maxlibs)
	  break;
      }
    }
  }

  /* Pick up adjacent strings to the new string. */
  if (adjs) {
    gg_assert(num_adj);
    num_my_adj = chainlinks(str, my_adjs);
    for (k = 0; k < num_my_adj; k++) {
      if (liberty_cap > 0 && countlib(my_adjs[k]) > liberty_cap)
	continue;
      if (ma[my_adjs[k]])
	continue;
      ma[my_adjs[k]] = 1;
      if (do_add) {
	adjs[*num_adj] = my_adjs[k];
	(*num_adj)++;
      }
    }
  }
}

/* Internal timers for assessing time spent on various tasks. */
#define NUMBER_OF_TIMERS 4
static double timers[NUMBER_OF_TIMERS];

/* Start a timer. */
void
start_timer(int n)
{
  gg_assert(n >= 0 && n < NUMBER_OF_TIMERS);
  if (!showtime)
    return;

  timers[n] = gg_cputime();
}

/* Report time spent and restart the timer. Make no report if elapsed
 * time is less than mintime.
 */
double
time_report(int n, const char *occupation, int move, double mintime)
{
  double t;
  double dt;
  gg_assert(n >= 0 && n < NUMBER_OF_TIMERS);

  if (!showtime)
    return 0.0;

  t = gg_cputime();
  dt = t - timers[n];
  if (dt > mintime) {
    gprintf("%s", occupation);
    if (move != NO_MOVE)
      gprintf("%1m", move);
    fprintf(stderr, ": %.2f sec\n", dt);
  }
  timers[n] = t;
  return dt;
}

void
clearstats()
{
  stats.nodes                    = 0;
  stats.read_result_entered      = 0;
  stats.read_result_hits         = 0;
  stats.trusted_read_result_hits = 0;
}
  
void
showstats()
{
  gprintf("Nodes:                    %d\n", stats.nodes);
  gprintf("Read results entered:     %d\n", stats.read_result_entered);
  gprintf("Read result hits:         %d\n", stats.read_result_hits);
  gprintf("Trusted read result hits: %d\n", stats.trusted_read_result_hits);
}


/* Set up a compiled in pattern database for use by the Monte Carlo
 * code. If name is NULL, the first pattern database is used.
 *
 * The reason why this function and the next are placed here rather
 * than in montecarlo.c is to keep that file free from dependency on
 * patterns.h.
 */
int
choose_mc_patterns(char *name)
{
  int k;
  for (k = 0; mc_pattern_databases[k].name; k++) {
    if (!name || strcmp(name, mc_pattern_databases[k].name) == 0) {
      mc_init_patterns(mc_pattern_databases[k].values);
      return 1;
    }
  }

  return 0;
}

/* List compiled in Monte Carlo pattern databases. */
void
list_mc_patterns(void)
{
  int k;
  printf("Available builtin Monte Carlo local patterns:\n\n");
  for (k = 0; mc_pattern_databases[k].name; k++) {
    if (k == 0)
      printf("* %s (default)\n", mc_pattern_databases[k].name);
    else
      printf("* %s\n", mc_pattern_databases[k].name);
  }
  printf("\nUse \"--mc-patterns name\" to choose one of these.\n");
  printf("Use \"--mc-load-patterns filename\" to directly load a pattern database.\n");
}

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