Index: engine/breakin.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/breakin.c,v
retrieving revision 1.21
diff -u -p -r1.21 breakin.c
--- engine/breakin.c	8 Oct 2005 08:10:26 -0000	1.21
+++ engine/breakin.c	14 Oct 2005 00:18:31 -0000
@@ -411,7 +411,7 @@ break_territories(int color_to_move, str
   struct moyo_data territories;
   int k;
 
-  if (!experimental_break_in || level < 10)
+  if (!experimental_break_in || get_level() < 10)
     return;
 
   influence_get_territory_segmentation(q, &territories);
Index: engine/clock.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/clock.c,v
retrieving revision 1.23
diff -u -p -r1.23 clock.c
--- engine/clock.c	12 Jun 2005 09:34:13 -0000	1.23
+++ engine/clock.c	14 Oct 2005 00:18:32 -0000
@@ -35,79 +35,49 @@
  *                                                               *
 \* ============================================================= */
 
-#include "gnugo.h"
-
-#include "liberty.h"
-#include "gg_utils.h"
 #include "clock.h"
+#include "gg_utils.h"
+#include "board.h"
 
-/* parameters */
-#define CLOCK_MAX_MOVES           500   /* max number of moves for a game */
-#define CLOCK_STEP                0.4   /* modification step for level */
-#define CLOCK_HURRY               10    /* Last chance limit: */
-#define CLOCK_HURRYR              0.02  /* (10 sec or or 2% of main_time) */
-#define CLOCK_HURRY_LEVEL         1     /* Last chance level: */
-#define CLOCK_SAFE                300   /* Keep Ahead limit: */
-#define CLOCK_SAFER               0.20  /* (5min or 20% of time) */
-#define CLOCK_DELTA               10    /* Maximal time difference: */
-#define CLOCK_DELTAR              0.10  /* 10sec or 10% of left time */
-#define CLOCK_TIME_CONTRACT       0.75  /* 75% of time to play */
-#define CLOCK_MOVE_CONTRACT(b)    (((b)*(b))/2)
-#define CLOCK_CONTRACT_MIN_LEVEL  5
+/* Level data */
+static int level             = DEFAULT_LEVEL; /* current level */
+static int level_offset      = 0;
+static int min_level         = 0;
+static int max_level         = gg_max(DEFAULT_LEVEL, 10);
 
 
 /*************************/
 /* Datas and other stuff */
 /*************************/
 
-typedef struct {
-
-  /* clock parameters */
-  int    clock_on;
-  int    ready;
-  double main_time;
-  double byoyomi_time; /* zero if no byo-yomi */
-  int    byoyomi_stones;
-
-  /* clock status */
-  double timer[3];
-  double btimer[3];
-  int    byoyomi[3];
-  int    dead[3];
-
-  /* dates of each move */
-  int    moveno; /* invariant: COLOR(clk.moveno) = color of last move */
-  double date[CLOCK_MAX_MOVES];
-
-  /* adapative system parameters */
-  int    autolevel_on;
-  double level;  /* FIXME: Why is this a double and not an int? */
-  double levels[CLOCK_MAX_MOVES];
-  double expected[CLOCK_MAX_MOVES];
-  double error; /* time/move estimation error */
-} gnugo_clock;
-
-static gnugo_clock clk;
-
-/* Color macro:
- *   WHITE : odd moves
- *   BLACK : even moves. 
- */
-#define COLOR(m)  ((m) % 2 ? WHITE : BLACK)
-
-
-static const char *pname[3] = {"     ", "White", "Black"};
-
-
-/* forward declarations */
-
-static double estimate_time_by_move(int color, int move);
+/* clock parameters */
+static int main_time = -1;
+static int byoyomi_time = -1;
+static int byoyomi_stones = -1; /* <= 0 if no byo-yomi */
+
+/* Keep track of the remaining time left.
+ * If stones_left is zero, .._time_left is the remaining main time.
+ * Otherwise, the remaining time for this byoyomi period.
+ */
+struct remaining_time_data {
+  double time_left;
+  double time_for_last_move;
+  int stones;
+  int movenum;
+  int in_byoyomi;
+};
 
+struct timer_data {
+  struct remaining_time_data official;
+  struct remaining_time_data estimated;
+  int time_out;
+};
 
+static struct timer_data black_time_data;
+static struct timer_data white_time_data;
 
 
 /* Echo a time value in STANDARD format */
-
 static void
 timeval_print(FILE *outfile, double tv)
 {
@@ -120,312 +90,170 @@ timeval_print(FILE *outfile, double tv)
   fprintf(outfile, "%3dmin %.2fsec ", min, sec);
 }
 
-/******************************/
-/*  Initialization functions  */
-/******************************/
-
 
-/*
- * Initialize the structure.
- * -1 means "do not modify this value".
- * clock_init(-1, -1, -1) only resets the clock.
- */
+/* Print the clock status for one side. */
 void
-clock_init(int time, int byo_time, int byo_stones)
+clock_print(int color)
 {
-  int color;
+  struct timer_data* const td
+    = (color == BLACK) ? &black_time_data : &white_time_data;
 
-  if (time > 0) {
-    clk.main_time = time;
-    clk.ready = 1;
-  }
-
-  if (byo_time >= 0)
-    clk.byoyomi_time = byo_time;
+  fprintf(stderr, "clock: "); 
+  fprintf(stderr, "%s ", color_to_string(color));
 
-  if (byo_stones >= 0)
-    clk.byoyomi_stones = byo_stones;
+  if (td->time_out)
+    fprintf(stderr, "TIME OUT! ");
+  else {
+    if (td->estimated.in_byoyomi) {
+      fprintf(stderr, "byoyomi");
+      timeval_print(stderr, td->estimated.time_left);
+      fprintf(stderr, "for %d stones.", td->estimated.stones);
+    }
+    else
+      timeval_print(stderr, td->estimated.time_left);
 
-  clk.moveno = -1;
-  for (color = WHITE; color <= BLACK; color++) {
-    clk.timer[color] = 0;
-    clk.btimer[color] = 0;
-    clk.byoyomi[color] = 0;
-    clk.dead[color] = 0;
   }
+  fprintf(stderr, "\n");
 }
 
 
-/*
- * Activate the clock.
- */
-void 
-clock_enable(void)
-{
-  gg_assert(clk.ready);
-  clk.clock_on = 1;
-}
-
-/*
- * Activate Autolevel.
- */
-void 
-clock_enable_autolevel(void)
-{
-  gg_assert(clk.clock_on);
-  clk.autolevel_on = 1;
-}
-
-
-/***********************/
-/*  Access functions.  */
-/***********************/
-
-
-/* 
- * Maintain timers and all stuff up to date
- * (used by push_button).
- */
-static void
-clock_byoyomi_update(int color, double dt)
-{
-  gg_assert(clk.moveno > 0);
-
-  /* update byoyomi timer */
-  if (clk.byoyomi[color])
-    clk.btimer[color] = clk.btimer[color] + dt;
- 
-  /* Check if player is just begining byoyomi. */
-  if (clk.timer[color] < clk.main_time && !clk.byoyomi[color]) {
-    clk.byoyomi[color] = clk.moveno;
-    clk.btimer[color] = dt;
-  }
-  
-  /* Check if player is time-out. */
-  clk.dead[color] |= (clock_is_byoyomi(color)
-		      && clk.byoyomi_time < clk.btimer[color]);
-
-  /* Check byoyomi period reset. */
-  if (clk.byoyomi[color]
-      && clk.moveno - clk.byoyomi[color] == 2 * clk.byoyomi_stones - 1) {
-    clk.byoyomi[color] = clk.moveno;
-    clk.btimer[color] = 0;
-  }
-}
-
+/******************************/
+/*  Initialization functions  */
+/******************************/
 
 /*
- * Update the clock.
+ * Initialize the time settings for this game.
+ * -1 means "do not modify this value".
  */
 void
-clock_push_button(int color)
-{
-  double now, dt, tme;
-
-  if (!clk.clock_on)
-    return;
-
-  now = gg_gettimeofday();
-  gg_assert(clk.ready);
-
-  /* time/move estimation */
-  tme = estimate_time_by_move(color, clk.moveno);
-
-  /* first move */
-  if (clk.moveno == -1) {
-    /* fprintf(stderr, "clock: first move by %s.\n", pname[color]); */
-    clk.moveno++;
-    clk.date[0] = now;
-
-    if (color != BLACK) { /* do an empty move for BLACK */
-      clk.date[1] = now;
-      clk.moveno++;
-    }
-    return;
-  }
-
-  /* fprintf(stderr, "clock: %s push the button.\n", pname[color]);*/
-  /* fprintf(stderr, "clock: %s's turn.\n", pname[COLOR(clk.moveno+1)]);*/
-
-  /* Pushing twice on the button does nothing. */
-  if (color != COLOR(clk.moveno+1)) {
-    fprintf(stderr, "clock: double push.\n");
-    return;
-  }
-
-  /* Other moves (clk. moveno > -1) */
-  clk.moveno++;
-  gg_assert(clk.moveno < CLOCK_MAX_MOVES);
-  clk.date[clk.moveno] = now;
-
-  /* Update main timer. */
-  dt = clk.date[clk.moveno] - clk.date[clk.moveno - 1];
-  clk.timer[color] += dt;
-
-  /* Estimate prediction error for next move. */
-  if (clk.moveno > 11)
-    clk.error = (clk.error + 2 * gg_abs(dt-tme))/3;
-  else
-    clk.error = 3.0;
-
-  clock_byoyomi_update(color, dt);
-  clock_print(color);
-}
-
-
-/*
- * Unplay a move.
- */
-void 
-clock_unpush_button(int color)
+clock_settings(int time, int byo_time, int byo_stones)
 {
-  double dt;
-
-  if (!clk.clock_on)
-    return;
-     
-  gg_assert(clk.ready);
-  gg_assert(color == COLOR(clk.moveno));
-
-  if (clk.moveno < 1) {
-    clock_init(-1, -1, -1);
-    return;
-  }
-
-  /* Update main timer. */
-  dt = clk.date[clk.moveno] - clk.date[clk.moveno - 1];
-  clk.timer[color] -= dt;
-  clk.moveno--;
-
-  /* Check if back from byoyomi. */
-  if (clk.timer[color] < clk.main_time) {
-    clk.byoyomi[color] = 0;
-    clk.btimer[color] = 0;
-  }
-     
-  /* Update byoyomi timer. */
-  if (clk.byoyomi[color])
-    clk.btimer[color] -= dt;
-
-  clock_print(color);
+  if (time >= 0)
+    main_time = time;
+  if (byo_time >= 0)
+    byoyomi_time = byo_time;
+  if (byo_stones >= 0)
+    byoyomi_stones = byo_stones;
+  init_timers();
 }
 
-
-/*
- * return the (exact) main timer value.
+/* Get time settings. Returns 1 if any time settings have been made,
+ * 0 otherwise.
  */
-double
-clock_get_timer(int color)
+int
+get_clock_settings(int *t, int *byo_t, int *byo_s)
 {
-  double dt;
-
-  gg_assert(clk.clock_on && clk.ready);
-
-  dt = gg_gettimeofday() - clk.date[clk.moveno];
-
-  if (COLOR(clk.moveno) != color)
-    return clk.timer[color] + dt;
-  else 
-    return clk.timer[color];
+  if (t)
+    *t = main_time;
+  if (byo_t)
+    *byo_t = byoyomi_time;
+  if (byo_s)
+    *byo_s = byoyomi_stones;
+  return (main_time >= 0 || byoyomi_time >= 0);
 }
 
 
-/*
- * Give the time left or negative if in byoyomi.
- */
-double  
-clock_get_time_left(int color)
+/* Initialize all timers. */
+void
+init_timers()
 {
-  return clk.main_time - clock_get_timer(color);
-}
-
+  white_time_data.official.time_left = main_time;
+  white_time_data.official.time_for_last_move = -1.0;
+  white_time_data.official.stones = 0;
+  white_time_data.official.movenum = 0;
+  white_time_data.official.in_byoyomi = 0;
+  white_time_data.estimated = white_time_data.official;
+  white_time_data.time_out = 0;
+  black_time_data = white_time_data;
 
-/*
- * Check if color is (officially) in byoyomi.
- */
-int
-clock_is_byoyomi(int color)
-{
-  return clock_get_time_left(color) < 0;
+  level_offset = 0;
 }
 
 
-/*
- * Return the (exact) main timer value.
- */
-double
-clock_get_btimer(int color)
-{
-  double dt;
-  
-  /* sanity check */
-  gg_assert(clk.clock_on && clk.ready);
-  dt = gg_gettimeofday() - clk.date[clk.moveno];
-
-  if (COLOR(clk.moveno) != color)
-    return clk.btimer[color] + dt;
-  else 
-    return clk.btimer[color];
-}
+/*****************************/
+/*  Clock access functions.  */
+/*****************************/
 
 
-/*
- * Get The Byoyomi time left and the number of stones to play.
- */
-double
-clock_get_btime_left(int color, int *stones)
+void
+update_time_left(int color, int time_left, int stones)
 {
-  if (stones != NULL)
-    *stones = clk.byoyomi_stones - (clk.moveno - clk.byoyomi[color]) / 2;
-
-  return clk.byoyomi_time - clock_get_btimer(color);
+  struct timer_data* const td
+    = ((color == BLACK) ? &black_time_data : &white_time_data);
+  int time_used = td->official.time_left - time_left;
+
+  /* Did our estimate for time usage go wrong? */
+  if (time_used > 0
+      && gg_abs(time_used - td->estimated.time_for_last_move) >= 1.0)
+    td->estimated.time_for_last_move = time_used;
+  td->estimated.stones = stones;
+  td->estimated.movenum = movenum;
+  /* Did our clock go wrong? */
+  if (gg_abs(td->estimated.time_left - time_left) >= 1.0)
+    td->estimated.time_left = time_left;
+  if (stones > 0)
+    td->estimated.in_byoyomi = 1;
+
+  td->official.stones = stones;
+  td->official.movenum = movenum;
+  td->official.time_for_last_move = td->official.time_for_last_move - time_left;
+  td->official.time_left = time_left;
+  td->official.in_byoyomi = td->estimated.in_byoyomi;
 }
 
-
 /*
- * Check if a player is time over.
+ * Update the estimated timer after a move has been made.
  */
-int
-clock_is_time_over(int color)
-{
-  return clock_is_byoyomi(color) && clock_get_btime_left(color, NULL) <= 0;
-}
-
-
 void
-clock_print(int color)
+clock_push_button(int color)
 {
-  double tleft;
-  int stones;
-
-  if (!clk.clock_on)
-    return;
-
-  gg_assert(clk.ready);
-
-  fprintf(stderr, "clock: "); 
-  fprintf(stderr, "%s ", pname[color]);
-
-  if (clock_is_time_over(color))
-    fprintf(stderr, "TIME OUT! ");
-  else {
-    if (clock_is_byoyomi(color))
-      tleft = clock_get_btime_left(color, &stones);
-    else
-      tleft = clock_get_time_left(color);
-      
-    if (clock_is_byoyomi(color)) {
-      fprintf(stderr, "byoyomi");
-      timeval_print(stderr, tleft);
-      fprintf(stderr, "for %d stones.\n", stones);
+  static double last_time = -1.0;
+  static int last_movenum = -1;
+  struct timer_data* const td
+    = (color == BLACK) ? &black_time_data : &white_time_data;
+  double now = gg_gettimeofday();
+
+  if (last_movenum >= 0
+      && movenum == last_movenum + 1
+      && movenum > td->estimated.movenum) {
+    double time_used = now - last_time;
+    td->estimated.time_left -= time_used;
+    td->estimated.movenum = movenum;
+    td->estimated.time_for_last_move = time_used;
+    if (td->estimated.time_left < 0) {
+      if (td->estimated.in_byoyomi || byoyomi_stones == 0) {
+	DEBUG(DEBUG_TIME, "%s ran out of time.\n", color_to_string(color));
+	if (debug & DEBUG_TIME)
+	  clock_print(color);
+	td->time_out = 1;
+      }
+      else {
+	/* Entering byoyomi. */
+	gg_assert(!(td->estimated.in_byoyomi));
+	td->estimated.in_byoyomi = 1;
+	td->estimated.stones = byoyomi_stones - 1;
+	td->estimated.time_left += byoyomi_time;
+	if (td->estimated.time_left < 0)
+	  td->time_out = 1;
+      }
+    }
+    else if (td->estimated.stones > 0) {
+      gg_assert(td->estimated.in_byoyomi);
+      td->estimated.stones = td->estimated.stones - 1;
+      if (td->estimated.stones == 0) {
+	td->estimated.time_left = byoyomi_time;
+	td->estimated.stones = byoyomi_stones;
+      }
     }
-    else
-      timeval_print(stderr, tleft);
-
   }
-  fprintf(stderr, "\n");
-}
 
+  last_movenum = movenum;
+  last_time = now;
+
+  /* Update main timer. */
+  if (debug & DEBUG_TIME)
+    clock_print(color);
+}
 
 
 /**********************/
@@ -433,199 +261,136 @@ clock_print(int color)
 /**********************/
 
 
+/* Analyze the two most recent time reports and determine the time
+ * spent on the last moves, the (effective) number of stones left and
+ * the (effective) remaining time.
+ */
+static int
+analyze_time_data(int color, double *time_for_last_move, double *time_left,
+		  int *stones_left)
+{
+  struct remaining_time_data * const timer
+    = (color == BLACK) ? &black_time_data.estimated
+	               : &white_time_data.estimated;
 
-/* Write the time/move to outfile */
-void 
-clock_report_autolevel(FILE *outfile, int color)
-{
-  int i, first;
-  double dt, est, exp;
-
-  if (!clk.autolevel_on)
-    return;
+  /* Do we have any time limits. */
+  if (!get_clock_settings(NULL, NULL, NULL))
+    return 0;
 
-  if (outfile == NULL)
-    outfile = fopen("autolevel.dat", "w");
-  if (outfile == NULL)
-    return;
+  /* If we don't have consistent time information yet, just return. */
+  if (timer->time_for_last_move < 0.0)
+    return 0;
 
-  fprintf(outfile, "#\n#  level  prediction   expected  time/move\n");  
-  fprintf(outfile, "#-----------------------------------------\n"); 
+  *time_for_last_move = timer->time_for_last_move;
 
-  if (color == WHITE)
-    first = 8;
-  else
-    first = 9;
-
-  for (i = first; i < clk.moveno; i += 2) {
-    dt = clk.date[i+1] - clk.date[i];
-    est = estimate_time_by_move(color, i);
-    exp = clk.expected[i + 1];
-    fprintf(outfile, "%5.2f  %5.2f  %5.2f  %5.2f\n",
-	    clk.levels[i + 1], est, exp, dt);
+  if (timer->stones == 0) {
+    /* Main time running. */
+    *time_left = timer->time_left + byoyomi_time;
+    if (byoyomi_time > 0)
+      *stones_left = byoyomi_stones;
+    else {
+      /* Absolute time. Here we aim to be able to play at least X more
+       * moves or a total of Y moves. We choose Y as a third of the
+       * number of vertices and X as 40% of Y. For 19x19 this means
+       * that we aim to play at least a total of 120 moves
+       * (corresponding to a 240 move game) or another 24 moves.
+       *
+       * FIXME: Maybe we should use the game_status of
+       * influence_evaluate_position() here to guess how many moves
+       * are remaining.
+       */
+      int nominal_moves = board_size * board_size / 3;
+      *stones_left = gg_max(nominal_moves - movenum / 2,
+			    2 * nominal_moves / 5);
+    }
+  }
+  else {
+    *time_left = timer->time_left;
+    *stones_left = timer->stones;
   }
+  return 1;
 }
 
 
-/* 
- * Give an estimation of the time/move 
- * based on the last played move.
+/* Adjust the level offset given information of current playing speed
+ * and remaining time and stones.
  */
-
-/* coeficients to estimate time/move */
-static const double 
-coef[5] = {
-  1.0/15.0, 2.0/15.0, 3.0/15.0, 4.0/15.0, 5.0/15.0 
-};
-
-static double
-estimate_time_by_move(int color, int move)
+void
+adjust_level_offset(int color)
 {
-  double res;
-  int i;
+  double time_for_last_move;
+  double time_left;
+  int stones_left;
 
-  if (move <= 10)
-    return 0;
+  if (!analyze_time_data(color, &time_for_last_move, &time_left, &stones_left))
+    return;
 
-  gg_assert(COLOR(move) == OTHER_COLOR(color));
 
-  res = 0;
-  for (i = 0; i < 5; i++)
-    res += coef[i] * (clk.date[move-9+i*2] - clk.date[move-10+i*2]);
-  
-  return res;
+  /* These rules are both crude and ad hoc.
+   *
+   * FIXME: Use rules with at least some theoretical basis.
+   */
+  if (time_left < time_for_last_move * (stones_left + 3))
+    level_offset--;
+  if (time_left < time_for_last_move * stones_left)
+    level_offset--;
+  if (3 * time_left < 2 * time_for_last_move * stones_left)
+    level_offset--;
+  if (2 * time_left < time_for_last_move * stones_left)
+    level_offset--;
+  if (3 * time_left < time_for_last_move * stones_left)
+    level_offset--;
+
+  if (time_for_last_move == 0)
+    time_for_last_move = 1;
+  if (time_left > time_for_last_move * (stones_left + 6))
+    level_offset++;
+  if (time_left > 2 * time_for_last_move * (stones_left + 6))
+    level_offset++;
+
+  if (level + level_offset < min_level)
+    level_offset = min_level - level;
+
+  if (level + level_offset > max_level)
+    level_offset = max_level - level;
+
+  DEBUG(DEBUG_TIME, "New level %d (%d %C %f %f %d)\n", level + level_offset,
+	movenum / 2, color, time_for_last_move, time_left, stones_left);
 }
 
 
-/* 
- * Try to respect a "time contract". 
- */
-static void 
-respect_time_contract(int color)
-{
-  double time_left, expected_tm, predicted_tm;
-  double moves_left;
-
-  fprintf(stderr, "\n*** time contract:\n");
-
-  predicted_tm = estimate_time_by_move(color, clk.moveno);
+/********************************/
+/* Interface to level settings. */
+/********************************/
 
-  /* Compute the expected mean time/move 
-   * to respect the contract.
-   */
-  moves_left = (CLOCK_MOVE_CONTRACT(board_size) - clk.moveno) / 2.0;
-  time_left = (clock_get_time_left(color)
-	       - (1.0 - CLOCK_TIME_CONTRACT) * clk.main_time);
-  expected_tm = time_left / moves_left;
-
-  clk.expected[clk.moveno + 1] = expected_tm;
-
-  fprintf(stderr, "%4.0f moves ", moves_left);
-  fprintf(stderr, "must be played in %.2fsec\n", time_left);
-  fprintf(stderr, "time/move: prediction=%.2f", predicted_tm);
-  fprintf(stderr, "+/-%.2fsec --> ", clk.error);
-  fprintf(stderr, "expected=%.2f\n", expected_tm);
-
-  /* Compare this result with the prediction
-   * (up to prediction error estimation)
-   * and update the level.
-   */ 
-  if (clk.level > CLOCK_CONTRACT_MIN_LEVEL)
-    if ((predicted_tm - clk.error) > expected_tm)
-      clk.level -= CLOCK_STEP;
-  if ((predicted_tm + clk.error) < expected_tm)
-    clk.level += CLOCK_STEP;
+int
+get_level()
+{
+  return level + level_offset;
 }
 
-
-/* 
- * Try to keep gnugo ahead on the clock. 
- */
-static void
-keep_ahead(int color)
+void
+set_level(int new_level)
 {
-  double dt, st, delta_max;
-
-  fprintf(stderr, "*** safe limit reached: trying to keep ahead\n");
-
-  dt = clock_get_time_left(color) - clock_get_time_left(OTHER_COLOR(color));
-  st = clock_get_time_left(color) + clock_get_time_left(OTHER_COLOR(color));
-  delta_max = gg_max(CLOCK_DELTA, CLOCK_DELTAR * st);
-
-  fprintf(stderr, "deltamax: %gsec, delta=%gsec => ", delta_max, dt);
-      
-  if (dt < -delta_max) {
-    fprintf(stderr, "behind\n");
-    clk.level -= CLOCK_STEP;
-  }
-  else {
-    if (dt > delta_max) {
-      fprintf(stderr, "ahead\n");
-      clk.level += CLOCK_STEP;
-    }
-    else
-      fprintf(stderr, "equal\n");
-  }
+  level = new_level;
+  level_offset = 0;
+  if (level > max_level)
+    max_level = level;
+  if (level < min_level)
+    min_level = level;
 }
 
-
-/* 
- * Modify the level during a game to avoid losing by time.
- */
 void
-clock_adapt_level(int *p_level, int color)
+set_max_level(int new_max)
 {
-  double hurry_limit, safe_limit;
-
-  /* 
-   * Do not touch the level during the first 10 moves
-   * to estimate time/move on a reasonable sample.
-   */
-  if (clk.moveno < 10 || !clk.autolevel_on) {
-    clk.level = *p_level;
-    clk.levels[clk.moveno + 1] = clk.level;
-    return;
-  }
-  
-  /* 
-   * Hurry strategy:
-   * Behind this limit the only priority is finish at all costs.
-   */
-  hurry_limit = gg_max(CLOCK_HURRY, CLOCK_HURRYR * clk.main_time);
-  if (clock_get_time_left(color) < hurry_limit) {
-    fprintf(stderr, "*** hurry limit reached:\n");
-    clk.level = CLOCK_HURRY_LEVEL;
-    *p_level = clk.level;
-    return;
-  }
-
-  /* 
-   * Time contract strategy:
-   * try to respect the time of a standard game. 
-   */
-  if (clk.moveno < CLOCK_MOVE_CONTRACT(board_size))
-    respect_time_contract(color);
-
-  /* 
-   * Keep ahead strategy:
-   * When the safe_limit is reached gnugo tries to keep ahead in time.
-   */
-  safe_limit = gg_max(CLOCK_SAFE, CLOCK_SAFER * clk.main_time);
-  if (clock_get_time_left(color) < safe_limit) 
-    keep_ahead(color);
-
-  /* Update the level. */
-  if (clk.level > (double) max_level)
-    clk.level = (double) max_level;
-  if (clk.level < (double) min_level)
-    clk.level = (double) min_level;
-
-  clk.levels[clk.moveno + 1] = clk.level;
-  *p_level = clk.level;
-  
-  fprintf(stderr, "level %4.1f at move %d\n", clk.level, movenum);
+  max_level = new_max;
 }
 
+void
+set_min_level(int new_min)
+{
+  min_level = new_min;
+}
 
 
 /*
Index: engine/clock.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/clock.h,v
retrieving revision 1.11
diff -u -p -r1.11 clock.h
--- engine/clock.h	12 Jun 2005 09:34:13 -0000	1.11
+++ engine/clock.h	14 Oct 2005 00:18:32 -0000
@@ -23,67 +23,25 @@
 #ifndef _CLOCK_H_
 #define _CLOCK_H_
 
-/* ============================================================= *\
- *                        Time handling                          *
- *                          for GNU Go                           *
- *                         __       __                           *
- *                        <  >     <  >                          *
- *                      +--++-------++--+                        *
- *                      |  .'11 12 1'.  |                        *
- *                      |  :10 \    2:  |                        *
- *                      |  :9   @-> 3:  |                        *
- *                      |  :8       4;  |                        *
- *                      |  '..7 6 5..'  |                        *
- *                      |_______________|                        *
- *                                                               *
-\* ============================================================= */
-
-#include <stdio.h>
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 #include "gnugo.h"
 
-#ifdef HAVE_VISUAL_C
-#include <winsock.h>
-#include <io.h>
-#include <time.h>
-#else
-#include <sys/time.h>
-#endif
-
-#ifdef __MINGW32__
-#include <windows.h>
-#include <winsock.h>
-#include <io.h>
-#endif
-
-/* interface */
- 
 /* initialization and activation */
-void clock_init(int time, int byo_time, int byo_stones);
-void clock_enable(void);
+void clock_settings(int time, int byo_time, int byo_stones);
+void init_timers(void);
  
-void clock_enable_autolevel(void);
-
 /* main access */
 void clock_push_button(int color);
-void clock_unpush_button(int color);
-
-/* getting informations about clock */
-int clock_is_byoyomi(int color);
-int clock_is_time_over(int color);
-double clock_get_timer(int color);
-double clock_get_btimer(int color);
-double clock_get_time_left(int color);
-double clock_get_btime_left(int color, int *stones);
+void update_time_left(int color, int time_left, int stones);
+void clock_print(int color);
+int get_clock_settings(int *t, int *byo_t, int *byo_s);
 
-/* adaptative system */
-void clock_adapt_level(int *p_level, int color);
+void adjust_level_offset(int color);
 
-/* output */
-void clock_print(int color);
-void clock_report_autolevel(FILE *f, int color);
+/* Access to level settings. */
+int get_level(void);
+void set_level(int new_level);
+void set_max_level(int new_max);
+void set_min_level(int new_min);
 
 
 #endif  /* _CLOCK_H_ */
Index: engine/dragon.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v
retrieving revision 1.153
diff -u -p -r1.153 dragon.c
--- engine/dragon.c	8 Oct 2005 08:19:42 -0000	1.153
+++ engine/dragon.c	14 Oct 2005 00:18:32 -0000
@@ -354,7 +354,7 @@ make_dragons(int stop_before_owl)
 	int dcode = DRAGON2(str).owl_defense_code;
 	int defense_point, second_defense_point;
 	
-	if (level >= 8
+	if (get_level() >= 8
 	    && !disable_threat_computation
 	    && (owl_threats 
 		|| thrashing_stone[str])) {
Index: engine/genmove.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/genmove.c,v
retrieving revision 1.107
diff -u -p -r1.107 genmove.c
--- engine/genmove.c	8 Oct 2005 08:07:12 -0000	1.107
+++ engine/genmove.c	14 Oct 2005 00:18:32 -0000
@@ -91,7 +91,7 @@ reset_engine()
   clear_break_in_list();
 
   /* Set up depth values (see comments there for details). */
-  set_depth_values(level, 0);
+  set_depth_values(get_level(), 0);
 }
 
 /*
@@ -318,9 +318,6 @@ do_genmove(int color, float pure_threat_
   move = PASS_MOVE;  
   *value = 0.0; 
   
-  /* experimental level adapter */
-  clock_adapt_level(&level, color);
-
   /* Prepare pattern matcher and reading code. */
   reset_engine();
 
Index: engine/globals.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/globals.c,v
retrieving revision 1.76
diff -u -p -r1.76 globals.c
--- engine/globals.c	13 Oct 2005 16:31:31 -0000	1.76
+++ engine/globals.c	14 Oct 2005 00:18:32 -0000
@@ -92,9 +92,6 @@ int disable_fuseki    = 0;  /* do not ge
 int josekidb          = 1;  /* use joseki database */
 int showtime          = 0;  /* print time to find move */
 int showscore         = 0;  /* print estimated score */
-int level             = DEFAULT_LEVEL; /* strength; up to 10 supported */
-int min_level         = 0;
-int max_level         = gg_max(DEFAULT_LEVEL, 10);
 int debug             = 0;  /* controls debug output */
 int verbose           = 0;  /* trace level */
 char outfilename[128] = ""; /* output file (-o option) */
@@ -102,6 +99,7 @@ int output_flags      = OUTPUT_DEFAULT; 
 int limit_search      = 0;  /* limit search to a portion of the board */
 int metamachine       = 0;  /* use metamachine_genmove */
 int oracle_exists     = 0;  /* oracle is available for consultation   */
+int autolevel_on      = 0;  /* Adjust leven in GMP or ASCII mode. */
 
 int disable_threat_computation = 0;
 int disable_endgame_patterns   = 0;
Index: engine/gnugo.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/gnugo.h,v
retrieving revision 1.124
diff -u -p -r1.124 gnugo.h
--- engine/gnugo.h	13 Oct 2005 16:31:31 -0000	1.124
+++ engine/gnugo.h	14 Oct 2005 00:18:32 -0000
@@ -176,6 +176,7 @@ extern int output_flags;       /* amount
 #define DEBUG_ORACLE_STREAM         0x1000000
 #define DEBUG_LARGE_SCALE           0x1000000
 #define DEBUG_SPLIT_OWL             0x2000000
+#define DEBUG_TIME                  0x4000000
 
 
 #define DEBUG_FLAGS "\
@@ -206,6 +207,7 @@ DEBUG_MISCELLANEOUS         0x800000\n\
 DEBUG_ORACLE_STREAM         0x1000000\n\
 DEBUG_LARGE_SCALE           0x1000000\n\
 DEBUG_SPLIT_OWL             0x2000000\n\
+DEBUG_TIME                  0x4000000\n\
 "
 
 
@@ -242,7 +244,6 @@ extern int hashflags;		/* hash flags */
 extern int fusekidb;            /* use fuseki database */
 extern int disable_fuseki;      /* do not generate fuseki moves */
 extern int josekidb;            /* use joseki database */
-extern int level;		/* controls depth of reading */
 extern int semeai_variations;   /* max variations considered reading semeai */
 extern int showtime;		/* print genmove time */
 extern int showscore;		/* print score */
@@ -274,6 +275,8 @@ extern int mandated_owl_branch_depth;
 extern int mandated_owl_reading_depth;
 extern int mandated_owl_node_limit; 
 extern int mandated_semeai_node_limit; 
+
+extern int autolevel_on;
 
 extern float potential_moves[BOARDMAX];
 
Index: engine/interface.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/interface.c,v
retrieving revision 1.57
diff -u -p -r1.57 interface.c
--- engine/interface.c	7 Oct 2005 21:36:57 -0000	1.57
+++ engine/interface.c	14 Oct 2005 00:18:33 -0000
@@ -67,6 +67,7 @@ gnugo_clear_board(int boardsize)
 {
   board_size = boardsize;
   clear_board();
+  init_timers();
 #if 0
   if (metamachine && oracle_exists)
     oracle_clear_board(boardsize);
Index: engine/liberty.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
retrieving revision 1.245
diff -u -p -r1.245 liberty.h
--- engine/liberty.h	9 Oct 2005 19:06:13 -0000	1.245
+++ engine/liberty.h	14 Oct 2005 00:18:33 -0000
@@ -731,9 +731,6 @@ extern int connect_depth2;
 extern int connection_node_limit;
 extern int breakin_depth;
 extern int breakin_node_limit;
-extern int level;               /* controls the strength of play */
-extern int min_level;           /* minimum level for adjustment schemes */
-extern int max_level;           /* minimum level for adjustment schemes */
 extern int semeai_variations;   /* max variations considered reading semeai */
 extern float best_move_values[10];
 extern int best_moves[10];
Index: engine/owl.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.237
diff -u -p -r1.237 owl.c
--- engine/owl.c	8 Oct 2005 08:19:42 -0000	1.237
+++ engine/owl.c	14 Oct 2005 00:18:35 -0000
@@ -919,7 +919,7 @@ do_owl_analyze_semeai(int apos, int bpos
       include_semeai_worms_in_eyespace = 0;
     }
 
-    if (level < 8) {
+    if (get_level() < 8) {
       /* If no owl moves were found on two consecutive moves,
        * turn off the owl phase.
        */
@@ -2853,7 +2853,7 @@ owl_estimate_life(struct local_owl_data 
   matches_found = 0;
   memset(found_matches, 0, sizeof(found_matches));
 
-  if (level >= 8) {
+  if (get_level() >= 8) {
     memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache));
     if (!does_attack) {
       clear_owl_move_data(dummy_moves);
@@ -5958,7 +5958,7 @@ owl_substantial(int str)
   /* fill all the liberties */
   for (k = 0; k < liberties; k++) {
     if (trymove(libs[k], owl->color, NULL, 0)) {
-      if (level >= 8)
+      if (get_level() >= 8)
 	increase_depth_values();
       owl->goal[libs[k]] = 1;
     }
@@ -5966,7 +5966,7 @@ owl_substantial(int str)
       /* if we can't fill, try swapping with the next liberty */
       if (k < liberties-1
 	  && trymove(libs[k+1], owl->color, NULL, 0)) {
-	if (level >= 8)
+	if (get_level() >= 8)
 	  increase_depth_values();
 	owl->goal[libs[k+1]] = 1;
 	libs[k+1] = libs[k];
@@ -5974,7 +5974,7 @@ owl_substantial(int str)
       else {
 	/* Can't fill the liberties. Give up! */
 	while (stackp > 0) {
-	  if (level >= 8)
+	  if (get_level() >= 8)
 	    decrease_depth_values();
 	  popgo();
 	}
@@ -5995,7 +5995,7 @@ owl_substantial(int str)
   else
     result = 1;
   while (stackp > 0) {
-    if (level >= 8)
+    if (get_level() >= 8)
       decrease_depth_values();
     popgo();
   }
Index: engine/reading.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/reading.c,v
retrieving revision 1.162
diff -u -p -r1.162 reading.c
--- engine/reading.c	8 Oct 2005 08:31:27 -0000	1.162
+++ engine/reading.c	14 Oct 2005 00:18:37 -0000
@@ -1757,7 +1757,7 @@ defend3(int str, int *move)
     bamboo_rescue_moves(str, liberties, libs, &moves);
   }
 
-  if (level >= 8 && stackp <= backfill2_depth)
+  if (get_level() >= 8 && stackp <= backfill2_depth)
     superstring_break_chain_moves(str, 4, &moves);
 
   if (stackp <= break_chain_depth)
@@ -1775,7 +1775,7 @@ defend3(int str, int *move)
   /* If nothing else works, we try playing a liberty of the
    * super_string.
    */
-  if (level >= 8 && stackp <= backfill2_depth) {
+  if (get_level() >= 8 && stackp <= backfill2_depth) {
     superstring_moves(str, &moves, 3, 0);
     squeeze_moves(str, &moves);
   }
@@ -3217,7 +3217,7 @@ attack2(int str, int *move)
       /* If it is not possible to make a direct atari, we try filling
        * a liberty of the superstring.
        */
-      if (level >= 8
+      if (get_level() >= 8
           && stackp <= backfill_depth
           && (stackp <= superstring_depth || !atari_possible)) {
 	int liberty_cap = 2;
@@ -3365,7 +3365,7 @@ attack3(int str, int *move)
       /* If nothing else works, we try filling a liberty of the
        * super_string.
        */
-      if (level >= 8 && stackp <= backfill2_depth) {
+      if (get_level() >= 8 && stackp <= backfill2_depth) {
 	superstring_moves(str, &moves, 3, 1);
 	squeeze_moves(str, &moves);
       }
Index: engine/sgffile.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/sgffile.c,v
retrieving revision 1.35
diff -u -p -r1.35 sgffile.c
--- engine/sgffile.c	12 Jun 2005 09:34:14 -0000	1.35
+++ engine/sgffile.c	14 Oct 2005 00:18:37 -0000
@@ -165,7 +165,7 @@ sgffile_printsgf(int color_to_play, cons
   sgftree_clear(&sgftree);
   sgftreeCreateHeaderNode(&sgftree, board_size, relative_komi);
   sgf_write_header(sgftree.root, 1, get_random_seed(), relative_komi,
-		   level, chinese_rules);
+		   get_level(), chinese_rules);
   gg_snprintf(str, 128, "GNU Go %s load and print", gg_version());
   sgfOverwriteProperty(sgftree.root, "GN", str);
   
Index: engine/value_moves.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v
retrieving revision 1.156
diff -u -p -r1.156 value_moves.c
--- engine/value_moves.c	8 Oct 2005 08:38:39 -0000	1.156
+++ engine/value_moves.c	14 Oct 2005 00:18:38 -0000
@@ -3757,12 +3757,12 @@ review_move_reasons(int *the_move, float
   find_more_attack_and_defense_moves(color);
   time_report(2, "  find_more_attack_and_defense_moves", NO_MOVE, 1.0);
 
-  if (level >= 6) {
+  if (get_level() >= 6) {
     find_more_owl_attack_and_defense_moves(color);
     time_report(2, "  find_more_owl_attack_and_defense_moves", NO_MOVE, 1.0);
   }
 
-  if (large_scale && level >= 6) {
+  if (large_scale && get_level() >= 6) {
     find_large_scale_owl_attack_moves(color);
     time_report(2, "  find_large_scale_owl_attack_moves", NO_MOVE, 1.0);
   }
Index: interface/main.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/main.c,v
retrieving revision 1.121
diff -u -p -r1.121 main.c
--- interface/main.c	13 Oct 2005 16:31:31 -0000	1.121
+++ interface/main.c	14 Oct 2005 00:18:41 -0000
@@ -337,9 +337,6 @@ main(int argc, char *argv[])
   int seed = 0;
   int seed_specified = 0;
 
-  /* Default parameters for clock and auto level systems. */
-  clock_init(3600, 0, 0);      /* One hour sudden death. */
-
   sgftree_clear(&sgftree);
   gameinfo_clear(&gameinfo, board_size, komi);
   
@@ -780,19 +777,15 @@ main(int argc, char *argv[])
 	break;
 	
       case OPT_LEVEL:
-	level = atoi(gg_optarg);
-	if (level > max_level)
-	  max_level = level;
-	if (level < min_level)
-	  min_level = level;
+	set_level(atoi(gg_optarg));
 	break;
 
       case OPT_MIN_LEVEL:
-	min_level = atoi(gg_optarg);
+	set_min_level(atoi(gg_optarg));
 	break;
 
       case OPT_MAX_LEVEL:
-	max_level = atoi(gg_optarg);
+	set_max_level(atoi(gg_optarg));
 	break;
 
       case OPT_LIMIT_SEARCH:
@@ -807,25 +800,19 @@ main(int argc, char *argv[])
 	break;
 
       case OPT_CLOCK_TIME:
-
-	clock_init(atoi(gg_optarg), -1, -1);
-	clock_enable();
+	clock_settings(atoi(gg_optarg), -1, -1);
 	break;
 
       case OPT_CLOCK_BYO_TIME: 
-	clock_init(-1, atoi(gg_optarg), -1);
-	clock_enable();
+	clock_settings(-1, atoi(gg_optarg), -1);
 	break;
 
       case OPT_CLOCK_BYO_PERIOD:
-	clock_init(-1, -1, atoi(gg_optarg));
-	clock_enable();
+	clock_settings(-1, -1, atoi(gg_optarg));
 	break;
 
       case OPT_AUTOLEVEL:
-	clock_init(-1, -1, -1);
-	clock_enable();
-	clock_enable_autolevel();
+	autolevel_on = 1;
 	break;
 	
       case OPT_DEBUG_INFLUENCE:
@@ -1372,7 +1359,6 @@ main(int argc, char *argv[])
   if (profile_patterns)
     report_pattern_profiling();
 
-  clock_report_autolevel(NULL, gameinfo.computer_player);
   sgfFreeNode(sgftree.root); 
 
   return 0;
@@ -1556,8 +1542,7 @@ Options providing detailed reading resul
 static void
 show_help(void)
 {
-  set_depth_values(DEFAULT_LEVEL, 0);
-  printf(USAGE, level);
+  printf(USAGE, DEFAULT_LEVEL);
   printf(USAGE1, (float) DEFAULT_MEMORY);
   printf(USAGE2, MIN_BOARD, MAX_BOARD, MAX_HANDICAP);
 }
Index: interface/play_ascii.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/play_ascii.c,v
retrieving revision 1.61
diff -u -p -r1.61 play_ascii.c
--- interface/play_ascii.c	7 Oct 2005 23:22:31 -0000	1.61
+++ interface/play_ascii.c	14 Oct 2005 00:18:41 -0000
@@ -54,6 +54,8 @@ static int showdead = 0;
 static SGFTree sgftree;
 static int resignation_allowed;
 
+static int clock_on = 0;
+
 /* Unreasonable score used to detect missing information. */
 #define NO_SCORE 4711
 /* Keep track of the score estimated before the last computer move. */
@@ -296,6 +298,11 @@ ascii_showboard(void)
   fflush(stdout);
   printf("%s\n\n", letterbar);
   fflush(stdout);
+
+  if (clock_on) {
+    clock_print(WHITE);
+    clock_print(BLACK);
+  }
   
 }  /* end ascii_showboard */
 
@@ -440,7 +447,7 @@ init_sgf(Gameinfo *ginfo)
   sgf_initialized = 1;
 
   sgf_write_header(sgftree.root, 1, get_random_seed(), komi,
-      		   level, chinese_rules);
+      		   get_level(), chinese_rules);
   sgfOverwritePropertyInt(sgftree.root, "HA", ginfo->handicap);
   if (ginfo->handicap > 0)
     sgffile_recordboard(sgftree.root);
@@ -463,6 +470,8 @@ computer_move(Gameinfo *gameinfo, int *p
   init_sgf(gameinfo);
 
   /* Generate computer move. */
+  if (autolevel_on)
+    adjust_level_offset(gameinfo->to_move);
   move_value = gnugo_genmove(&i, &j, gameinfo->to_move, &resign);
   if (resignation_allowed && resign) {
     int state = ascii_endgame(gameinfo, 2);
@@ -618,6 +627,9 @@ do_play_ascii(Gameinfo *gameinfo)
   char *tmpstring;
   int state = 1;
 
+  if (get_clock_settings(NULL, NULL, NULL))
+    clock_on = 1;
+
   while (state == 1) {
     state = 0;
 
@@ -775,8 +787,8 @@ do_play_ascii(Gameinfo *gameinfo)
 	    printf("\nInvalid command syntax!\n");
 	    break;
 	  }
-	  level = num;
-	  printf("\nSet level to %d\n", level);
+	  set_level(num);
+	  printf("\nSet level to %d\n", num);
 	  break;
 
 	case DISPLAY:
Index: interface/play_gmp.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/play_gmp.c,v
retrieving revision 1.32
diff -u -p -r1.32 play_gmp.c
--- interface/play_gmp.c	5 Oct 2005 16:32:12 -0000	1.32
+++ interface/play_gmp.c	14 Oct 2005 00:18:41 -0000
@@ -133,7 +133,7 @@ play_gmp(Gameinfo *gameinfo, int simplif
 
   gameinfo->computer_player = mycolor;
   sgf_write_header(sgftree.root, 1, get_random_seed(), komi,
-		   level, chinese_rules);
+		   get_level(), chinese_rules);
   gameinfo->handicap = gnugo_sethand(gameinfo->handicap, sgftree.root);
   sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
 
@@ -186,7 +186,10 @@ play_gmp(Gameinfo *gameinfo, int simplif
     }
     else {
       /* Generate my next move. */
-      float move_value = gnugo_genmove(&i, &j, mycolor, NULL);
+      float move_value;
+      if (autolevel_on)
+	adjust_level_offset(mycolor);
+      move_value = gnugo_genmove(&i, &j, mycolor, NULL);
       gnugo_play_move(i, j, mycolor);
       sgffile_add_debuginfo(sgftree.lastnode, move_value);
       
Index: interface/play_gtp.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/play_gtp.c,v
retrieving revision 1.172
diff -u -p -r1.172 play_gtp.c
--- interface/play_gtp.c	8 Oct 2005 08:10:26 -0000	1.172
+++ interface/play_gtp.c	14 Oct 2005 00:18:41 -0000
@@ -35,28 +35,10 @@
 
 /* Internal state that's not part of the engine. */
 static int handicap = 0;
-static int main_time = 0;
-static int byo_yomi_time = 1;
-static int byo_yomi_stones = 0;
 
 static int report_uncertainty = 0;
 static int gtp_orientation = 0;
 
-/* Time handling. Index 0 is the most recent report, index 1 the
- * second most recent report.
- */
-static int black_time_left[2];
-static int black_stones_left[2];
-static int white_time_left[2];
-static int white_stones_left[2];
-static int level_offset;
-
-
-static void gtp_init_time_handling(void);
-static void analyze_time_data(int time_left_data[2], int stones_left_data[2],
-			      int *time_for_last_move,
-			      int *time_left, int *stones_left);
-static void adjust_level_offset(int color);
 static void gtp_print_code(int c);
 static void gtp_print_vertices2(int n, int *moves);
 static void rotate_on_input(int ai, int aj, int *bi, int *bj);
@@ -359,7 +341,7 @@ play_gtp(FILE *gtp_input, FILE *gtp_outp
   gtp_set_vertex_transform_hooks(rotate_on_input, rotate_on_output);
 
   /* Initialize time handling. */
-  gtp_init_time_handling();
+  init_timers();
   
   /* Prepare pattern matcher and reading code. */
   reset_engine();
@@ -516,7 +498,7 @@ gtp_clear_board(char *s)
     update_random_seed();
 
   clear_board();
-  gtp_init_time_handling();
+  init_timers();
   
   return gtp_success("");
 }
@@ -627,7 +609,7 @@ gtp_playblack(char *s)
   if (!is_legal(POS(i, j), BLACK))
     return gtp_failure("illegal move");
 
-  play_move(POS(i, j), BLACK);
+  gnugo_play_move(i, j, BLACK);
   return gtp_success("");
 }
 
@@ -658,7 +640,7 @@ gtp_playwhite(char *s)
   if (!is_legal(POS(i, j), WHITE))
     return gtp_failure("illegal move");
 
-  play_move(POS(i, j), WHITE);
+  gnugo_play_move(i, j, WHITE);
   return gtp_success("");
 }
 
@@ -682,7 +664,7 @@ gtp_play(char *s)
   if (!is_legal(POS(i, j), color))
     return gtp_failure("illegal move");
 
-  play_move(POS(i, j), color);
+  gnugo_play_move(i, j, color);
   return gtp_success("");
 }
 
@@ -871,7 +853,7 @@ gtp_loadsgf(char *s)
   handicap = gameinfo.handicap;
   gtp_internal_set_boardsize(board_size);
   reset_engine();
-  gtp_init_time_handling();
+  init_timers();
 
   sgfFreeNode(sgftree.root);
 
@@ -2471,7 +2453,7 @@ gtp_genmove_black(char *s)
 
   move = genmove(BLACK, NULL, NULL);
 
-  play_move(move, BLACK);
+  gnugo_play_move(I(move), J(move), BLACK);
 
   gtp_start_response(GTP_SUCCESS);
   gtp_print_vertex(I(move), J(move));
@@ -2496,7 +2478,7 @@ gtp_genmove_white(char *s)
 
   move = genmove(WHITE, NULL, NULL);
 
-  play_move(move, WHITE);
+  gnugo_play_move(I(move), J(move), WHITE);
 
   gtp_start_response(GTP_SUCCESS);
   gtp_print_vertex(I(move), J(move));
@@ -2526,14 +2508,12 @@ gtp_genmove(char *s)
     return gtp_failure("genmove cannot be called when stackp > 0");
 
   adjust_level_offset(color);
-  level += level_offset;
   move = genmove(color, NULL, &resign);
-  level -= level_offset;
 
   if (resign)
     return gtp_success("resign");
 
-  play_move(move, color);
+  gnugo_play_move(I(move), J(move), color);
 
   gtp_start_response(GTP_SUCCESS);
   gtp_print_vertex(I(move), J(move));
@@ -2708,13 +2688,11 @@ gtp_kgs_genmove_cleanup(char *s)
   capture_all_dead = 1;
   
   adjust_level_offset(color);
-  level += level_offset;
   move = genmove(color, NULL, NULL);
-  level -= level_offset;
 
   capture_all_dead = save_capture_all_dead;
   
-  play_move(move, color);
+  gnugo_play_move(I(move), J(move), color);
 
   gtp_start_response(GTP_SUCCESS);
   gtp_print_vertex(I(move), J(move));
@@ -2845,8 +2823,7 @@ gtp_set_level(char *s)
   if (sscanf(s, "%d", &new_level) < 1)
     return gtp_failure("level not an integer");
   
-  level = new_level;
-  level_offset = 0;
+  set_level(new_level);
   return gtp_success("");
 }
 
@@ -2901,131 +2878,6 @@ gtp_gg_undo(char *s)
  * time handling *
  *****************/
 
-/* Initialize time data variables and set the level offset to 0. */
-static void
-gtp_init_time_handling(void)
-{
-  int k;
-  for (k = 0; k < 1; k++) {
-    black_time_left[k] = -1;
-    black_stones_left[k] = -1;
-    white_time_left[k] = -1;
-    white_stones_left[k] = -1;
-  }
-  level_offset = 0;
-}
-
-/* Analyze the two most recent time reports and determine the time
- * spent on the last moves, the (effective) number of stones left and
- * the (effective) remaining time.
- */
-static void
-analyze_time_data(int time_left_data[2], int stones_left_data[2],
-		  int *time_for_last_move, int *time_left, int *stones_left)
-{
-  *time_for_last_move = -1;
-  *time_left = -1;
-  *stones_left = -1;
-
-  /* Do we have any time limits. */
-  if (byo_yomi_stones == 0 && byo_yomi_time > 0)
-    return;
-  
-  /* If we don't have time information for the two last moves, just return. */
-  if (time_left_data[1] < 0)
-    return;
-
-  if (stones_left_data[0] == 0) {
-    /* Main time running. */
-    *time_for_last_move = time_left_data[1] - time_left_data[0];
-    *time_left = time_left_data[0] + byo_yomi_time;
-    if (byo_yomi_time > 0)
-      *stones_left = byo_yomi_stones;
-    else {
-      /* Absolute time. Here we aim to be able to play at least X more
-       * moves or a total of Y moves. We choose Y as a third of the
-       * number of vertices and X as 40% of Y. For 19x19 this means
-       * that we aim to play at least a total of 120 moves
-       * (corresponding to a 240 move game) or another 24 moves.
-       */
-      int nominal_moves = board_size * board_size / 3;
-      *stones_left = gg_max(nominal_moves - movenum / 2,
-			    2 * nominal_moves / 5);
-    }
-  }
-  else {
-    if (stones_left_data[1] == 0)
-      *time_for_last_move = time_left_data[1] + (byo_yomi_time
-						 - time_left_data[0]);
-    else if (stones_left_data[1] == stones_left_data[0] + 1)
-      *time_for_last_move = time_left_data[1] - time_left_data[0];
-    else
-      return;
-
-    *time_left = time_left_data[0];
-    *stones_left = stones_left_data[0];
-  }
-}
-
-/* Adjust the level offset given information of current playing speed
- * and remaining time and stones.
- *
- * FIXME: Integrate this code with the one in clock.c. Or maybe rather
- *        replace them both with something better.
- */
-static void
-adjust_level_offset(int color)
-{
-  int time_for_last_move;
-  int time_left;
-  int stones_left;
-
-  if (color == BLACK)
-    analyze_time_data(black_time_left, black_stones_left, &time_for_last_move,
-		      &time_left, &stones_left);
-  else
-    analyze_time_data(white_time_left, white_stones_left, &time_for_last_move,
-		      &time_left, &stones_left);
-
-  if (time_for_last_move < 0)
-    return;
-
-  /* These rules are both crude and ad hoc.
-   *
-   * FIXME: Use rules with at least some theoretical basis.
-   */
-  if (time_left < time_for_last_move * (stones_left + 3))
-    level_offset--;
-  if (time_left < time_for_last_move * stones_left)
-    level_offset--;
-  if (3 * time_left < 2 * time_for_last_move * stones_left)
-    level_offset--;
-  if (2 * time_left < time_for_last_move * stones_left)
-    level_offset--;
-  if (3 * time_left < time_for_last_move * stones_left)
-    level_offset--;
-
-  if (time_for_last_move == 0)
-    time_for_last_move = 1;
-  if (time_left > time_for_last_move * (stones_left + 6))
-    level_offset++;
-  if (time_left > 2 * time_for_last_move * (stones_left + 6))
-    level_offset++;
-
-  if (level + level_offset < min_level)
-    level_offset = min_level - level;
-
-  if (level + level_offset > max_level)
-    level_offset = max_level - level;
-
-  if (1) {
-    if (level_offset != 0) {
-      gprintf("New level %d (%d %C %d %d %d)\n", level + level_offset,
-	      movenum / 2, color, time_for_last_move, time_left, stones_left);
-    }
-  }
-}
-
 /* Function:  Set time allowance
  * Arguments: int main_time, int byo_yomi_time, int byo_yomi_stones
  * Fails:     syntax error
@@ -3037,15 +2889,12 @@ adjust_level_offset(int color)
 static int
 gtp_time_settings(char *s)
 {
-  int a, b, c;
+  int main_time, byoyomi_time, byoyomi_stones;
   
-  if (sscanf(s, "%d %d %d", &a, &b, &c) < 3)
+  if (sscanf(s, "%d %d %d", &main_time, &byoyomi_time, &byoyomi_stones) < 3)
     return gtp_failure("not three integers");
 
-  main_time = a;
-  byo_yomi_time = b;
-  byo_yomi_stones = c;
-
+  clock_settings(main_time, byoyomi_time, byoyomi_stones);
   return gtp_success("");
 }
 
@@ -3073,18 +2922,7 @@ gtp_time_left(char *s)
   if (sscanf(s+n, "%d %d", &time, &stones) < 2)
     return gtp_failure("time and stones not two integers");
 
-  if (color == BLACK) {
-    black_time_left[1] = black_time_left[0];
-    black_stones_left[1] = black_stones_left[0];
-    black_time_left[0] = time;
-    black_stones_left[0] = stones;
-  }
-  else {
-    white_time_left[1] = white_time_left[0];
-    white_stones_left[1] = white_stones_left[0];
-    white_time_left[0] = time;
-    white_stones_left[0] = stones;
-  }
+  update_time_left(color, time, stones);
   
   return gtp_success("");
 }
@@ -3149,7 +2987,7 @@ finish_and_score_game(int seed)
 
   do {
     move = genmove_conservative(next, NULL);
-    play_move(move, next);
+    gnugo_play_move(I(move), J(move), next);
     if (move != PASS_MOVE) {
       pass = 0;
       moves++;
Index: interface/play_solo.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/play_solo.c,v
retrieving revision 1.38
diff -u -p -r1.38 play_solo.c
--- interface/play_solo.c	5 Oct 2005 16:32:12 -0000	1.38
+++ interface/play_solo.c	14 Oct 2005 00:18:41 -0000
@@ -61,7 +61,7 @@ play_solo(Gameinfo *gameinfo, int moves)
   sgftree_clear(&sgftree);
   sgftreeCreateHeaderNode(&sgftree, board_size, komi);
   sgf_write_header(sgftree.root, 1, get_random_seed(), 5.5,
-                   level, chinese_rules);
+                   get_level(), chinese_rules);
  
   /* Generate some random moves. */
   if (board_size > 6) {

