Ticket #33: arend_7_8.1-clock.diff
| File arend_7_8.1-clock.diff, 49.2 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 double main_time = -1.0; 55 static double byoyomi_time = -1.0; 56 static int byoyomi_stones = -1; /* zero 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 93 94 /* Print the clock status for one side. */ 95 static void 96 clock_print(int color) 97 { 98 struct timer_data* const td 99 = (color == BLACK) ? &black_time_data : &white_time_data; 100 101 fprintf(stderr, "clock: "); 102 fprintf(stderr, "%s ", color_to_string(color)); 103 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); 114 115 } 116 fprintf(stderr, "\n"); 117 } 118 119 123 120 /******************************/ 124 121 /* Initialization functions */ 125 122 /******************************/ 126 123 127 128 124 /* 129 * Initialize the structure.125 * Initialize the time settings for this game. 130 126 * -1 means "do not modify this value". 131 * clock_init(-1, -1, -1) only resets the clock.132 127 */ 133 128 void 134 clock_ init(int time, int byo_time, int byo_stones)129 clock_settings(int time, int byo_time, int byo_stones) 135 130 { 136 int color; 137 138 if (time > 0) { 139 clk.main_time = time; 140 clk.ready = 1; 141 } 142 131 if (time > 0) 132 main_time = time; 143 133 if (byo_time >= 0) 144 clk.byoyomi_time = byo_time; 145 134 byoyomi_time = byo_time; 146 135 if (byo_stones >= 0) 147 clk.byoyomi_stones = byo_stones; 148 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 } 136 byoyomi_stones = byo_stones; 137 init_timers(); 156 138 } 157 139 158 140 159 /* 160 * Activate the clock. 161 */ 162 void 163 clock_enable(void) 141 /* Initialize all timers. */ 142 void 143 init_timers() 164 144 { 165 gg_assert(clk.ready); 166 clk.clock_on = 1; 167 } 145 white_time_data.official.time_left = main_time; 146 white_time_data.official.time_for_last_move = -1.0; 147 white_time_data.official.stones = 0; 148 white_time_data.official.movenum = 0; 149 white_time_data.official.in_byoyomi = 0; 150 white_time_data.estimated = white_time_data.official; 151 black_time_data = white_time_data; 168 152 169 /* 170 * Activate Autolevel. 171 */ 172 void 173 clock_enable_autolevel(void) 174 { 175 gg_assert(clk.clock_on); 176 clk.autolevel_on = 1; 153 level_offset = 0; 177 154 } 178 155 179 156 180 /*********************** /181 /* Access functions. */182 /*********************** /157 /*****************************/ 158 /* Clock access functions. */ 159 /*****************************/ 183 160 184 161 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) 162 void 163 update_time_left(int color, int time_left, int stones) 191 164 { 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 } 165 struct timer_data* const td 166 = ((color == BLACK) ? &black_time_data : &white_time_data); 167 int time_used = td->official.time_left - time_left; 168 169 /* Did our estimate for time usage go wrong? */ 170 if (time_used > 0 171 && gg_abs(time_used - td->estimated.time_for_last_move) >= 1.0) 172 td->estimated.time_for_last_move = time_used; 173 td->estimated.stones = stones; 174 td->estimated.movenum = movenum; 175 /* Did our clock go wrong? */ 176 if (gg_abs(td->estimated.time_left - time_left) >= 1.0) 177 td->estimated.time_left = time_left; 178 if (stones > 0) 179 td->estimated.in_byoyomi = 1; 180 181 td->official.stones = stones; 182 td->official.movenum = movenum; 183 td->official.time_for_last_move = td->official.time_for_last_move - time_left; 184 td->official.time_left = time_left; 185 td->official.in_byoyomi = td->estimated.in_byoyomi; 214 186 } 215 187 216 217 188 /* 218 * Update the clock.189 * Update the estimated timer after a move has been made. 219 190 */ 220 191 void 221 192 clock_push_button(int color) 222 193 { 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++; 194 static double last_time = -1.0; 195 static int last_movenum = -1; 196 struct timer_data* const td 197 = (color == BLACK) ? &black_time_data : &white_time_data; 198 double now = gg_gettimeofday(); 199 200 if (last_movenum >= 0 201 && movenum == last_movenum + 1 202 && movenum > td->estimated.movenum) { 203 double time_used = now - last_time; 204 td->estimated.time_left -= time_used; 205 td->estimated.movenum = movenum; 206 td->estimated.time_for_last_move = time_used; 207 if (td->estimated.time_left < 0) { 208 if (td->estimated.in_byoyomi || byoyomi_stones == 0) { 209 gprintf("%s ran out of time.\n", color_to_string(color)); 210 clock_print(color); 211 td->time_out = 1; 212 } 213 else { 214 /* Entering byoyomi. */ 215 gg_assert(!(td->estimated.in_byoyomi)); 216 td->estimated.in_byoyomi = 1; 217 td->estimated.stones = byoyomi_stones - 1; 218 td->estimated.time_left += byoyomi_time; 219 if (td->estimated.time_left < 0) 220 td->time_out = 1; 221 } 222 } 223 else if (td->estimated.stones > 0) { 224 gg_assert(td->estimated.in_byoyomi); 225 td->estimated.stones = td->estimated.stones - 1; 226 if (td->estimated.stones == 0) { 227 td->estimated.time_left = byoyomi_time; 228 td->estimated.stones = byoyomi_stones; 229 } 243 230 } 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 231 } 255 232 256 /* Other moves (clk. moveno > -1) */ 257 clk.moveno++; 258 gg_assert(clk.moveno < CLOCK_MAX_MOVES); 259 clk.date[clk.moveno] = now; 233 last_movenum = movenum; 234 last_time = now; 260 235 261 236 /* 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 else269 clk.error = 3.0;270 271 clock_byoyomi_update(color, dt);272 237 clock_print(color); 273 238 } 274 239 275 240 276 /* 277 * Unplay a move. 278 */ 279 void 280 clock_unpush_button(int color) 281 { 282 double dt; 241 /**********************/ 242 /* Autolevel system */ 243 /**********************/ 283 244 284 if (!clk.clock_on)285 return;286 287 gg_assert(clk.ready);288 gg_assert(color == COLOR(clk.moveno));289 245 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; 246 /* Analyze the two most recent time reports and determine the time 247 * spent on the last moves, the (effective) number of stones left and 248 * the (effective) remaining time. 249 */ 250 static int 251 analyze_time_data(int color, double *time_for_last_move, double *time_left, 252 int *stones_left) 253 { 254 struct remaining_time_data * const timer 255 = (color == BLACK) ? &black_time_data.estimated 256 : &white_time_data.estimated; 257 258 /* Do we have any time limits. */ 259 if (byoyomi_stones == 0 && byoyomi_time > 0) { 260 gprintf("No time limits.\n"); 261 return 0; 304 262 } 305 306 /* Update byoyomi timer. */307 if (clk.byoyomi[color])308 clk.btimer[color] -= dt;309 310 clock_print(color);311 }312 313 314 /*315 * return the (exact) main timer value.316 */317 double318 clock_get_timer(int color)319 {320 double dt;321 263 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]; 330 } 331 332 333 /* 334 * Give the time left or negative if in byoyomi. 335 */ 336 double 337 clock_get_time_left(int color) 338 { 339 return clk.main_time - clock_get_timer(color); 340 } 341 342 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; 350 } 351 352 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 } 370 371 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) 377 { 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); 382 } 383 384 385 /* 386 * Check if a player is time over. 387 */ 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 395 void 396 clock_print(int color) 397 { 398 double tleft; 399 int stones; 400 401 if (!clk.clock_on) 402 return; 403 404 gg_assert(clk.ready); 264 /* If we don't have consistent time information yet, just return. */ 265 if (timer->time_for_last_move < 0.0) 266 return 0; 405 267 406 fprintf(stderr, "clock: "); 407 fprintf(stderr, "%s ", pname[color]); 268 *time_for_last_move = timer->time_for_last_move; 408 269 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); 270 if (timer->stones == 0) { 271 /* Main time running. */ 272 *time_left = timer->time_left + byoyomi_time; 273 if (byoyomi_time > 0) 274 *stones_left = byoyomi_stones; 275 else { 276 /* Absolute time. Here we aim to be able to play at least X more 277 * moves or a total of Y moves. We choose Y as a third of the 278 * number of vertices and X as 40% of Y. For 19x19 this means 279 * that we aim to play at least a total of 120 moves 280 * (corresponding to a 240 move game) or another 24 moves. 281 * 282 * FIXME: Maybe we should use the game_status of 283 * influence_evaluate_position() here to guess how many moves 284 * are remaining. 285 */ 286 int nominal_moves = board_size * board_size / 3; 287 *stones_left = gg_max(nominal_moves - movenum / 2, 288 2 * nominal_moves / 5); 421 289 } 422 else423 timeval_print(stderr, tleft);424 425 290 } 426 fprintf(stderr, "\n"); 291 else { 292 *time_left = timer->time_left; 293 *stones_left = timer->stones; 294 } 295 return 1; 427 296 } 428 297 429 298 430 431 /**********************/ 432 /* Autolevel system */ 433 /**********************/ 434 435 436 437 /* Write the time/move to outfile */ 438 void 439 clock_report_autolevel(FILE *outfile, int color) 299 /* Adjust the level offset given information of current playing speed 300 * and remaining time and stones. 301 */ 302 void 303 adjust_level_offset(int color) 440 304 { 441 int i, first; 442 double dt, est, exp; 443 444 if (!clk.autolevel_on) 445 return; 305 double time_for_last_move; 306 double time_left; 307 int stones_left; 446 308 447 if (outfile == NULL) 448 outfile = fopen("autolevel.dat", "w"); 449 if (outfile == NULL) 309 if (!analyze_time_data(color, &time_for_last_move, &time_left, &stones_left)) 450 310 return; 451 311 452 fprintf(outfile, "#\n# level prediction expected time/move\n");453 fprintf(outfile, "#-----------------------------------------\n");454 312 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); 313 /* These rules are both crude and ad hoc. 314 * 315 * FIXME: Use rules with at least some theoretical basis. 316 */ 317 if (time_left < time_for_last_move * (stones_left + 3)) 318 level_offset--; 319 if (time_left < time_for_last_move * stones_left) 320 level_offset--; 321 if (3 * time_left < 2 * time_for_last_move * stones_left) 322 level_offset--; 323 if (2 * time_left < time_for_last_move * stones_left) 324 level_offset--; 325 if (3 * time_left < time_for_last_move * stones_left) 326 level_offset--; 327 328 if (time_for_last_move == 0) 329 time_for_last_move = 1; 330 if (time_left > time_for_last_move * (stones_left + 6)) 331 level_offset++; 332 if (time_left > 2 * time_for_last_move * (stones_left + 6)) 333 level_offset++; 334 335 if (level + level_offset < min_level) 336 level_offset = min_level - level; 337 338 if (level + level_offset > max_level) 339 level_offset = max_level - level; 340 341 if (1) { 342 /*if (level_offset != 0) { */ 343 gprintf("New level %d (%d %C %f %f %d)\n", level + level_offset, 344 movenum / 2, color, time_for_last_move, time_left, stones_left); 345 /*}*/ 466 346 } 467 347 } 468 348 469 349 470 /* 471 * Give an estimation of the time/move 472 * based on the last played move. 473 */ 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 }; 350 /********************************/ 351 /* Interface to level settings. */ 352 /********************************/ 480 353 481 static double 482 estimate_time_by_move(int color, int move)354 int 355 get_level() 483 356 { 484 double res; 485 int i; 486 487 if (move <= 10) 488 return 0; 489 490 gg_assert(COLOR(move) == OTHER_COLOR(color)); 491 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; 357 return level + level_offset; 497 358 } 498 359 499 500 /* 501 * Try to respect a "time contract". 502 */ 503 static void 504 respect_time_contract(int color) 360 void 361 set_level(int new_level) 505 362 { 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); 512 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; 363 level = new_level; 364 level_offset = 0; 365 if (level > max_level) 366 max_level = level; 367 if (level < min_level) 368 min_level = level; 538 369 } 539 370 540 541 /* 542 * Try to keep gnugo ahead on the clock. 543 */ 544 static void 545 keep_ahead(int color) 371 void 372 set_max_level(int new_max) 546 373 { 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 } 374 max_level = new_max; 569 375 } 570 376 571 572 /*573 * Modify the level during a game to avoid losing by time.574 */575 377 void 576 clock_adapt_level(int *p_level, int color)378 set_min_level(int new_min) 577 379 { 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); 380 min_level = new_min; 627 381 } 628 629 382 630 383 631 384 /* -
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 26 #include <stdio.h> 42 27 #ifdef HAVE_CONFIG_H 43 28 #include <config.h> 44 29 #endif 45 #include "gnugo.h"46 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 30 61 /* interface */62 63 31 /* initialization and activation */ 64 void clock_ init(int time, int byo_time, int byo_stones);65 void clock_enable(void);32 void clock_settings(int time, int byo_time, int byo_stones); 33 void init_timers(void); 66 34 67 void clock_enable_autolevel(void);68 69 35 /* main access */ 70 36 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); 37 void update_time_left(int color, int time_left, int stones); 80 38 81 /* adaptative system */ 82 void clock_adapt_level(int *p_level, int color); 39 void adjust_level_offset(int color); 83 40 84 /* output */ 85 void clock_print(int color); 86 void clock_report_autolevel(FILE *f, int color); 41 /* Access to level settings. */ 42 int get_level(void); 43 void set_level(int new_level); 44 void set_max_level(int new_max); 45 void set_min_level(int new_min); 87 46 88 47 89 48 #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.75 diff -u -p -r1.75 globals.c
int disable_fuseki = 0; /* do not ge 91 91 int josekidb = 1; /* use joseki database */ 92 92 int showtime = 0; /* print time to find move */ 93 93 int showscore = 0; /* print estimated score */ 94 int level = DEFAULT_LEVEL; /* strength; up to 10 supported */95 int min_level = 0;96 int max_level = gg_max(DEFAULT_LEVEL, 10);97 94 int debug = 0; /* controls debug output */ 98 95 int verbose = 0; /* trace level */ 99 96 char outfilename[128] = ""; /* output file (-o option) */ … … int output_flags = OUTPUT_DEFAULT; 101 98 int limit_search = 0; /* limit search to a portion of the board */ 102 99 int metamachine = 0; /* use metamachine_genmove */ 103 100 int oracle_exists = 0; /* oracle is available for consultation */ 101 int autolevel_on = 0; /* Adjust leven in GMP or ASCII mode. */ 104 102 105 103 int disable_threat_computation = 0; 106 104 int disable_endgame_patterns = 0; -
engine/gnugo.h
RCS file: /cvsroot/gnugo/gnugo/engine/gnugo.h,v retrieving revision 1.122 diff -u -p -r1.122 gnugo.h
extern int hashflags; /* hash flags */ 207 207 extern int fusekidb; /* use fuseki database */ 208 208 extern int disable_fuseki; /* do not generate fuseki moves */ 209 209 extern int josekidb; /* use joseki database */ 210 extern int level; /* controls depth of reading */211 210 extern int semeai_variations; /* max variations considered reading semeai */ 212 211 extern int showtime; /* print genmove time */ 213 212 extern int showscore; /* print score */ … … extern int mandated_owl_distrust_depth; 238 237 extern int mandated_owl_branch_depth; 239 238 extern int mandated_owl_reading_depth; 240 239 extern int mandated_owl_node_limit; 240 241 extern int autolevel_on; 241 242 242 243 extern float potential_moves[BOARDMAX]; 243 244 -
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.119 diff -u -p -r1.119 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[]) 808 801 809 802 case OPT_CLOCK_TIME: 810 803 811 clock_ init(atoi(gg_optarg), -1, -1);812 clock_enable();804 clock_settings(atoi(gg_optarg), -1, -1); 805 init_timers(); 813 806 break; 814 807 815 808 case OPT_CLOCK_BYO_TIME: 816 clock_init(-1, atoi(gg_optarg), -1); 817 clock_enable(); 809 clock_settings(-1, atoi(gg_optarg), -1); 818 810 break; 819 811 820 812 case OPT_CLOCK_BYO_PERIOD: 821 clock_ init(-1, -1, atoi(gg_optarg));822 clock_enable();813 clock_settings(-1, -1, atoi(gg_optarg)); 814 init_timers(); 823 815 break; 824 816 825 817 case OPT_AUTOLEVEL: 826 clock_init(-1, -1, -1); 827 clock_enable(); 828 clock_enable_autolevel(); 818 init_timers(); 819 autolevel_on = 1; 829 820 break; 830 821 831 822 case OPT_DEBUG_INFLUENCE: … … main(int argc, char *argv[]) 1372 1363 if (profile_patterns) 1373 1364 report_pattern_profiling(); 1374 1365 1375 clock_report_autolevel(NULL, gameinfo.computer_player);1376 1366 sgfFreeNode(sgftree.root); 1377 1367 1378 1368 return 0; … … DEBUG_LARGE_SCALE 0x1000000\n\ 1584 1574 static void 1585 1575 show_help(void) 1586 1576 { 1587 set_depth_values(DEFAULT_LEVEL, 0); 1588 printf(USAGE, level); 1577 printf(USAGE, DEFAULT_LEVEL); 1589 1578 printf(USAGE1, (float) DEFAULT_MEMORY); 1590 1579 printf(USAGE2, MIN_BOARD, MAX_BOARD, MAX_HANDICAP); 1591 1580 } -
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
init_sgf(Gameinfo *ginfo) 440 440 sgf_initialized = 1; 441 441 442 442 sgf_write_header(sgftree.root, 1, get_random_seed(), komi, 443 level, chinese_rules);443 get_level(), chinese_rules); 444 444 sgfOverwritePropertyInt(sgftree.root, "HA", ginfo->handicap); 445 445 if (ginfo->handicap > 0) 446 446 sgffile_recordboard(sgftree.root); … … computer_move(Gameinfo *gameinfo, int *p 463 463 init_sgf(gameinfo); 464 464 465 465 /* Generate computer move. */ 466 if (autolevel_on) 467 adjust_level_offset(gameinfo->to_move); 466 468 move_value = gnugo_genmove(&i, &j, gameinfo->to_move, &resign); 467 469 if (resignation_allowed && resign) { 468 470 int state = ascii_endgame(gameinfo, 2); … … do_play_ascii(Gameinfo *gameinfo) 775 777 printf("\nInvalid command syntax!\n"); 776 778 break; 777 779 } 778 level = num;779 printf("\nSet level to %d\n", level);780 set_level(num); 781 printf("\nSet level to %d\n", num); 780 782 break; 781 783 782 784 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 … … gtp_time_settings(char *s) 3042 2894 if (sscanf(s, "%d %d %d", &a, &b, &c) < 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(a, b, c); 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) { -
interface/gtp_examples/twogtp.pike
RCS file: /cvsroot/gnugo/gnugo/interface/gtp_examples/twogtp.pike,v retrieving revision 1.13 diff -u -p -r1.13 twogtp.pike
class GtpServer { 377 377 378 378 if (use_time_control) { 379 379 if (main_time >= 0.0) { 380 send_command(sprintf("time_left %s %d %d", color,381 (int) time_left, stones_left)); 380 /* send_command(sprintf("time_left %s %d %d", color, 381 (int) time_left, stones_left)); */ 382 382 } 383 383 384 384 #ifdef __AUTO_BIGNUM__
