Ticket #33: arend_7_8.1b-clock.diff

File arend_7_8.1b-clock.diff, 50.5 KB (added by arend, 6 years ago)

revised patch

  • engine/breakin.c

    RCS file: /cvsroot/gnugo/gnugo/engine/breakin.c,v
    retrieving revision 1.21
    diff -u -p -r1.21 breakin.c
    break_territories(int color_to_move, str 
    411411  struct moyo_data territories; 
    412412  int k; 
    413413 
    414   if (!experimental_break_in || level < 10) 
     414  if (!experimental_break_in || get_level() < 10) 
    415415    return; 
    416416 
    417417  influence_get_territory_segmentation(q, &territories); 
  • engine/clock.c

    RCS file: /cvsroot/gnugo/gnugo/engine/clock.c,v
    retrieving revision 1.23
    diff -u -p -r1.23 clock.c
     
    3535 *                                                               * 
    3636\* ============================================================= */ 
    3737 
    38 #include "gnugo.h" 
    39  
    40 #include "liberty.h" 
    41 #include "gg_utils.h" 
    4238#include "clock.h" 
     39#include "gg_utils.h" 
     40#include "board.h" 
    4341 
    44 /* parameters */ 
    45 #define CLOCK_MAX_MOVES           500   /* max number of moves for a game */ 
    46 #define CLOCK_STEP                0.4   /* modification step for level */ 
    47 #define CLOCK_HURRY               10    /* Last chance limit: */ 
    48 #define CLOCK_HURRYR              0.02  /* (10 sec or or 2% of main_time) */ 
    49 #define CLOCK_HURRY_LEVEL         1     /* Last chance level: */ 
    50 #define CLOCK_SAFE                300   /* Keep Ahead limit: */ 
    51 #define CLOCK_SAFER               0.20  /* (5min or 20% of time) */ 
    52 #define CLOCK_DELTA               10    /* Maximal time difference: */ 
    53 #define CLOCK_DELTAR              0.10  /* 10sec or 10% of left time */ 
    54 #define CLOCK_TIME_CONTRACT       0.75  /* 75% of time to play */ 
    55 #define CLOCK_MOVE_CONTRACT(b)    (((b)*(b))/2) 
    56 #define CLOCK_CONTRACT_MIN_LEVEL  5 
     42/* Level data */ 
     43static int level             = DEFAULT_LEVEL; /* current level */ 
     44static int level_offset      = 0; 
     45static int min_level         = 0; 
     46static int max_level         = gg_max(DEFAULT_LEVEL, 10); 
    5747 
    5848 
    5949/*************************/ 
    6050/* Datas and other stuff */ 
    6151/*************************/ 
    6252 
    63 typedef struct { 
    64  
    65   /* clock parameters */ 
    66   int    clock_on; 
    67   int    ready; 
    68   double main_time; 
    69   double byoyomi_time; /* zero if no byo-yomi */ 
    70   int    byoyomi_stones; 
    71  
    72   /* clock status */ 
    73   double timer[3]; 
    74   double btimer[3]; 
    75   int    byoyomi[3]; 
    76   int    dead[3]; 
    77  
    78   /* dates of each move */ 
    79   int    moveno; /* invariant: COLOR(clk.moveno) = color of last move */ 
    80   double date[CLOCK_MAX_MOVES]; 
    81  
    82   /* adapative system parameters */ 
    83   int    autolevel_on; 
    84   double level;  /* FIXME: Why is this a double and not an int? */ 
    85   double levels[CLOCK_MAX_MOVES]; 
    86   double expected[CLOCK_MAX_MOVES]; 
    87   double error; /* time/move estimation error */ 
    88 } gnugo_clock; 
    89  
    90 static gnugo_clock clk; 
    91  
    92 /* Color macro: 
    93  *   WHITE : odd moves 
    94  *   BLACK : even moves.  
    95  */ 
    96 #define COLOR(m)  ((m) % 2 ? WHITE : BLACK) 
    97  
    98  
    99 static const char *pname[3] = {"     ", "White", "Black"}; 
    100  
    101  
    102 /* forward declarations */ 
    103  
    104 static double estimate_time_by_move(int color, int move); 
     53/* clock parameters */ 
     54static int main_time = -1; 
     55static int byoyomi_time = -1; 
     56static int byoyomi_stones = -1; /* <= 0 if no byo-yomi */ 
     57 
     58/* Keep track of the remaining time left. 
     59 * If stones_left is zero, .._time_left is the remaining main time. 
     60 * Otherwise, the remaining time for this byoyomi period. 
     61 */ 
     62struct remaining_time_data { 
     63  double time_left; 
     64  double time_for_last_move; 
     65  int stones; 
     66  int movenum; 
     67  int in_byoyomi; 
     68}; 
    10569 
     70struct timer_data { 
     71  struct remaining_time_data official; 
     72  struct remaining_time_data estimated; 
     73  int time_out; 
     74}; 
    10675 
     76static struct timer_data black_time_data; 
     77static struct timer_data white_time_data; 
    10778 
    10879 
    10980/* Echo a time value in STANDARD format */ 
    110  
    11181static void 
    11282timeval_print(FILE *outfile, double tv) 
    11383{ 
    timeval_print(FILE *outfile, double tv) 
    12090  fprintf(outfile, "%3dmin %.2fsec ", min, sec); 
    12191} 
    12292 
    123 /******************************/ 
    124 /*  Initialization functions  */ 
    125 /******************************/ 
    126  
    12793 
    128 /* 
    129  * Initialize the structure. 
    130  * -1 means "do not modify this value". 
    131  * clock_init(-1, -1, -1) only resets the clock. 
    132  */ 
     94/* Print the clock status for one side. */ 
    13395void 
    134 clock_init(int time, int byo_time, int byo_stones) 
     96clock_print(int color) 
    13597{ 
    136   int color; 
     98  struct timer_data* const td 
     99    = (color == BLACK) ? &black_time_data : &white_time_data; 
    137100 
    138   if (time > 0) { 
    139     clk.main_time = time; 
    140     clk.ready = 1; 
    141   } 
    142  
    143   if (byo_time >= 0) 
    144     clk.byoyomi_time = byo_time; 
     101  fprintf(stderr, "clock: ");  
     102  fprintf(stderr, "%s ", color_to_string(color)); 
    145103 
    146   if (byo_stones >= 0) 
    147     clk.byoyomi_stones = byo_stones; 
     104  if (td->time_out) 
     105    fprintf(stderr, "TIME OUT! "); 
     106  else { 
     107    if (td->estimated.in_byoyomi) { 
     108      fprintf(stderr, "byoyomi"); 
     109      timeval_print(stderr, td->estimated.time_left); 
     110      fprintf(stderr, "for %d stones.", td->estimated.stones); 
     111    } 
     112    else 
     113      timeval_print(stderr, td->estimated.time_left); 
    148114 
    149   clk.moveno = -1; 
    150   for (color = WHITE; color <= BLACK; color++) { 
    151     clk.timer[color] = 0; 
    152     clk.btimer[color] = 0; 
    153     clk.byoyomi[color] = 0; 
    154     clk.dead[color] = 0; 
    155115  } 
     116  fprintf(stderr, "\n"); 
    156117} 
    157118 
    158119 
    159 /* 
    160  * Activate the clock. 
    161  */ 
    162 void  
    163 clock_enable(void) 
    164 { 
    165   gg_assert(clk.ready); 
    166   clk.clock_on = 1; 
    167 } 
    168  
    169 /* 
    170  * Activate Autolevel. 
    171  */ 
    172 void  
    173 clock_enable_autolevel(void) 
    174 { 
    175   gg_assert(clk.clock_on); 
    176   clk.autolevel_on = 1; 
    177 } 
    178  
    179  
    180 /***********************/ 
    181 /*  Access functions.  */ 
    182 /***********************/ 
    183  
    184  
    185 /*  
    186  * Maintain timers and all stuff up to date 
    187  * (used by push_button). 
    188  */ 
    189 static void 
    190 clock_byoyomi_update(int color, double dt) 
    191 { 
    192   gg_assert(clk.moveno > 0); 
    193  
    194   /* update byoyomi timer */ 
    195   if (clk.byoyomi[color]) 
    196     clk.btimer[color] = clk.btimer[color] + dt; 
    197   
    198   /* Check if player is just begining byoyomi. */ 
    199   if (clk.timer[color] < clk.main_time && !clk.byoyomi[color]) { 
    200     clk.byoyomi[color] = clk.moveno; 
    201     clk.btimer[color] = dt; 
    202   } 
    203    
    204   /* Check if player is time-out. */ 
    205   clk.dead[color] |= (clock_is_byoyomi(color) 
    206                       && clk.byoyomi_time < clk.btimer[color]); 
    207  
    208   /* Check byoyomi period reset. */ 
    209   if (clk.byoyomi[color] 
    210       && clk.moveno - clk.byoyomi[color] == 2 * clk.byoyomi_stones - 1) { 
    211     clk.byoyomi[color] = clk.moveno; 
    212     clk.btimer[color] = 0; 
    213   } 
    214 } 
    215  
     120/******************************/ 
     121/*  Initialization functions  */ 
     122/******************************/ 
    216123 
    217124/* 
    218  * Update the clock. 
     125 * Initialize the time settings for this game. 
     126 * -1 means "do not modify this value". 
    219127 */ 
    220128void 
    221 clock_push_button(int color) 
    222 { 
    223   double now, dt, tme; 
    224  
    225   if (!clk.clock_on) 
    226     return; 
    227  
    228   now = gg_gettimeofday(); 
    229   gg_assert(clk.ready); 
    230  
    231   /* time/move estimation */ 
    232   tme = estimate_time_by_move(color, clk.moveno); 
    233  
    234   /* first move */ 
    235   if (clk.moveno == -1) { 
    236     /* fprintf(stderr, "clock: first move by %s.\n", pname[color]); */ 
    237     clk.moveno++; 
    238     clk.date[0] = now; 
    239  
    240     if (color != BLACK) { /* do an empty move for BLACK */ 
    241       clk.date[1] = now; 
    242       clk.moveno++; 
    243     } 
    244     return; 
    245   } 
    246  
    247   /* fprintf(stderr, "clock: %s push the button.\n", pname[color]);*/ 
    248   /* fprintf(stderr, "clock: %s's turn.\n", pname[COLOR(clk.moveno+1)]);*/ 
    249  
    250   /* Pushing twice on the button does nothing. */ 
    251   if (color != COLOR(clk.moveno+1)) { 
    252     fprintf(stderr, "clock: double push.\n"); 
    253     return; 
    254   } 
    255  
    256   /* Other moves (clk. moveno > -1) */ 
    257   clk.moveno++; 
    258   gg_assert(clk.moveno < CLOCK_MAX_MOVES); 
    259   clk.date[clk.moveno] = now; 
    260  
    261   /* Update main timer. */ 
    262   dt = clk.date[clk.moveno] - clk.date[clk.moveno - 1]; 
    263   clk.timer[color] += dt; 
    264  
    265   /* Estimate prediction error for next move. */ 
    266   if (clk.moveno > 11) 
    267     clk.error = (clk.error + 2 * gg_abs(dt-tme))/3; 
    268   else 
    269     clk.error = 3.0; 
    270  
    271   clock_byoyomi_update(color, dt); 
    272   clock_print(color); 
    273 } 
    274  
    275  
    276 /* 
    277  * Unplay a move. 
    278  */ 
    279 void  
    280 clock_unpush_button(int color) 
     129clock_settings(int time, int byo_time, int byo_stones) 
    281130{ 
    282   double dt; 
    283  
    284   if (!clk.clock_on) 
    285     return; 
    286       
    287   gg_assert(clk.ready); 
    288   gg_assert(color == COLOR(clk.moveno)); 
    289  
    290   if (clk.moveno < 1) { 
    291     clock_init(-1, -1, -1); 
    292     return; 
    293   } 
    294  
    295   /* Update main timer. */ 
    296   dt = clk.date[clk.moveno] - clk.date[clk.moveno - 1]; 
    297   clk.timer[color] -= dt; 
    298   clk.moveno--; 
    299  
    300   /* Check if back from byoyomi. */ 
    301   if (clk.timer[color] < clk.main_time) { 
    302     clk.byoyomi[color] = 0; 
    303     clk.btimer[color] = 0; 
    304   } 
    305       
    306   /* Update byoyomi timer. */ 
    307   if (clk.byoyomi[color]) 
    308     clk.btimer[color] -= dt; 
    309  
    310   clock_print(color); 
     131  if (time >= 0) 
     132    main_time = time; 
     133  if (byo_time >= 0) 
     134    byoyomi_time = byo_time; 
     135  if (byo_stones >= 0) 
     136    byoyomi_stones = byo_stones; 
     137  init_timers(); 
    311138} 
    312139 
    313  
    314 /* 
    315  * return the (exact) main timer value. 
     140/* Get time settings. Returns 1 if any time settings have been made, 
     141 * 0 otherwise. 
    316142 */ 
    317 double 
    318 clock_get_timer(int color) 
     143int 
     144get_clock_settings(int *t, int *byo_t, int *byo_s) 
    319145{ 
    320   double dt; 
    321  
    322   gg_assert(clk.clock_on && clk.ready); 
    323  
    324   dt = gg_gettimeofday() - clk.date[clk.moveno]; 
    325  
    326   if (COLOR(clk.moveno) != color) 
    327     return clk.timer[color] + dt; 
    328   else  
    329     return clk.timer[color]; 
     146  if (t) 
     147    *t = main_time; 
     148  if (byo_t) 
     149    *byo_t = byoyomi_time; 
     150  if (byo_s) 
     151    *byo_s = byoyomi_stones; 
     152  return (main_time >= 0 || byoyomi_time >= 0); 
    330153} 
    331154 
    332155 
    333 /* 
    334  * Give the time left or negative if in byoyomi. 
    335  */ 
    336 double   
    337 clock_get_time_left(int color) 
     156/* Initialize all timers. */ 
     157void 
     158init_timers() 
    338159{ 
    339   return clk.main_time - clock_get_timer(color); 
    340 } 
    341  
     160  white_time_data.official.time_left = main_time; 
     161  white_time_data.official.time_for_last_move = -1.0; 
     162  white_time_data.official.stones = 0; 
     163  white_time_data.official.movenum = 0; 
     164  white_time_data.official.in_byoyomi = 0; 
     165  white_time_data.estimated = white_time_data.official; 
     166  white_time_data.time_out = 0; 
     167  black_time_data = white_time_data; 
    342168 
    343 /* 
    344  * Check if color is (officially) in byoyomi. 
    345  */ 
    346 int 
    347 clock_is_byoyomi(int color) 
    348 { 
    349   return clock_get_time_left(color) < 0; 
     169  level_offset = 0; 
    350170} 
    351171 
    352172 
    353 /* 
    354  * Return the (exact) main timer value. 
    355  */ 
    356 double 
    357 clock_get_btimer(int color) 
    358 { 
    359   double dt; 
    360    
    361   /* sanity check */ 
    362   gg_assert(clk.clock_on && clk.ready); 
    363   dt = gg_gettimeofday() - clk.date[clk.moveno]; 
    364  
    365   if (COLOR(clk.moveno) != color) 
    366     return clk.btimer[color] + dt; 
    367   else  
    368     return clk.btimer[color]; 
    369 } 
     173/*****************************/ 
     174/*  Clock access functions.  */ 
     175/*****************************/ 
    370176 
    371177 
    372 /* 
    373  * Get The Byoyomi time left and the number of stones to play. 
    374  */ 
    375 double 
    376 clock_get_btime_left(int color, int *stones) 
     178void 
     179update_time_left(int color, int time_left, int stones) 
    377180{ 
    378   if (stones != NULL) 
    379     *stones = clk.byoyomi_stones - (clk.moveno - clk.byoyomi[color]) / 2; 
    380  
    381   return clk.byoyomi_time - clock_get_btimer(color); 
     181  struct timer_data* const td 
     182    = ((color == BLACK) ? &black_time_data : &white_time_data); 
     183  int time_used = td->official.time_left - time_left; 
     184 
     185  /* Did our estimate for time usage go wrong? */ 
     186  if (time_used > 0 
     187      && gg_abs(time_used - td->estimated.time_for_last_move) >= 1.0) 
     188    td->estimated.time_for_last_move = time_used; 
     189  td->estimated.stones = stones; 
     190  td->estimated.movenum = movenum; 
     191  /* Did our clock go wrong? */ 
     192  if (gg_abs(td->estimated.time_left - time_left) >= 1.0) 
     193    td->estimated.time_left = time_left; 
     194  if (stones > 0) 
     195    td->estimated.in_byoyomi = 1; 
     196 
     197  td->official.stones = stones; 
     198  td->official.movenum = movenum; 
     199  td->official.time_for_last_move = td->official.time_for_last_move - time_left; 
     200  td->official.time_left = time_left; 
     201  td->official.in_byoyomi = td->estimated.in_byoyomi; 
    382202} 
    383203 
    384  
    385204/* 
    386  * Check if a player is time over. 
     205 * Update the estimated timer after a move has been made. 
    387206 */ 
    388 int 
    389 clock_is_time_over(int color) 
    390 { 
    391   return clock_is_byoyomi(color) && clock_get_btime_left(color, NULL) <= 0; 
    392 } 
    393  
    394  
    395207void 
    396 clock_print(int color) 
     208clock_push_button(int color) 
    397209{ 
    398   double tleft; 
    399   int stones; 
    400  
    401   if (!clk.clock_on) 
    402     return; 
    403  
    404   gg_assert(clk.ready); 
    405  
    406   fprintf(stderr, "clock: ");  
    407   fprintf(stderr, "%s ", pname[color]); 
    408  
    409   if (clock_is_time_over(color)) 
    410     fprintf(stderr, "TIME OUT! "); 
    411   else { 
    412     if (clock_is_byoyomi(color)) 
    413       tleft = clock_get_btime_left(color, &stones); 
    414     else 
    415       tleft = clock_get_time_left(color); 
    416        
    417     if (clock_is_byoyomi(color)) { 
    418       fprintf(stderr, "byoyomi"); 
    419       timeval_print(stderr, tleft); 
    420       fprintf(stderr, "for %d stones.\n", stones); 
     210  static double last_time = -1.0; 
     211  static int last_movenum = -1; 
     212  struct timer_data* const td 
     213    = (color == BLACK) ? &black_time_data : &white_time_data; 
     214  double now = gg_gettimeofday(); 
     215 
     216  if (last_movenum >= 0 
     217      && movenum == last_movenum + 1 
     218      && movenum > td->estimated.movenum) { 
     219    double time_used = now - last_time; 
     220    td->estimated.time_left -= time_used; 
     221    td->estimated.movenum = movenum; 
     222    td->estimated.time_for_last_move = time_used; 
     223    if (td->estimated.time_left < 0) { 
     224      if (td->estimated.in_byoyomi || byoyomi_stones == 0) { 
     225        DEBUG(DEBUG_TIME, "%s ran out of time.\n", color_to_string(color)); 
     226        if (debug & DEBUG_TIME) 
     227          clock_print(color); 
     228        td->time_out = 1; 
     229      } 
     230      else { 
     231        /* Entering byoyomi. */ 
     232        gg_assert(!(td->estimated.in_byoyomi)); 
     233        td->estimated.in_byoyomi = 1; 
     234        td->estimated.stones = byoyomi_stones - 1; 
     235        td->estimated.time_left += byoyomi_time; 
     236        if (td->estimated.time_left < 0) 
     237          td->time_out = 1; 
     238      } 
     239    } 
     240    else if (td->estimated.stones > 0) { 
     241      gg_assert(td->estimated.in_byoyomi); 
     242      td->estimated.stones = td->estimated.stones - 1; 
     243      if (td->estimated.stones == 0) { 
     244        td->estimated.time_left = byoyomi_time; 
     245        td->estimated.stones = byoyomi_stones; 
     246      } 
    421247    } 
    422     else 
    423       timeval_print(stderr, tleft); 
    424  
    425248  } 
    426   fprintf(stderr, "\n"); 
    427 } 
    428249 
     250  last_movenum = movenum; 
     251  last_time = now; 
     252 
     253  /* Update main timer. */ 
     254  if (debug & DEBUG_TIME) 
     255    clock_print(color); 
     256} 
    429257 
    430258 
    431259/**********************/ 
    clock_print(int color) 
    433261/**********************/ 
    434262 
    435263 
     264/* Analyze the two most recent time reports and determine the time 
     265 * spent on the last moves, the (effective) number of stones left and 
     266 * the (effective) remaining time. 
     267 */ 
     268static int 
     269analyze_time_data(int color, double *time_for_last_move, double *time_left, 
     270                  int *stones_left) 
     271{ 
     272  struct remaining_time_data * const timer 
     273    = (color == BLACK) ? &black_time_data.estimated 
     274                       : &white_time_data.estimated; 
    436275 
    437 /* Write the time/move to outfile */ 
    438 void  
    439 clock_report_autolevel(FILE *outfile, int color) 
    440 { 
    441   int i, first; 
    442   double dt, est, exp; 
    443  
    444   if (!clk.autolevel_on) 
    445     return; 
     276  /* Do we have any time limits. */ 
     277  if (!get_clock_settings(NULL, NULL, NULL)) 
     278    return 0; 
    446279 
    447   if (outfile == NULL) 
    448     outfile = fopen("autolevel.dat", "w"); 
    449   if (outfile == NULL) 
    450     return; 
     280  /* If we don't have consistent time information yet, just return. */ 
     281  if (timer->time_for_last_move < 0.0) 
     282    return 0; 
    451283 
    452   fprintf(outfile, "#\n#  level  prediction   expected  time/move\n");   
    453   fprintf(outfile, "#-----------------------------------------\n");  
     284  *time_for_last_move = timer->time_for_last_move; 
    454285 
    455   if (color == WHITE) 
    456     first = 8; 
    457   else 
    458     first = 9; 
    459  
    460   for (i = first; i < clk.moveno; i += 2) { 
    461     dt = clk.date[i+1] - clk.date[i]; 
    462     est = estimate_time_by_move(color, i); 
    463     exp = clk.expected[i + 1]; 
    464     fprintf(outfile, "%5.2f  %5.2f  %5.2f  %5.2f\n", 
    465             clk.levels[i + 1], est, exp, dt); 
     286  if (timer->stones == 0) { 
     287    /* Main time running. */ 
     288    *time_left = timer->time_left + byoyomi_time; 
     289    if (byoyomi_time > 0) 
     290      *stones_left = byoyomi_stones; 
     291    else { 
     292      /* Absolute time. Here we aim to be able to play at least X more 
     293       * moves or a total of Y moves. We choose Y as a third of the 
     294       * number of vertices and X as 40% of Y. For 19x19 this means 
     295       * that we aim to play at least a total of 120 moves 
     296       * (corresponding to a 240 move game) or another 24 moves. 
     297       * 
     298       * FIXME: Maybe we should use the game_status of 
     299       * influence_evaluate_position() here to guess how many moves 
     300       * are remaining. 
     301       */ 
     302      int nominal_moves = board_size * board_size / 3; 
     303      *stones_left = gg_max(nominal_moves - movenum / 2, 
     304                            2 * nominal_moves / 5); 
     305    } 
     306  } 
     307  else { 
     308    *time_left = timer->time_left; 
     309    *stones_left = timer->stones; 
    466310  } 
     311  return 1; 
    467312} 
    468313 
    469314 
    470 /*  
    471  * Give an estimation of the time/move  
    472  * based on the last played move. 
     315/* Adjust the level offset given information of current playing speed 
     316 * and remaining time and stones. 
    473317 */ 
    474  
    475 /* coeficients to estimate time/move */ 
    476 static const double  
    477 coef[5] = { 
    478   1.0/15.0, 2.0/15.0, 3.0/15.0, 4.0/15.0, 5.0/15.0  
    479 }; 
    480  
    481 static double 
    482 estimate_time_by_move(int color, int move) 
     318void 
     319adjust_level_offset(int color) 
    483320{ 
    484   double res; 
    485   int i; 
     321  double time_for_last_move; 
     322  double time_left; 
     323  int stones_left; 
    486324 
    487   if (move <= 10) 
    488     return 0; 
     325  if (!analyze_time_data(color, &time_for_last_move, &time_left, &stones_left)) 
     326    return; 
    489327 
    490   gg_assert(COLOR(move) == OTHER_COLOR(color)); 
    491328 
    492   res = 0; 
    493   for (i = 0; i < 5; i++) 
    494     res += coef[i] * (clk.date[move-9+i*2] - clk.date[move-10+i*2]); 
    495    
    496   return res; 
     329  /* These rules are both crude and ad hoc. 
     330   * 
     331   * FIXME: Use rules with at least some theoretical basis. 
     332   */ 
     333  if (time_left < time_for_last_move * (stones_left + 3)) 
     334    level_offset--; 
     335  if (time_left < time_for_last_move * stones_left) 
     336    level_offset--; 
     337  if (3 * time_left < 2 * time_for_last_move * stones_left) 
     338    level_offset--; 
     339  if (2 * time_left < time_for_last_move * stones_left) 
     340    level_offset--; 
     341  if (3 * time_left < time_for_last_move * stones_left) 
     342    level_offset--; 
     343 
     344  if (time_for_last_move == 0) 
     345    time_for_last_move = 1; 
     346  if (time_left > time_for_last_move * (stones_left + 6)) 
     347    level_offset++; 
     348  if (time_left > 2 * time_for_last_move * (stones_left + 6)) 
     349    level_offset++; 
     350 
     351  if (level + level_offset < min_level) 
     352    level_offset = min_level - level; 
     353 
     354  if (level + level_offset > max_level) 
     355    level_offset = max_level - level; 
     356 
     357  DEBUG(DEBUG_TIME, "New level %d (%d %C %f %f %d)\n", level + level_offset, 
     358        movenum / 2, color, time_for_last_move, time_left, stones_left); 
    497359} 
    498360 
    499361 
    500 /*  
    501  * Try to respect a "time contract".  
    502  */ 
    503 static void  
    504 respect_time_contract(int color) 
    505 { 
    506   double time_left, expected_tm, predicted_tm; 
    507   double moves_left; 
    508  
    509   fprintf(stderr, "\n*** time contract:\n"); 
    510  
    511   predicted_tm = estimate_time_by_move(color, clk.moveno); 
     362/********************************/ 
     363/* Interface to level settings. */ 
     364/********************************/ 
    512365 
    513   /* Compute the expected mean time/move  
    514    * to respect the contract. 
    515    */ 
    516   moves_left = (CLOCK_MOVE_CONTRACT(board_size) - clk.moveno) / 2.0; 
    517   time_left = (clock_get_time_left(color) 
    518                - (1.0 - CLOCK_TIME_CONTRACT) * clk.main_time); 
    519   expected_tm = time_left / moves_left; 
    520  
    521   clk.expected[clk.moveno + 1] = expected_tm; 
    522  
    523   fprintf(stderr, "%4.0f moves ", moves_left); 
    524   fprintf(stderr, "must be played in %.2fsec\n", time_left); 
    525   fprintf(stderr, "time/move: prediction=%.2f", predicted_tm); 
    526   fprintf(stderr, "+/-%.2fsec --> ", clk.error); 
    527   fprintf(stderr, "expected=%.2f\n", expected_tm); 
    528  
    529   /* Compare this result with the prediction 
    530    * (up to prediction error estimation) 
    531    * and update the level. 
    532    */  
    533   if (clk.level > CLOCK_CONTRACT_MIN_LEVEL) 
    534     if ((predicted_tm - clk.error) > expected_tm) 
    535       clk.level -= CLOCK_STEP; 
    536   if ((predicted_tm + clk.error) < expected_tm) 
    537     clk.level += CLOCK_STEP; 
     366int 
     367get_level() 
     368{ 
     369  return level + level_offset; 
    538370} 
    539371 
    540  
    541 /*  
    542  * Try to keep gnugo ahead on the clock.  
    543  */ 
    544 static void 
    545 keep_ahead(int color) 
     372void 
     373set_level(int new_level) 
    546374{ 
    547   double dt, st, delta_max; 
    548  
    549   fprintf(stderr, "*** safe limit reached: trying to keep ahead\n"); 
    550  
    551   dt = clock_get_time_left(color) - clock_get_time_left(OTHER_COLOR(color)); 
    552   st = clock_get_time_left(color) + clock_get_time_left(OTHER_COLOR(color)); 
    553   delta_max = gg_max(CLOCK_DELTA, CLOCK_DELTAR * st); 
    554  
    555   fprintf(stderr, "deltamax: %gsec, delta=%gsec => ", delta_max, dt); 
    556        
    557   if (dt < -delta_max) { 
    558     fprintf(stderr, "behind\n"); 
    559     clk.level -= CLOCK_STEP; 
    560   } 
    561   else { 
    562     if (dt > delta_max) { 
    563       fprintf(stderr, "ahead\n"); 
    564       clk.level += CLOCK_STEP; 
    565     } 
    566     else 
    567       fprintf(stderr, "equal\n"); 
    568   } 
     375  level = new_level; 
     376  level_offset = 0; 
     377  if (level > max_level) 
     378    max_level = level; 
     379  if (level < min_level) 
     380    min_level = level; 
    569381} 
    570382 
    571  
    572 /*  
    573  * Modify the level during a game to avoid losing by time. 
    574  */ 
    575383void 
    576 clock_adapt_level(int *p_level, int color) 
     384set_max_level(int new_max) 
    577385{ 
    578   double hurry_limit, safe_limit; 
    579  
    580   /*  
    581    * Do not touch the level during the first 10 moves 
    582    * to estimate time/move on a reasonable sample. 
    583    */ 
    584   if (clk.moveno < 10 || !clk.autolevel_on) { 
    585     clk.level = *p_level; 
    586     clk.levels[clk.moveno + 1] = clk.level; 
    587     return; 
    588   } 
    589    
    590   /*  
    591    * Hurry strategy: 
    592    * Behind this limit the only priority is finish at all costs. 
    593    */ 
    594   hurry_limit = gg_max(CLOCK_HURRY, CLOCK_HURRYR * clk.main_time); 
    595   if (clock_get_time_left(color) < hurry_limit) { 
    596     fprintf(stderr, "*** hurry limit reached:\n"); 
    597     clk.level = CLOCK_HURRY_LEVEL; 
    598     *p_level = clk.level; 
    599     return; 
    600   } 
    601  
    602   /*  
    603    * Time contract strategy: 
    604    * try to respect the time of a standard game.  
    605    */ 
    606   if (clk.moveno < CLOCK_MOVE_CONTRACT(board_size)) 
    607     respect_time_contract(color); 
    608  
    609   /*  
    610    * Keep ahead strategy: 
    611    * When the safe_limit is reached gnugo tries to keep ahead in time. 
    612    */ 
    613   safe_limit = gg_max(CLOCK_SAFE, CLOCK_SAFER * clk.main_time); 
    614   if (clock_get_time_left(color) < safe_limit)  
    615     keep_ahead(color); 
    616  
    617   /* Update the level. */ 
    618   if (clk.level > (double) max_level) 
    619     clk.level = (double) max_level; 
    620   if (clk.level < (double) min_level) 
    621     clk.level = (double) min_level; 
    622  
    623   clk.levels[clk.moveno + 1] = clk.level; 
    624   *p_level = clk.level; 
    625    
    626   fprintf(stderr, "level %4.1f at move %d\n", clk.level, movenum); 
     386  max_level = new_max; 
    627387} 
    628388 
     389void 
     390set_min_level(int new_min) 
     391{ 
     392  min_level = new_min; 
     393} 
    629394 
    630395 
    631396/* 
  • engine/clock.h

    RCS file: /cvsroot/gnugo/gnugo/engine/clock.h,v
    retrieving revision 1.11
    diff -u -p -r1.11 clock.h
     
    2323#ifndef _CLOCK_H_ 
    2424#define _CLOCK_H_ 
    2525 
    26 /* ============================================================= *\ 
    27  *                        Time handling                          * 
    28  *                          for GNU Go                           * 
    29  *                         __       __                           * 
    30  *                        <  >     <  >                          * 
    31  *                      +--++-------++--+                        * 
    32  *                      |  .'11 12 1'.  |                        * 
    33  *                      |  :10 \    2:  |                        * 
    34  *                      |  :9   @-> 3:  |                        * 
    35  *                      |  :8       4;  |                        * 
    36  *                      |  '..7 6 5..'  |                        * 
    37  *                      |_______________|                        * 
    38  *                                                               * 
    39 \* ============================================================= */ 
    40  
    41 #include <stdio.h> 
    42 #ifdef HAVE_CONFIG_H 
    43 #include <config.h> 
    44 #endif 
    4526#include "gnugo.h" 
    4627 
    47 #ifdef HAVE_VISUAL_C 
    48 #include <winsock.h> 
    49 #include <io.h> 
    50 #include <time.h> 
    51 #else 
    52 #include <sys/time.h> 
    53 #endif 
    54  
    55 #ifdef __MINGW32__ 
    56 #include <windows.h> 
    57 #include <winsock.h> 
    58 #include <io.h> 
    59 #endif 
    60  
    61 /* interface */ 
    62   
    6328/* initialization and activation */ 
    64 void clock_init(int time, int byo_time, int byo_stones); 
    65 void clock_enable(void); 
     29void clock_settings(int time, int byo_time, int byo_stones); 
     30void init_timers(void); 
    6631  
    67 void clock_enable_autolevel(void); 
    68  
    6932/* main access */ 
    7033void clock_push_button(int color); 
    71 void clock_unpush_button(int color); 
    72  
    73 /* getting informations about clock */ 
    74 int clock_is_byoyomi(int color); 
    75 int clock_is_time_over(int color); 
    76 double clock_get_timer(int color); 
    77 double clock_get_btimer(int color); 
    78 double clock_get_time_left(int color); 
    79 double clock_get_btime_left(int color, int *stones); 
     34void update_time_left(int color, int time_left, int stones); 
     35void clock_print(int color); 
     36int get_clock_settings(int *t, int *byo_t, int *byo_s); 
    8037 
    81 /* adaptative system */ 
    82 void clock_adapt_level(int *p_level, int color); 
     38void adjust_level_offset(int color); 
    8339 
    84 /* output */ 
    85 void clock_print(int color); 
    86 void clock_report_autolevel(FILE *f, int color); 
     40/* Access to level settings. */ 
     41int get_level(void); 
     42void set_level(int new_level); 
     43void set_max_level(int new_max); 
     44void set_min_level(int new_min); 
    8745 
    8846 
    8947#endif  /* _CLOCK_H_ */ 
  • engine/dragon.c

    RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v
    retrieving revision 1.153
    diff -u -p -r1.153 dragon.c
    make_dragons(int stop_before_owl) 
    354354        int dcode = DRAGON2(str).owl_defense_code; 
    355355        int defense_point, second_defense_point; 
    356356         
    357         if (level >= 8 
     357        if (get_level() >= 8 
    358358            && !disable_threat_computation 
    359359            && (owl_threats  
    360360                || thrashing_stone[str])) { 
  • engine/genmove.c

    RCS file: /cvsroot/gnugo/gnugo/engine/genmove.c,v
    retrieving revision 1.107
    diff -u -p -r1.107 genmove.c
    reset_engine() 
    9191  clear_break_in_list(); 
    9292 
    9393  /* Set up depth values (see comments there for details). */ 
    94   set_depth_values(level, 0); 
     94  set_depth_values(get_level(), 0); 
    9595} 
    9696 
    9797/* 
    do_genmove(int color, float pure_threat_ 
    318318  move = PASS_MOVE;   
    319319  *value = 0.0;  
    320320   
    321   /* experimental level adapter */ 
    322   clock_adapt_level(&level, color); 
    323  
    324321  /* Prepare pattern matcher and reading code. */ 
    325322  reset_engine(); 
    326323 
  • engine/globals.c

    RCS file: /cvsroot/gnugo/gnugo/engine/globals.c,v
    retrieving revision 1.76
    diff -u -p -r1.76 globals.c
    int disable_fuseki = 0; /* do not ge 
    9292int josekidb          = 1;  /* use joseki database */ 
    9393int showtime          = 0;  /* print time to find move */ 
    9494int showscore         = 0;  /* print estimated score */ 
    95 int level             = DEFAULT_LEVEL; /* strength; up to 10 supported */ 
    96 int min_level         = 0; 
    97 int max_level         = gg_max(DEFAULT_LEVEL, 10); 
    9895int debug             = 0;  /* controls debug output */ 
    9996int verbose           = 0;  /* trace level */ 
    10097char outfilename[128] = ""; /* output file (-o option) */ 
    int output_flags = OUTPUT_DEFAULT;  
    10299int limit_search      = 0;  /* limit search to a portion of the board */ 
    103100int metamachine       = 0;  /* use metamachine_genmove */ 
    104101int oracle_exists     = 0;  /* oracle is available for consultation   */ 
     102int autolevel_on      = 0;  /* Adjust leven in GMP or ASCII mode. */ 
    105103 
    106104int disable_threat_computation = 0; 
    107105int disable_endgame_patterns   = 0; 
  • engine/gnugo.h

    RCS file: /cvsroot/gnugo/gnugo/engine/gnugo.h,v
    retrieving revision 1.124
    diff -u -p -r1.124 gnugo.h
    extern int output_flags; /* amount 
    176176#define DEBUG_ORACLE_STREAM         0x1000000 
    177177#define DEBUG_LARGE_SCALE           0x1000000 
    178178#define DEBUG_SPLIT_OWL             0x2000000 
     179#define DEBUG_TIME                  0x4000000 
    179180 
    180181 
    181182#define DEBUG_FLAGS "\ 
    DEBUG_MISCELLANEOUS 0x800000\n\ 
    206207DEBUG_ORACLE_STREAM         0x1000000\n\ 
    207208DEBUG_LARGE_SCALE           0x1000000\n\ 
    208209DEBUG_SPLIT_OWL             0x2000000\n\ 
     210DEBUG_TIME                  0x4000000\n\ 
    209211" 
    210212 
    211213 
    extern int hashflags; /* hash flags */ 
    242244extern int fusekidb;            /* use fuseki database */ 
    243245extern int disable_fuseki;      /* do not generate fuseki moves */ 
    244246extern int josekidb;            /* use joseki database */ 
    245 extern int level;               /* controls depth of reading */ 
    246247extern int semeai_variations;   /* max variations considered reading semeai */ 
    247248extern int showtime;            /* print genmove time */ 
    248249extern int showscore;           /* print score */ 
    extern int mandated_owl_branch_depth; 
    274275extern int mandated_owl_reading_depth; 
    275276extern int mandated_owl_node_limit;  
    276277extern int mandated_semeai_node_limit;  
     278 
     279extern int autolevel_on; 
    277280 
    278281extern float potential_moves[BOARDMAX]; 
    279282 
  • engine/interface.c

    RCS file: /cvsroot/gnugo/gnugo/engine/interface.c,v
    retrieving revision 1.57
    diff -u -p -r1.57 interface.c
    gnugo_clear_board(int boardsize) 
    6767{ 
    6868  board_size = boardsize; 
    6969  clear_board(); 
     70  init_timers(); 
    7071#if 0 
    7172  if (metamachine && oracle_exists) 
    7273    oracle_clear_board(boardsize); 
  • engine/liberty.h

    RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
    retrieving revision 1.245
    diff -u -p -r1.245 liberty.h
    extern int connect_depth2; 
    731731extern int connection_node_limit; 
    732732extern int breakin_depth; 
    733733extern int breakin_node_limit; 
    734 extern int level;               /* controls the strength of play */ 
    735 extern int min_level;           /* minimum level for adjustment schemes */ 
    736 extern int max_level;           /* minimum level for adjustment schemes */ 
    737734extern int semeai_variations;   /* max variations considered reading semeai */ 
    738735extern float best_move_values[10]; 
    739736extern int best_moves[10]; 
  • engine/owl.c

    RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
    retrieving revision 1.237
    diff -u -p -r1.237 owl.c
    do_owl_analyze_semeai(int apos, int bpos 
    919919      include_semeai_worms_in_eyespace = 0; 
    920920    } 
    921921 
    922     if (level < 8) { 
     922    if (get_level() < 8) { 
    923923      /* If no owl moves were found on two consecutive moves, 
    924924       * turn off the owl phase. 
    925925       */ 
    owl_estimate_life(struct local_owl_data  
    28532853  matches_found = 0; 
    28542854  memset(found_matches, 0, sizeof(found_matches)); 
    28552855 
    2856   if (level >= 8) { 
     2856  if (get_level() >= 8) { 
    28572857    memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache)); 
    28582858    if (!does_attack) { 
    28592859      clear_owl_move_data(dummy_moves); 
    owl_substantial(int str) 
    59585958  /* fill all the liberties */ 
    59595959  for (k = 0; k < liberties; k++) { 
    59605960    if (trymove(libs[k], owl->color, NULL, 0)) { 
    5961       if (level >= 8) 
     5961      if (get_level() >= 8) 
    59625962        increase_depth_values(); 
    59635963      owl->goal[libs[k]] = 1; 
    59645964    } 
    owl_substantial(int str) 
    59665966      /* if we can't fill, try swapping with the next liberty */ 
    59675967      if (k < liberties-1 
    59685968          && trymove(libs[k+1], owl->color, NULL, 0)) { 
    5969         if (level >= 8) 
     5969        if (get_level() >= 8) 
    59705970          increase_depth_values(); 
    59715971        owl->goal[libs[k+1]] = 1; 
    59725972        libs[k+1] = libs[k]; 
    owl_substantial(int str) 
    59745974      else { 
    59755975        /* Can't fill the liberties. Give up! */ 
    59765976        while (stackp > 0) { 
    5977           if (level >= 8) 
     5977          if (get_level() >= 8) 
    59785978            decrease_depth_values(); 
    59795979          popgo(); 
    59805980        } 
    owl_substantial(int str) 
    59955995  else 
    59965996    result = 1; 
    59975997  while (stackp > 0) { 
    5998     if (level >= 8) 
     5998    if (get_level() >= 8) 
    59995999      decrease_depth_values(); 
    60006000    popgo(); 
    60016001  } 
  • engine/reading.c

    RCS file: /cvsroot/gnugo/gnugo/engine/reading.c,v
    retrieving revision 1.162
    diff -u -p -r1.162 reading.c
    defend3(int str, int *move) 
    17571757    bamboo_rescue_moves(str, liberties, libs, &moves); 
    17581758  } 
    17591759 
    1760   if (level >= 8 && stackp <= backfill2_depth) 
     1760  if (get_level() >= 8 && stackp <= backfill2_depth) 
    17611761    superstring_break_chain_moves(str, 4, &moves); 
    17621762 
    17631763  if (stackp <= break_chain_depth) 
    defend3(int str, int *move) 
    17751775  /* If nothing else works, we try playing a liberty of the 
    17761776   * super_string. 
    17771777   */ 
    1778   if (level >= 8 && stackp <= backfill2_depth) { 
     1778  if (get_level() >= 8 && stackp <= backfill2_depth) { 
    17791779    superstring_moves(str, &moves, 3, 0); 
    17801780    squeeze_moves(str, &moves); 
    17811781  } 
    attack2(int str, int *move) 
    32173217      /* If it is not possible to make a direct atari, we try filling 
    32183218       * a liberty of the superstring. 
    32193219       */ 
    3220       if (level >= 8 
     3220      if (get_level() >= 8 
    32213221          && stackp <= backfill_depth 
    32223222          && (stackp <= superstring_depth || !atari_possible)) { 
    32233223        int liberty_cap = 2; 
    attack3(int str, int *move) 
    33653365      /* If nothing else works, we try filling a liberty of the 
    33663366       * super_string. 
    33673367       */ 
    3368       if (level >= 8 && stackp <= backfill2_depth) { 
     3368      if (get_level() >= 8 && stackp <= backfill2_depth) { 
    33693369        superstring_moves(str, &moves, 3, 1); 
    33703370        squeeze_moves(str, &moves); 
    33713371      } 
  • engine/sgffile.c

    RCS file: /cvsroot/gnugo/gnugo/engine/sgffile.c,v
    retrieving revision 1.35
    diff -u -p -r1.35 sgffile.c
    sgffile_printsgf(int color_to_play, cons 
    165165  sgftree_clear(&sgftree); 
    166166  sgftreeCreateHeaderNode(&sgftree, board_size, relative_komi); 
    167167  sgf_write_header(sgftree.root, 1, get_random_seed(), relative_komi, 
    168                    level, chinese_rules); 
     168                   get_level(), chinese_rules); 
    169169  gg_snprintf(str, 128, "GNU Go %s load and print", gg_version()); 
    170170  sgfOverwriteProperty(sgftree.root, "GN", str); 
    171171   
  • 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
    review_move_reasons(int *the_move, float 
    37573757  find_more_attack_and_defense_moves(color); 
    37583758  time_report(2, "  find_more_attack_and_defense_moves", NO_MOVE, 1.0); 
    37593759 
    3760   if (level >= 6) { 
     3760  if (get_level() >= 6) { 
    37613761    find_more_owl_attack_and_defense_moves(color); 
    37623762    time_report(2, "  find_more_owl_attack_and_defense_moves", NO_MOVE, 1.0); 
    37633763  } 
    37643764 
    3765   if (large_scale && level >= 6) { 
     3765  if (large_scale && get_level() >= 6) { 
    37663766    find_large_scale_owl_attack_moves(color); 
    37673767    time_report(2, "  find_large_scale_owl_attack_moves", NO_MOVE, 1.0); 
    37683768  } 
  • interface/main.c

    RCS file: /cvsroot/gnugo/gnugo/interface/main.c,v
    retrieving revision 1.121
    diff -u -p -r1.121 main.c
    main(int argc, char *argv[]) 
    337337  int seed = 0; 
    338338  int seed_specified = 0; 
    339339 
    340   /* Default parameters for clock and auto level systems. */ 
    341   clock_init(3600, 0, 0);      /* One hour sudden death. */ 
    342  
    343340  sgftree_clear(&sgftree); 
    344341  gameinfo_clear(&gameinfo, board_size, komi); 
    345342   
    main(int argc, char *argv[]) 
    780777        break; 
    781778         
    782779      case OPT_LEVEL: 
    783         level = atoi(gg_optarg); 
    784         if (level > max_level) 
    785           max_level = level; 
    786         if (level < min_level) 
    787           min_level = level; 
     780        set_level(atoi(gg_optarg)); 
    788781        break; 
    789782 
    790783      case OPT_MIN_LEVEL: 
    791         min_level = atoi(gg_optarg); 
     784        set_min_level(atoi(gg_optarg)); 
    792785        break; 
    793786 
    794787      case OPT_MAX_LEVEL: 
    795         max_level = atoi(gg_optarg); 
     788        set_max_level(atoi(gg_optarg)); 
    796789        break; 
    797790 
    798791      case OPT_LIMIT_SEARCH: 
    main(int argc, char *argv[]) 
    807800        break; 
    808801 
    809802      case OPT_CLOCK_TIME: 
    810  
    811         clock_init(atoi(gg_optarg), -1, -1); 
    812         clock_enable(); 
     803        clock_settings(atoi(gg_optarg), -1, -1); 
    813804        break; 
    814805 
    815806      case OPT_CLOCK_BYO_TIME:  
    816         clock_init(-1, atoi(gg_optarg), -1); 
    817         clock_enable(); 
     807        clock_settings(-1, atoi(gg_optarg), -1); 
    818808        break; 
    819809 
    820810      case OPT_CLOCK_BYO_PERIOD: 
    821         clock_init(-1, -1, atoi(gg_optarg)); 
    822         clock_enable(); 
     811        clock_settings(-1, -1, atoi(gg_optarg)); 
    823812        break; 
    824813 
    825814      case OPT_AUTOLEVEL: 
    826         clock_init(-1, -1, -1); 
    827         clock_enable(); 
    828         clock_enable_autolevel(); 
     815        autolevel_on = 1; 
    829816        break; 
    830817         
    831818      case OPT_DEBUG_INFLUENCE: 
    main(int argc, char *argv[]) 
    13721359  if (profile_patterns) 
    13731360    report_pattern_profiling(); 
    13741361 
    1375   clock_report_autolevel(NULL, gameinfo.computer_player); 
    13761362  sgfFreeNode(sgftree.root);  
    13771363 
    13781364  return 0; 
    Options providing detailed reading resul 
    15561542static void 
    15571543show_help(void) 
    15581544{ 
    1559   set_depth_values(DEFAULT_LEVEL, 0); 
    1560   printf(USAGE, level); 
     1545  printf(USAGE, DEFAULT_LEVEL); 
    15611546  printf(USAGE1, (float) DEFAULT_MEMORY); 
    15621547  printf(USAGE2, MIN_BOARD, MAX_BOARD, MAX_HANDICAP); 
    15631548} 
  • 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
    static int showdead = 0; 
    5454static SGFTree sgftree; 
    5555static int resignation_allowed; 
    5656 
     57static int clock_on = 0; 
     58 
    5759/* Unreasonable score used to detect missing information. */ 
    5860#define NO_SCORE 4711 
    5961/* Keep track of the score estimated before the last computer move. */ 
    ascii_showboard(void) 
    296298  fflush(stdout); 
    297299  printf("%s\n\n", letterbar); 
    298300  fflush(stdout); 
     301 
     302  if (clock_on) { 
     303    clock_print(WHITE); 
     304    clock_print(BLACK); 
     305  } 
    299306   
    300307}  /* end ascii_showboard */ 
    301308 
    init_sgf(Gameinfo *ginfo) 
    440447  sgf_initialized = 1; 
    441448 
    442449  sgf_write_header(sgftree.root, 1, get_random_seed(), komi, 
    443                    level, chinese_rules); 
     450                   get_level(), chinese_rules); 
    444451  sgfOverwritePropertyInt(sgftree.root, "HA", ginfo->handicap); 
    445452  if (ginfo->handicap > 0) 
    446453    sgffile_recordboard(sgftree.root); 
    computer_move(Gameinfo *gameinfo, int *p 
    463470  init_sgf(gameinfo); 
    464471 
    465472  /* Generate computer move. */ 
     473  if (autolevel_on) 
     474    adjust_level_offset(gameinfo->to_move); 
    466475  move_value = gnugo_genmove(&i, &j, gameinfo->to_move, &resign); 
    467476  if (resignation_allowed && resign) { 
    468477    int state = ascii_endgame(gameinfo, 2); 
    do_play_ascii(Gameinfo *gameinfo) 
    618627  char *tmpstring; 
    619628  int state = 1; 
    620629 
     630  if (get_clock_settings(NULL, NULL, NULL)) 
     631    clock_on = 1; 
     632 
    621633  while (state == 1) { 
    622634    state = 0; 
    623635 
    do_play_ascii(Gameinfo *gameinfo) 
    775787            printf("\nInvalid command syntax!\n"); 
    776788            break; 
    777789          } 
    778           level = num; 
    779           printf("\nSet level to %d\n", level); 
     790          set_level(num); 
     791          printf("\nSet level to %d\n", num); 
    780792          break; 
    781793 
    782794        case DISPLAY: 
  • 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
    play_gmp(Gameinfo *gameinfo, int simplif 
    133133 
    134134  gameinfo->computer_player = mycolor; 
    135135  sgf_write_header(sgftree.root, 1, get_random_seed(), komi, 
    136                    level, chinese_rules); 
     136                   get_level(), chinese_rules); 
    137137  gameinfo->handicap = gnugo_sethand(gameinfo->handicap, sgftree.root); 
    138138  sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap); 
    139139 
    play_gmp(Gameinfo *gameinfo, int simplif 
    186186    } 
    187187    else { 
    188188      /* Generate my next move. */ 
    189       float move_value = gnugo_genmove(&i, &j, mycolor, NULL); 
     189      float move_value; 
     190      if (autolevel_on) 
     191        adjust_level_offset(mycolor); 
     192      move_value = gnugo_genmove(&i, &j, mycolor, NULL); 
    190193      gnugo_play_move(i, j, mycolor); 
    191194      sgffile_add_debuginfo(sgftree.lastnode, move_value); 
    192195       
  • 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
     
    3535 
    3636/* Internal state that's not part of the engine. */ 
    3737static int handicap = 0; 
    38 static int main_time = 0; 
    39 static int byo_yomi_time = 1; 
    40 static int byo_yomi_stones = 0; 
    4138 
    4239static int report_uncertainty = 0; 
    4340static int gtp_orientation = 0; 
    4441 
    45 /* Time handling. Index 0 is the most recent report, index 1 the 
    46  * second most recent report. 
    47  */ 
    48 static int black_time_left[2]; 
    49 static int black_stones_left[2]; 
    50 static int white_time_left[2]; 
    51 static int white_stones_left[2]; 
    52 static int level_offset; 
    53  
    54  
    55 static void gtp_init_time_handling(void); 
    56 static void analyze_time_data(int time_left_data[2], int stones_left_data[2], 
    57                               int *time_for_last_move, 
    58                               int *time_left, int *stones_left); 
    59 static void adjust_level_offset(int color); 
    6042static void gtp_print_code(int c); 
    6143static void gtp_print_vertices2(int n, int *moves); 
    6244static void rotate_on_input(int ai, int aj, int *bi, int *bj); 
    play_gtp(FILE *gtp_input, FILE *gtp_outp 
    359341  gtp_set_vertex_transform_hooks(rotate_on_input, rotate_on_output); 
    360342 
    361343  /* Initialize time handling. */ 
    362   gtp_init_time_handling(); 
     344  init_timers(); 
    363345   
    364346  /* Prepare pattern matcher and reading code. */ 
    365347  reset_engine(); 
    gtp_clear_board(char *s) 
    516498    update_random_seed(); 
    517499 
    518500  clear_board(); 
    519   gtp_init_time_handling(); 
     501  init_timers(); 
    520502   
    521503  return gtp_success(""); 
    522504} 
    gtp_playblack(char *s) 
    627609  if (!is_legal(POS(i, j), BLACK)) 
    628610    return gtp_failure("illegal move"); 
    629611 
    630   play_move(POS(i, j), BLACK); 
     612  gnugo_play_move(i, j, BLACK); 
    631613  return gtp_success(""); 
    632614} 
    633615 
    gtp_playwhite(char *s) 
    658640  if (!is_legal(POS(i, j), WHITE)) 
    659641    return gtp_failure("illegal move"); 
    660642 
    661   play_move(POS(i, j), WHITE); 
     643  gnugo_play_move(i, j, WHITE); 
    662644  return gtp_success(""); 
    663645} 
    664646 
    gtp_play(char *s) 
    682664  if (!is_legal(POS(i, j), color)) 
    683665    return gtp_failure("illegal move"); 
    684666 
    685   play_move(POS(i, j), color); 
     667  gnugo_play_move(i, j, color); 
    686668  return gtp_success(""); 
    687669} 
    688670 
    gtp_loadsgf(char *s) 
    871853  handicap = gameinfo.handicap; 
    872854  gtp_internal_set_boardsize(board_size); 
    873855  reset_engine(); 
    874   gtp_init_time_handling(); 
     856  init_timers(); 
    875857 
    876858  sgfFreeNode(sgftree.root); 
    877859 
    gtp_genmove_black(char *s) 
    24712453 
    24722454  move = genmove(BLACK, NULL, NULL); 
    24732455 
    2474   play_move(move, BLACK); 
     2456  gnugo_play_move(I(move), J(move), BLACK); 
    24752457 
    24762458  gtp_start_response(GTP_SUCCESS); 
    24772459  gtp_print_vertex(I(move), J(move)); 
    gtp_genmove_white(char *s) 
    24962478 
    24972479  move = genmove(WHITE, NULL, NULL); 
    24982480 
    2499   play_move(move, WHITE); 
     2481  gnugo_play_move(I(move), J(move), WHITE); 
    25002482 
    25012483  gtp_start_response(GTP_SUCCESS); 
    25022484  gtp_print_vertex(I(move), J(move)); 
    gtp_genmove(char *s) 
    25262508    return gtp_failure("genmove cannot be called when stackp > 0"); 
    25272509 
    25282510  adjust_level_offset(color); 
    2529   level += level_offset; 
    25302511  move = genmove(color, NULL, &resign); 
    2531   level -= level_offset; 
    25322512 
    25332513  if (resign) 
    25342514    return gtp_success("resign"); 
    25352515 
    2536   play_move(move, color); 
     2516  gnugo_play_move(I(move), J(move), color); 
    25372517 
    25382518  gtp_start_response(GTP_SUCCESS); 
    25392519  gtp_print_vertex(I(move), J(move)); 
    gtp_kgs_genmove_cleanup(char *s) 
    27082688  capture_all_dead = 1; 
    27092689   
    27102690  adjust_level_offset(color); 
    2711   level += level_offset; 
    27122691  move = genmove(color, NULL, NULL); 
    2713   level -= level_offset; 
    27142692 
    27152693  capture_all_dead = save_capture_all_dead; 
    27162694   
    2717   play_move(move, color); 
     2695  gnugo_play_move(I(move), J(move), color); 
    27182696 
    27192697  gtp_start_response(GTP_SUCCESS); 
    27202698  gtp_print_vertex(I(move), J(move)); 
    gtp_set_level(char *s) 
    28452823  if (sscanf(s, "%d", &new_level) < 1) 
    28462824    return gtp_failure("level not an integer"); 
    28472825   
    2848   level = new_level; 
    2849   level_offset = 0; 
     2826  set_level(new_level); 
    28502827  return gtp_success(""); 
    28512828} 
    28522829 
    gtp_gg_undo(char *s) 
    29012878 * time handling * 
    29022879 *****************/ 
    29032880 
    2904 /* Initialize time data variables and set the level offset to 0. */ 
    2905 static void 
    2906 gtp_init_time_handling(void) 
    2907 { 
    2908   int k; 
    2909   for (k = 0; k < 1; k++) { 
    2910     black_time_left[k] = -1; 
    2911     black_stones_left[k] = -1; 
    2912     white_time_left[k] = -1; 
    2913     white_stones_left[k] = -1; 
    2914   } 
    2915   level_offset = 0; 
    2916 } 
    2917  
    2918 /* Analyze the two most recent time reports and determine the time 
    2919  * spent on the last moves, the (effective) number of stones left and 
    2920  * the (effective) remaining time. 
    2921  */ 
    2922 static void 
    2923 analyze_time_data(int time_left_data[2], int stones_left_data[2], 
    2924                   int *time_for_last_move, int *time_left, int *stones_left) 
    2925 { 
    2926   *time_for_last_move = -1; 
    2927   *time_left = -1; 
    2928   *stones_left = -1; 
    2929  
    2930   /* Do we have any time limits. */ 
    2931   if (byo_yomi_stones == 0 && byo_yomi_time > 0) 
    2932     return; 
    2933    
    2934   /* If we don't have time information for the two last moves, just return. */ 
    2935   if (time_left_data[1] < 0) 
    2936     return; 
    2937  
    2938   if (stones_left_data[0] == 0) { 
    2939     /* Main time running. */ 
    2940     *time_for_last_move = time_left_data[1] - time_left_data[0]; 
    2941     *time_left = time_left_data[0] + byo_yomi_time; 
    2942     if (byo_yomi_time > 0) 
    2943       *stones_left = byo_yomi_stones; 
    2944     else { 
    2945       /* Absolute time. Here we aim to be able to play at least X more 
    2946        * moves or a total of Y moves. We choose Y as a third of the 
    2947        * number of vertices and X as 40% of Y. For 19x19 this means 
    2948        * that we aim to play at least a total of 120 moves 
    2949        * (corresponding to a 240 move game) or another 24 moves. 
    2950        */ 
    2951       int nominal_moves = board_size * board_size / 3; 
    2952       *stones_left = gg_max(nominal_moves - movenum / 2, 
    2953                             2 * nominal_moves / 5); 
    2954     } 
    2955   } 
    2956   else { 
    2957     if (stones_left_data[1] == 0) 
    2958       *time_for_last_move = time_left_data[1] + (byo_yomi_time 
    2959                                                  - time_left_data[0]); 
    2960     else if (stones_left_data[1] == stones_left_data[0] + 1) 
    2961       *time_for_last_move = time_left_data[1] - time_left_data[0]; 
    2962     else 
    2963       return; 
    2964  
    2965     *time_left = time_left_data[0]; 
    2966     *stones_left = stones_left_data[0]; 
    2967   } 
    2968 } 
    2969  
    2970 /* Adjust the level offset given information of current playing speed 
    2971  * and remaining time and stones. 
    2972  * 
    2973  * FIXME: Integrate this code with the one in clock.c. Or maybe rather 
    2974  *        replace them both with something better. 
    2975  */ 
    2976 static void 
    2977 adjust_level_offset(int color) 
    2978 { 
    2979   int time_for_last_move; 
    2980   int time_left; 
    2981   int stones_left; 
    2982  
    2983   if (color == BLACK) 
    2984     analyze_time_data(black_time_left, black_stones_left, &time_for_last_move, 
    2985                       &time_left, &stones_left); 
    2986   else 
    2987     analyze_time_data(white_time_left, white_stones_left, &time_for_last_move, 
    2988                       &time_left, &stones_left); 
    2989  
    2990   if (time_for_last_move < 0) 
    2991     return; 
    2992  
    2993   /* These rules are both crude and ad hoc. 
    2994    * 
    2995    * FIXME: Use rules with at least some theoretical basis. 
    2996    */ 
    2997   if (time_left < time_for_last_move * (stones_left + 3)) 
    2998     level_offset--; 
    2999   if (time_left < time_for_last_move * stones_left) 
    3000     level_offset--; 
    3001   if (3 * time_left < 2 * time_for_last_move * stones_left) 
    3002     level_offset--; 
    3003   if (2 * time_left < time_for_last_move * stones_left) 
    3004     level_offset--; 
    3005   if (3 * time_left < time_for_last_move * stones_left) 
    3006     level_offset--; 
    3007  
    3008   if (time_for_last_move == 0) 
    3009     time_for_last_move = 1; 
    3010   if (time_left > time_for_last_move * (stones_left + 6)) 
    3011     level_offset++; 
    3012   if (time_left > 2 * time_for_last_move * (stones_left + 6)) 
    3013     level_offset++; 
    3014  
    3015   if (level + level_offset < min_level) 
    3016     level_offset = min_level - level; 
    3017  
    3018   if (level + level_offset > max_level) 
    3019     level_offset = max_level - level; 
    3020  
    3021   if (1) { 
    3022     if (level_offset != 0) { 
    3023       gprintf("New level %d (%d %C %d %d %d)\n", level + level_offset, 
    3024               movenum / 2, color, time_for_last_move, time_left, stones_left); 
    3025     } 
    3026   } 
    3027 } 
    3028  
    30292881/* Function:  Set time allowance 
    30302882 * Arguments: int main_time, int byo_yomi_time, int byo_yomi_stones 
    30312883 * Fails:     syntax error 
    adjust_level_offset(int color) 
    30372889static int 
    30382890gtp_time_settings(char *s) 
    30392891{ 
    3040   int a, b, c; 
     2892  int main_time, byoyomi_time, byoyomi_stones; 
    30412893   
    3042   if (sscanf(s, "%d %d %d", &a, &b, &c) < 3) 
     2894  if (sscanf(s, "%d %d %d", &main_time, &byoyomi_time, &byoyomi_stones) < 3) 
    30432895    return gtp_failure("not three integers"); 
    30442896 
    3045   main_time = a; 
    3046   byo_yomi_time = b; 
    3047   byo_yomi_stones = c; 
    3048  
     2897  clock_settings(main_time, byoyomi_time, byoyomi_stones); 
    30492898  return gtp_success(""); 
    30502899} 
    30512900 
    gtp_time_left(char *s) 
    30732922  if (sscanf(s+n, "%d %d", &time, &stones) < 2) 
    30742923    return gtp_failure("time and stones not two integers"); 
    30752924 
    3076   if (color == BLACK) { 
    3077     black_time_left[1] = black_time_left[0]; 
    3078     black_stones_left[1] = black_stones_left[0]; 
    3079     black_time_left[0] = time; 
    3080     black_stones_left[0] = stones; 
    3081   } 
    3082   else { 
    3083     white_time_left[1] = white_time_left[0]; 
    3084     white_stones_left[1] = white_stones_left[0]; 
    3085     white_time_left[0] = time; 
    3086     white_stones_left[0] = stones; 
    3087   } 
     2925  update_time_left(color, time, stones); 
    30882926   
    30892927  return gtp_success(""); 
    30902928} 
    finish_and_score_game(int seed) 
    31492987 
    31502988  do { 
    31512989    move = genmove_conservative(next, NULL); 
    3152     play_move(move, next); 
     2990    gnugo_play_move(I(move), J(move), next); 
    31532991    if (move != PASS_MOVE) { 
    31542992      pass = 0; 
    31552993      moves++; 
  • 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
    play_solo(Gameinfo *gameinfo, int moves) 
    6161  sgftree_clear(&sgftree); 
    6262  sgftreeCreateHeaderNode(&sgftree, board_size, komi); 
    6363  sgf_write_header(sgftree.root, 1, get_random_seed(), 5.5, 
    64                    level, chinese_rules); 
     64                   get_level(), chinese_rules); 
    6565  
    6666  /* Generate some random moves. */ 
    6767  if (board_size > 6) {