Ticket #33: arend_7_8.1b-clock.diff
| File arend_7_8.1b-clock.diff, 50.5 KB (added by arend, 6 years ago) |
|---|
-
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 411 411 struct moyo_data territories; 412 412 int k; 413 413 414 if (!experimental_break_in || level< 10)414 if (!experimental_break_in || get_level() < 10) 415 415 return; 416 416 417 417 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
35 35 * * 36 36 \* ============================================================= */ 37 37 38 #include "gnugo.h"39 40 #include "liberty.h"41 #include "gg_utils.h"42 38 #include "clock.h" 39 #include "gg_utils.h" 40 #include "board.h" 43 41 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 */ 43 static int level = DEFAULT_LEVEL; /* current level */ 44 static int level_offset = 0; 45 static int min_level = 0; 46 static int max_level = gg_max(DEFAULT_LEVEL, 10); 57 47 58 48 59 49 /*************************/ 60 50 /* Datas and other stuff */ 61 51 /*************************/ 62 52 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 */ 54 static int main_time = -1; 55 static int byoyomi_time = -1; 56 static 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 */ 62 struct remaining_time_data { 63 double time_left; 64 double time_for_last_move; 65 int stones; 66 int movenum; 67 int in_byoyomi; 68 }; 105 69 70 struct timer_data { 71 struct remaining_time_data official; 72 struct remaining_time_data estimated; 73 int time_out; 74 }; 106 75 76 static struct timer_data black_time_data; 77 static struct timer_data white_time_data; 107 78 108 79 109 80 /* Echo a time value in STANDARD format */ 110 111 81 static void 112 82 timeval_print(FILE *outfile, double tv) 113 83 { … … timeval_print(FILE *outfile, double tv) 120 90 fprintf(outfile, "%3dmin %.2fsec ", min, sec); 121 91 } 122 92 123 /******************************/124 /* Initialization functions */125 /******************************/126 127 93 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. */ 133 95 void 134 clock_ init(int time, int byo_time, int byo_stones)96 clock_print(int color) 135 97 { 136 int color; 98 struct timer_data* const td 99 = (color == BLACK) ? &black_time_data : &white_time_data; 137 100 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)); 145 103 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); 148 114 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;155 115 } 116 fprintf(stderr, "\n"); 156 117 } 157 118 158 119 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 /******************************/ 216 123 217 124 /* 218 * Update the clock. 125 * Initialize the time settings for this game. 126 * -1 means "do not modify this value". 219 127 */ 220 128 void 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) 129 clock_settings(int time, int byo_time, int byo_stones) 281 130 { 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(); 311 138 } 312 139 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. 316 142 */ 317 double 318 clock_get_timer(int color)143 int 144 get_clock_settings(int *t, int *byo_t, int *byo_s) 319 145 { 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); 330 153 } 331 154 332 155 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. */ 157 void 158 init_timers() 338 159 { 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; 342 168 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; 350 170 } 351 171 352 172 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 /*****************************/ 370 176 371 177 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) 178 void 179 update_time_left(int color, int time_left, int stones) 377 180 { 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; 382 202 } 383 203 384 385 204 /* 386 * Check if a player is time over.205 * Update the estimated timer after a move has been made. 387 206 */ 388 int389 clock_is_time_over(int color)390 {391 return clock_is_byoyomi(color) && clock_get_btime_left(color, NULL) <= 0;392 }393 394 395 207 void 396 clock_p rint(int color)208 clock_push_button(int color) 397 209 { 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 } 421 247 } 422 else423 timeval_print(stderr, tleft);424 425 248 } 426 fprintf(stderr, "\n");427 }428 249 250 last_movenum = movenum; 251 last_time = now; 252 253 /* Update main timer. */ 254 if (debug & DEBUG_TIME) 255 clock_print(color); 256 } 429 257 430 258 431 259 /**********************/ … … clock_print(int color) 433 261 /**********************/ 434 262 435 263 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 */ 268 static int 269 analyze_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; 436 275 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; 446 279 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; 451 283 452 fprintf(outfile, "#\n# level prediction expected time/move\n"); 453 fprintf(outfile, "#-----------------------------------------\n"); 284 *time_for_last_move = timer->time_for_last_move; 454 285 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; 466 310 } 311 return 1; 467 312 } 468 313 469 314 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. 473 317 */ 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) 318 void 319 adjust_level_offset(int color) 483 320 { 484 double res; 485 int i; 321 double time_for_last_move; 322 double time_left; 323 int stones_left; 486 324 487 if ( move <= 10)488 return 0;325 if (!analyze_time_data(color, &time_for_last_move, &time_left, &stones_left)) 326 return; 489 327 490 gg_assert(COLOR(move) == OTHER_COLOR(color));491 328 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); 497 359 } 498 360 499 361 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 /********************************/ 512 365 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; 366 int 367 get_level() 368 { 369 return level + level_offset; 538 370 } 539 371 540 541 /* 542 * Try to keep gnugo ahead on the clock. 543 */ 544 static void 545 keep_ahead(int color) 372 void 373 set_level(int new_level) 546 374 { 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; 569 381 } 570 382 571 572 /*573 * Modify the level during a game to avoid losing by time.574 */575 383 void 576 clock_adapt_level(int *p_level, int color)384 set_max_level(int new_max) 577 385 { 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; 627 387 } 628 388 389 void 390 set_min_level(int new_min) 391 { 392 min_level = new_min; 393 } 629 394 630 395 631 396 /* -
engine/clock.h
RCS file: /cvsroot/gnugo/gnugo/engine/clock.h,v retrieving revision 1.11 diff -u -p -r1.11 clock.h
23 23 #ifndef _CLOCK_H_ 24 24 #define _CLOCK_H_ 25 25 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_H43 #include <config.h>44 #endif45 26 #include "gnugo.h" 46 27 47 #ifdef HAVE_VISUAL_C48 #include <winsock.h>49 #include <io.h>50 #include <time.h>51 #else52 #include <sys/time.h>53 #endif54 55 #ifdef __MINGW32__56 #include <windows.h>57 #include <winsock.h>58 #include <io.h>59 #endif60 61 /* interface */62 63 28 /* initialization and activation */ 64 void clock_ init(int time, int byo_time, int byo_stones);65 void clock_enable(void);29 void clock_settings(int time, int byo_time, int byo_stones); 30 void init_timers(void); 66 31 67 void clock_enable_autolevel(void);68 69 32 /* main access */ 70 33 void 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); 34 void update_time_left(int color, int time_left, int stones); 35 void clock_print(int color); 36 int get_clock_settings(int *t, int *byo_t, int *byo_s); 80 37 81 /* adaptative system */ 82 void clock_adapt_level(int *p_level, int color); 38 void adjust_level_offset(int color); 83 39 84 /* output */ 85 void clock_print(int color); 86 void clock_report_autolevel(FILE *f, int color); 40 /* Access to level settings. */ 41 int get_level(void); 42 void set_level(int new_level); 43 void set_max_level(int new_max); 44 void set_min_level(int new_min); 87 45 88 46 89 47 #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) 354 354 int dcode = DRAGON2(str).owl_defense_code; 355 355 int defense_point, second_defense_point; 356 356 357 if ( level>= 8357 if (get_level() >= 8 358 358 && !disable_threat_computation 359 359 && (owl_threats 360 360 || 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() 91 91 clear_break_in_list(); 92 92 93 93 /* Set up depth values (see comments there for details). */ 94 set_depth_values( level, 0);94 set_depth_values(get_level(), 0); 95 95 } 96 96 97 97 /* … … do_genmove(int color, float pure_threat_ 318 318 move = PASS_MOVE; 319 319 *value = 0.0; 320 320 321 /* experimental level adapter */322 clock_adapt_level(&level, color);323 324 321 /* Prepare pattern matcher and reading code. */ 325 322 reset_engine(); 326 323 -
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 92 92 int josekidb = 1; /* use joseki database */ 93 93 int showtime = 0; /* print time to find move */ 94 94 int 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);98 95 int debug = 0; /* controls debug output */ 99 96 int verbose = 0; /* trace level */ 100 97 char outfilename[128] = ""; /* output file (-o option) */ … … int output_flags = OUTPUT_DEFAULT; 102 99 int limit_search = 0; /* limit search to a portion of the board */ 103 100 int metamachine = 0; /* use metamachine_genmove */ 104 101 int oracle_exists = 0; /* oracle is available for consultation */ 102 int autolevel_on = 0; /* Adjust leven in GMP or ASCII mode. */ 105 103 106 104 int disable_threat_computation = 0; 107 105 int 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 176 176 #define DEBUG_ORACLE_STREAM 0x1000000 177 177 #define DEBUG_LARGE_SCALE 0x1000000 178 178 #define DEBUG_SPLIT_OWL 0x2000000 179 #define DEBUG_TIME 0x4000000 179 180 180 181 181 182 #define DEBUG_FLAGS "\ … … DEBUG_MISCELLANEOUS 0x800000\n\ 206 207 DEBUG_ORACLE_STREAM 0x1000000\n\ 207 208 DEBUG_LARGE_SCALE 0x1000000\n\ 208 209 DEBUG_SPLIT_OWL 0x2000000\n\ 210 DEBUG_TIME 0x4000000\n\ 209 211 " 210 212 211 213 … … extern int hashflags; /* hash flags */ 242 244 extern int fusekidb; /* use fuseki database */ 243 245 extern int disable_fuseki; /* do not generate fuseki moves */ 244 246 extern int josekidb; /* use joseki database */ 245 extern int level; /* controls depth of reading */246 247 extern int semeai_variations; /* max variations considered reading semeai */ 247 248 extern int showtime; /* print genmove time */ 248 249 extern int showscore; /* print score */ … … extern int mandated_owl_branch_depth; 274 275 extern int mandated_owl_reading_depth; 275 276 extern int mandated_owl_node_limit; 276 277 extern int mandated_semeai_node_limit; 278 279 extern int autolevel_on; 277 280 278 281 extern float potential_moves[BOARDMAX]; 279 282 -
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) 67 67 { 68 68 board_size = boardsize; 69 69 clear_board(); 70 init_timers(); 70 71 #if 0 71 72 if (metamachine && oracle_exists) 72 73 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; 731 731 extern int connection_node_limit; 732 732 extern int breakin_depth; 733 733 extern 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 */737 734 extern int semeai_variations; /* max variations considered reading semeai */ 738 735 extern float best_move_values[10]; 739 736 extern 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 919 919 include_semeai_worms_in_eyespace = 0; 920 920 } 921 921 922 if ( level< 8) {922 if (get_level() < 8) { 923 923 /* If no owl moves were found on two consecutive moves, 924 924 * turn off the owl phase. 925 925 */ … … owl_estimate_life(struct local_owl_data 2853 2853 matches_found = 0; 2854 2854 memset(found_matches, 0, sizeof(found_matches)); 2855 2855 2856 if ( level>= 8) {2856 if (get_level() >= 8) { 2857 2857 memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache)); 2858 2858 if (!does_attack) { 2859 2859 clear_owl_move_data(dummy_moves); … … owl_substantial(int str) 5958 5958 /* fill all the liberties */ 5959 5959 for (k = 0; k < liberties; k++) { 5960 5960 if (trymove(libs[k], owl->color, NULL, 0)) { 5961 if ( level>= 8)5961 if (get_level() >= 8) 5962 5962 increase_depth_values(); 5963 5963 owl->goal[libs[k]] = 1; 5964 5964 } … … owl_substantial(int str) 5966 5966 /* if we can't fill, try swapping with the next liberty */ 5967 5967 if (k < liberties-1 5968 5968 && trymove(libs[k+1], owl->color, NULL, 0)) { 5969 if ( level>= 8)5969 if (get_level() >= 8) 5970 5970 increase_depth_values(); 5971 5971 owl->goal[libs[k+1]] = 1; 5972 5972 libs[k+1] = libs[k]; … … owl_substantial(int str) 5974 5974 else { 5975 5975 /* Can't fill the liberties. Give up! */ 5976 5976 while (stackp > 0) { 5977 if ( level>= 8)5977 if (get_level() >= 8) 5978 5978 decrease_depth_values(); 5979 5979 popgo(); 5980 5980 } … … owl_substantial(int str) 5995 5995 else 5996 5996 result = 1; 5997 5997 while (stackp > 0) { 5998 if ( level>= 8)5998 if (get_level() >= 8) 5999 5999 decrease_depth_values(); 6000 6000 popgo(); 6001 6001 } -
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) 1757 1757 bamboo_rescue_moves(str, liberties, libs, &moves); 1758 1758 } 1759 1759 1760 if ( level>= 8 && stackp <= backfill2_depth)1760 if (get_level() >= 8 && stackp <= backfill2_depth) 1761 1761 superstring_break_chain_moves(str, 4, &moves); 1762 1762 1763 1763 if (stackp <= break_chain_depth) … … defend3(int str, int *move) 1775 1775 /* If nothing else works, we try playing a liberty of the 1776 1776 * super_string. 1777 1777 */ 1778 if ( level>= 8 && stackp <= backfill2_depth) {1778 if (get_level() >= 8 && stackp <= backfill2_depth) { 1779 1779 superstring_moves(str, &moves, 3, 0); 1780 1780 squeeze_moves(str, &moves); 1781 1781 } … … attack2(int str, int *move) 3217 3217 /* If it is not possible to make a direct atari, we try filling 3218 3218 * a liberty of the superstring. 3219 3219 */ 3220 if ( level>= 83220 if (get_level() >= 8 3221 3221 && stackp <= backfill_depth 3222 3222 && (stackp <= superstring_depth || !atari_possible)) { 3223 3223 int liberty_cap = 2; … … attack3(int str, int *move) 3365 3365 /* If nothing else works, we try filling a liberty of the 3366 3366 * super_string. 3367 3367 */ 3368 if ( level>= 8 && stackp <= backfill2_depth) {3368 if (get_level() >= 8 && stackp <= backfill2_depth) { 3369 3369 superstring_moves(str, &moves, 3, 1); 3370 3370 squeeze_moves(str, &moves); 3371 3371 } -
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 165 165 sgftree_clear(&sgftree); 166 166 sgftreeCreateHeaderNode(&sgftree, board_size, relative_komi); 167 167 sgf_write_header(sgftree.root, 1, get_random_seed(), relative_komi, 168 level, chinese_rules);168 get_level(), chinese_rules); 169 169 gg_snprintf(str, 128, "GNU Go %s load and print", gg_version()); 170 170 sgfOverwriteProperty(sgftree.root, "GN", str); 171 171 -
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 3757 3757 find_more_attack_and_defense_moves(color); 3758 3758 time_report(2, " find_more_attack_and_defense_moves", NO_MOVE, 1.0); 3759 3759 3760 if ( level>= 6) {3760 if (get_level() >= 6) { 3761 3761 find_more_owl_attack_and_defense_moves(color); 3762 3762 time_report(2, " find_more_owl_attack_and_defense_moves", NO_MOVE, 1.0); 3763 3763 } 3764 3764 3765 if (large_scale && level>= 6) {3765 if (large_scale && get_level() >= 6) { 3766 3766 find_large_scale_owl_attack_moves(color); 3767 3767 time_report(2, " find_large_scale_owl_attack_moves", NO_MOVE, 1.0); 3768 3768 } -
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[]) 337 337 int seed = 0; 338 338 int seed_specified = 0; 339 339 340 /* Default parameters for clock and auto level systems. */341 clock_init(3600, 0, 0); /* One hour sudden death. */342 343 340 sgftree_clear(&sgftree); 344 341 gameinfo_clear(&gameinfo, board_size, komi); 345 342 … … main(int argc, char *argv[]) 780 777 break; 781 778 782 779 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)); 788 781 break; 789 782 790 783 case OPT_MIN_LEVEL: 791 min_level = atoi(gg_optarg);784 set_min_level(atoi(gg_optarg)); 792 785 break; 793 786 794 787 case OPT_MAX_LEVEL: 795 max_level = atoi(gg_optarg);788 set_max_level(atoi(gg_optarg)); 796 789 break; 797 790 798 791 case OPT_LIMIT_SEARCH: … … main(int argc, char *argv[]) 807 800 break; 808 801 809 802 case OPT_CLOCK_TIME: 810 811 clock_init(atoi(gg_optarg), -1, -1); 812 clock_enable(); 803 clock_settings(atoi(gg_optarg), -1, -1); 813 804 break; 814 805 815 806 case OPT_CLOCK_BYO_TIME: 816 clock_init(-1, atoi(gg_optarg), -1); 817 clock_enable(); 807 clock_settings(-1, atoi(gg_optarg), -1); 818 808 break; 819 809 820 810 case OPT_CLOCK_BYO_PERIOD: 821 clock_init(-1, -1, atoi(gg_optarg)); 822 clock_enable(); 811 clock_settings(-1, -1, atoi(gg_optarg)); 823 812 break; 824 813 825 814 case OPT_AUTOLEVEL: 826 clock_init(-1, -1, -1); 827 clock_enable(); 828 clock_enable_autolevel(); 815 autolevel_on = 1; 829 816 break; 830 817 831 818 case OPT_DEBUG_INFLUENCE: … … main(int argc, char *argv[]) 1372 1359 if (profile_patterns) 1373 1360 report_pattern_profiling(); 1374 1361 1375 clock_report_autolevel(NULL, gameinfo.computer_player);1376 1362 sgfFreeNode(sgftree.root); 1377 1363 1378 1364 return 0; … … Options providing detailed reading resul 1556 1542 static void 1557 1543 show_help(void) 1558 1544 { 1559 set_depth_values(DEFAULT_LEVEL, 0); 1560 printf(USAGE, level); 1545 printf(USAGE, DEFAULT_LEVEL); 1561 1546 printf(USAGE1, (float) DEFAULT_MEMORY); 1562 1547 printf(USAGE2, MIN_BOARD, MAX_BOARD, MAX_HANDICAP); 1563 1548 } -
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; 54 54 static SGFTree sgftree; 55 55 static int resignation_allowed; 56 56 57 static int clock_on = 0; 58 57 59 /* Unreasonable score used to detect missing information. */ 58 60 #define NO_SCORE 4711 59 61 /* Keep track of the score estimated before the last computer move. */ … … ascii_showboard(void) 296 298 fflush(stdout); 297 299 printf("%s\n\n", letterbar); 298 300 fflush(stdout); 301 302 if (clock_on) { 303 clock_print(WHITE); 304 clock_print(BLACK); 305 } 299 306 300 307 } /* end ascii_showboard */ 301 308 … … init_sgf(Gameinfo *ginfo) 440 447 sgf_initialized = 1; 441 448 442 449 sgf_write_header(sgftree.root, 1, get_random_seed(), komi, 443 level, chinese_rules);450 get_level(), chinese_rules); 444 451 sgfOverwritePropertyInt(sgftree.root, "HA", ginfo->handicap); 445 452 if (ginfo->handicap > 0) 446 453 sgffile_recordboard(sgftree.root); … … computer_move(Gameinfo *gameinfo, int *p 463 470 init_sgf(gameinfo); 464 471 465 472 /* Generate computer move. */ 473 if (autolevel_on) 474 adjust_level_offset(gameinfo->to_move); 466 475 move_value = gnugo_genmove(&i, &j, gameinfo->to_move, &resign); 467 476 if (resignation_allowed && resign) { 468 477 int state = ascii_endgame(gameinfo, 2); … … do_play_ascii(Gameinfo *gameinfo) 618 627 char *tmpstring; 619 628 int state = 1; 620 629 630 if (get_clock_settings(NULL, NULL, NULL)) 631 clock_on = 1; 632 621 633 while (state == 1) { 622 634 state = 0; 623 635 … … do_play_ascii(Gameinfo *gameinfo) 775 787 printf("\nInvalid command syntax!\n"); 776 788 break; 777 789 } 778 level = num;779 printf("\nSet level to %d\n", level);790 set_level(num); 791 printf("\nSet level to %d\n", num); 780 792 break; 781 793 782 794 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 133 133 134 134 gameinfo->computer_player = mycolor; 135 135 sgf_write_header(sgftree.root, 1, get_random_seed(), komi, 136 level, chinese_rules);136 get_level(), chinese_rules); 137 137 gameinfo->handicap = gnugo_sethand(gameinfo->handicap, sgftree.root); 138 138 sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap); 139 139 … … play_gmp(Gameinfo *gameinfo, int simplif 186 186 } 187 187 else { 188 188 /* 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); 190 193 gnugo_play_move(i, j, mycolor); 191 194 sgffile_add_debuginfo(sgftree.lastnode, move_value); 192 195 -
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
35 35 36 36 /* Internal state that's not part of the engine. */ 37 37 static int handicap = 0; 38 static int main_time = 0;39 static int byo_yomi_time = 1;40 static int byo_yomi_stones = 0;41 38 42 39 static int report_uncertainty = 0; 43 40 static int gtp_orientation = 0; 44 41 45 /* Time handling. Index 0 is the most recent report, index 1 the46 * 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);60 42 static void gtp_print_code(int c); 61 43 static void gtp_print_vertices2(int n, int *moves); 62 44 static void rotate_on_input(int ai, int aj, int *bi, int *bj); … … play_gtp(FILE *gtp_input, FILE *gtp_outp 359 341 gtp_set_vertex_transform_hooks(rotate_on_input, rotate_on_output); 360 342 361 343 /* Initialize time handling. */ 362 gtp_init_time_handling();344 init_timers(); 363 345 364 346 /* Prepare pattern matcher and reading code. */ 365 347 reset_engine(); … … gtp_clear_board(char *s) 516 498 update_random_seed(); 517 499 518 500 clear_board(); 519 gtp_init_time_handling();501 init_timers(); 520 502 521 503 return gtp_success(""); 522 504 } … … gtp_playblack(char *s) 627 609 if (!is_legal(POS(i, j), BLACK)) 628 610 return gtp_failure("illegal move"); 629 611 630 play_move(POS(i, j), BLACK);612 gnugo_play_move(i, j, BLACK); 631 613 return gtp_success(""); 632 614 } 633 615 … … gtp_playwhite(char *s) 658 640 if (!is_legal(POS(i, j), WHITE)) 659 641 return gtp_failure("illegal move"); 660 642 661 play_move(POS(i, j), WHITE);643 gnugo_play_move(i, j, WHITE); 662 644 return gtp_success(""); 663 645 } 664 646 … … gtp_play(char *s) 682 664 if (!is_legal(POS(i, j), color)) 683 665 return gtp_failure("illegal move"); 684 666 685 play_move(POS(i, j), color);667 gnugo_play_move(i, j, color); 686 668 return gtp_success(""); 687 669 } 688 670 … … gtp_loadsgf(char *s) 871 853 handicap = gameinfo.handicap; 872 854 gtp_internal_set_boardsize(board_size); 873 855 reset_engine(); 874 gtp_init_time_handling();856 init_timers(); 875 857 876 858 sgfFreeNode(sgftree.root); 877 859 … … gtp_genmove_black(char *s) 2471 2453 2472 2454 move = genmove(BLACK, NULL, NULL); 2473 2455 2474 play_move(move, BLACK);2456 gnugo_play_move(I(move), J(move), BLACK); 2475 2457 2476 2458 gtp_start_response(GTP_SUCCESS); 2477 2459 gtp_print_vertex(I(move), J(move)); … … gtp_genmove_white(char *s) 2496 2478 2497 2479 move = genmove(WHITE, NULL, NULL); 2498 2480 2499 play_move(move, WHITE);2481 gnugo_play_move(I(move), J(move), WHITE); 2500 2482 2501 2483 gtp_start_response(GTP_SUCCESS); 2502 2484 gtp_print_vertex(I(move), J(move)); … … gtp_genmove(char *s) 2526 2508 return gtp_failure("genmove cannot be called when stackp > 0"); 2527 2509 2528 2510 adjust_level_offset(color); 2529 level += level_offset;2530 2511 move = genmove(color, NULL, &resign); 2531 level -= level_offset;2532 2512 2533 2513 if (resign) 2534 2514 return gtp_success("resign"); 2535 2515 2536 play_move(move, color);2516 gnugo_play_move(I(move), J(move), color); 2537 2517 2538 2518 gtp_start_response(GTP_SUCCESS); 2539 2519 gtp_print_vertex(I(move), J(move)); … … gtp_kgs_genmove_cleanup(char *s) 2708 2688 capture_all_dead = 1; 2709 2689 2710 2690 adjust_level_offset(color); 2711 level += level_offset;2712 2691 move = genmove(color, NULL, NULL); 2713 level -= level_offset;2714 2692 2715 2693 capture_all_dead = save_capture_all_dead; 2716 2694 2717 play_move(move, color);2695 gnugo_play_move(I(move), J(move), color); 2718 2696 2719 2697 gtp_start_response(GTP_SUCCESS); 2720 2698 gtp_print_vertex(I(move), J(move)); … … gtp_set_level(char *s) 2845 2823 if (sscanf(s, "%d", &new_level) < 1) 2846 2824 return gtp_failure("level not an integer"); 2847 2825 2848 level = new_level; 2849 level_offset = 0; 2826 set_level(new_level); 2850 2827 return gtp_success(""); 2851 2828 } 2852 2829 … … gtp_gg_undo(char *s) 2901 2878 * time handling * 2902 2879 *****************/ 2903 2880 2904 /* Initialize time data variables and set the level offset to 0. */2905 static void2906 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 time2919 * spent on the last moves, the (effective) number of stones left and2920 * the (effective) remaining time.2921 */2922 static void2923 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 more2946 * moves or a total of Y moves. We choose Y as a third of the2947 * number of vertices and X as 40% of Y. For 19x19 this means2948 * that we aim to play at least a total of 120 moves2949 * (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_time2959 - 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 else2963 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 speed2971 * and remaining time and stones.2972 *2973 * FIXME: Integrate this code with the one in clock.c. Or maybe rather2974 * replace them both with something better.2975 */2976 static void2977 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 else2987 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 3029 2881 /* Function: Set time allowance 3030 2882 * Arguments: int main_time, int byo_yomi_time, int byo_yomi_stones 3031 2883 * Fails: syntax error … … adjust_level_offset(int color) 3037 2889 static int 3038 2890 gtp_time_settings(char *s) 3039 2891 { 3040 int a, b, c;2892 int main_time, byoyomi_time, byoyomi_stones; 3041 2893 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) 3043 2895 return gtp_failure("not three integers"); 3044 2896 3045 main_time = a; 3046 byo_yomi_time = b; 3047 byo_yomi_stones = c; 3048 2897 clock_settings(main_time, byoyomi_time, byoyomi_stones); 3049 2898 return gtp_success(""); 3050 2899 } 3051 2900 … … gtp_time_left(char *s) 3073 2922 if (sscanf(s+n, "%d %d", &time, &stones) < 2) 3074 2923 return gtp_failure("time and stones not two integers"); 3075 2924 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); 3088 2926 3089 2927 return gtp_success(""); 3090 2928 } … … finish_and_score_game(int seed) 3149 2987 3150 2988 do { 3151 2989 move = genmove_conservative(next, NULL); 3152 play_move(move, next);2990 gnugo_play_move(I(move), J(move), next); 3153 2991 if (move != PASS_MOVE) { 3154 2992 pass = 0; 3155 2993 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) 61 61 sgftree_clear(&sgftree); 62 62 sgftreeCreateHeaderNode(&sgftree, board_size, komi); 63 63 sgf_write_header(sgftree.root, 1, get_random_seed(), 5.5, 64 level, chinese_rules);64 get_level(), chinese_rules); 65 65 66 66 /* Generate some random moves. */ 67 67 if (board_size > 6) {
