RCS file: /sources/gnugo/gnugo/engine/genmove.c,v
retrieving revision 1.116
diff -u -r1.116 genmove.c
|
|
|
|
| 73 | 73 | void |
| 74 | 74 | reset_engine() |
| 75 | 75 | { |
| | 76 | static int last_level = -1; |
| | 77 | int act_level; |
| | 78 | |
| 76 | 79 | /* To improve the reproducability of games, we restart the random |
| 77 | 80 | * number generator with the same seed for each move. Thus we don't |
| 78 | 81 | * have to know how many previous moves have been played, nor |
| … |
… |
|
| 98 | 101 | clear_break_in_list(); |
| 99 | 102 | |
| 100 | 103 | /* Set up depth values (see comments there for details). */ |
| 101 | | set_depth_values(get_level(), 0); |
| | 104 | act_level = get_level(); |
| | 105 | if (last_level != act_level) |
| | 106 | { |
| | 107 | set_depth_values(act_level, 0); |
| | 108 | last_level = act_level; |
| | 109 | } |
| 102 | 110 | } |
| 103 | 111 | |
| 104 | 112 | /* |
| … |
… |
|
| 117 | 125 | void |
| 118 | 126 | examine_position(int how_much, int aftermath_play) |
| 119 | 127 | { |
| | 128 | #ifndef GG_TURN_OFF_TRACES |
| 120 | 129 | int save_verbose = verbose; |
| | 130 | #endif |
| 121 | 131 | |
| 122 | 132 | purge_persistent_caches(); |
| 123 | 133 | |
| | 134 | #ifndef GG_TURN_OFF_TRACES |
| 124 | 135 | /* Don't print reading traces during make_worms and make_dragons unless |
| 125 | 136 | * the user really wants it (verbose == 3). |
| 126 | 137 | */ |
| 127 | 138 | if (verbose == 1 || verbose == 2) |
| 128 | 139 | --verbose; |
| | 140 | #endif |
| 129 | 141 | |
| 130 | 142 | if (NEEDS_UPDATE(worms_examined)) { |
| | 143 | |
| | 144 | #ifndef GG_TURN_OFF_TRACES |
| 131 | 145 | start_timer(0); |
| | 146 | #endif |
| | 147 | |
| 132 | 148 | make_worms(); |
| | 149 | |
| | 150 | #ifndef GG_TURN_OFF_TRACES |
| 133 | 151 | time_report(0, " make worms", NO_MOVE, 1.0); |
| | 152 | #endif |
| 134 | 153 | } |
| 135 | 154 | |
| 136 | 155 | if (how_much == EXAMINE_WORMS) { |
| | 156 | |
| | 157 | #ifndef GG_TURN_OFF_TRACES |
| 137 | 158 | verbose = save_verbose; |
| | 159 | #endif |
| | 160 | |
| 138 | 161 | gg_assert(test_gray_border() < 0); |
| 139 | 162 | return; |
| 140 | 163 | } |
| … |
… |
|
| 142 | 165 | if (stones_on_board(BLACK | WHITE) != 0) { |
| 143 | 166 | if (NEEDS_UPDATE(initial_influence_examined)) |
| 144 | 167 | compute_worm_influence(); |
| | 168 | |
| 145 | 169 | if (how_much == EXAMINE_INITIAL_INFLUENCE) { |
| | 170 | |
| | 171 | #ifndef GG_TURN_OFF_TRACES |
| 146 | 172 | verbose = save_verbose; |
| | 173 | #endif |
| | 174 | |
| 147 | 175 | gg_assert(test_gray_border() < 0); |
| 148 | 176 | return; |
| 149 | 177 | } |
| … |
… |
|
| 151 | 179 | if (how_much == EXAMINE_DRAGONS_WITHOUT_OWL) { |
| 152 | 180 | if (NEEDS_UPDATE(dragons_examined_without_owl)) |
| 153 | 181 | make_dragons(1); |
| | 182 | |
| | 183 | #ifndef GG_TURN_OFF_TRACES |
| 154 | 184 | verbose = save_verbose; |
| | 185 | #endif |
| | 186 | |
| 155 | 187 | gg_assert(test_gray_border() < 0); |
| 156 | 188 | return; |
| 157 | 189 | } |
| … |
… |
|
| 163 | 195 | dragons_examined_without_owl = position_number; |
| 164 | 196 | } |
| 165 | 197 | if (how_much == EXAMINE_DRAGONS) { |
| | 198 | |
| | 199 | #ifndef GG_TURN_OFF_TRACES |
| 166 | 200 | verbose = save_verbose; |
| | 201 | #endif |
| | 202 | |
| 167 | 203 | gg_assert(test_gray_border() < 0); |
| 168 | 204 | return; |
| 169 | 205 | } |
| … |
… |
|
| 173 | 209 | || how_much == EXAMINE_ALL) { |
| 174 | 210 | initialize_dragon_data(); |
| 175 | 211 | compute_scores(chinese_rules || aftermath_play); |
| | 212 | |
| | 213 | #ifndef GG_TURN_OFF_TRACES |
| 176 | 214 | verbose = save_verbose; |
| | 215 | #endif |
| | 216 | |
| 177 | 217 | gg_assert(test_gray_border() < 0); |
| 178 | 218 | return; |
| 179 | 219 | } |
| 180 | 220 | |
| | 221 | #ifndef GG_TURN_OFF_TRACES |
| 181 | 222 | verbose = save_verbose; |
| | 223 | #endif |
| 182 | 224 | |
| 183 | 225 | if (NEEDS_UPDATE(initial_influence2_examined)) { |
| 184 | 226 | compute_dragon_influence(); |
| … |
… |
|
| 197 | 239 | return; |
| 198 | 240 | } |
| 199 | 241 | |
| | 242 | #ifndef GG_TURN_OFF_TRACES |
| 200 | 243 | if (printworms) |
| 201 | 244 | show_dragons(); |
| | 245 | #endif |
| 202 | 246 | } |
| 203 | 247 | |
| 204 | 248 | |
| … |
… |
|
| 283 | 327 | /* This function collects move reasons can be generated immediately from |
| 284 | 328 | * the data gathered in the examine_position() phase. |
| 285 | 329 | */ |
| 286 | | void |
| | 330 | inline void |
| 287 | 331 | collect_move_reasons(int color) |
| 288 | 332 | { |
| 289 | 333 | worm_reasons(color); |
| … |
… |
|
| 306 | 350 | int allowed_moves[BOARDMAX], float *value, int *resign) |
| 307 | 351 | { |
| 308 | 352 | float average_score, pessimistic_score, optimistic_score; |
| 309 | | int save_verbose; |
| 310 | | int save_depth; |
| 311 | 353 | int move; |
| 312 | 354 | float dummy_value; |
| 313 | 355 | int use_thrashing_dragon_heuristics = 0; |
| 314 | 356 | |
| | 357 | #ifndef GG_TURN_OFF_TRACES |
| | 358 | int save_verbose; |
| | 359 | #endif |
| | 360 | |
| | 361 | #ifndef GG_TURN_OFF_ASSERTS |
| | 362 | int save_depth; |
| | 363 | #endif |
| | 364 | |
| 315 | 365 | if (!value) |
| 316 | 366 | value = &dummy_value; |
| 317 | 367 | |
| | 368 | #ifndef GG_TURN_OFF_TRACES |
| 318 | 369 | start_timer(0); |
| | 370 | #endif |
| | 371 | |
| | 372 | #ifndef GG_TURN_OFF_STATS |
| 319 | 373 | clearstats(); |
| | 374 | #endif |
| 320 | 375 | |
| 321 | 376 | /* Usually we would not recommend resignation. */ |
| 322 | 377 | if (resign) |
| … |
… |
|
| 332 | 387 | /* Prepare pattern matcher and reading code. */ |
| 333 | 388 | reset_engine(); |
| 334 | 389 | |
| | 390 | #ifndef GG_TURN_OFF_ASSERTS |
| 335 | 391 | /* Store the depth value so we can check that it hasn't changed when |
| 336 | 392 | * we leave this function. |
| 337 | 393 | */ |
| 338 | 394 | save_depth = depth; |
| | 395 | #endif |
| 339 | 396 | |
| 340 | 397 | /* If in mirror mode, try to find a mirror move. */ |
| 341 | 398 | if (play_mirror_go |
| … |
… |
|
| 348 | 405 | } |
| 349 | 406 | |
| 350 | 407 | /* Find out information about the worms and dragons. */ |
| | 408 | #ifndef GG_TURN_OFF_TRACES |
| 351 | 409 | start_timer(1); |
| | 410 | #endif |
| | 411 | |
| 352 | 412 | examine_position(EXAMINE_ALL, 0); |
| | 413 | |
| | 414 | #ifndef GG_TURN_OFF_TRACES |
| 353 | 415 | time_report(1, "examine position", NO_MOVE, 1.0); |
| | 416 | #endif |
| 354 | 417 | |
| 355 | 418 | |
| 356 | 419 | /* The score will be used to determine when we are safely |
| … |
… |
|
| 374 | 437 | average_score = -(white_score + black_score)/2.0; |
| 375 | 438 | choose_strategy(color, average_score, game_status(color)); |
| 376 | 439 | |
| | 440 | #ifndef GG_TURN_OFF_TRACES |
| 377 | 441 | if (printboard) { |
| 378 | 442 | if (printboard == 1) |
| 379 | 443 | fprintf(stderr, "\n dragon_status display:\n\n"); |
| … |
… |
|
| 387 | 451 | showboard(4); |
| 388 | 452 | } |
| 389 | 453 | } |
| | 454 | #endif |
| 390 | 455 | |
| 391 | 456 | gg_assert(stackp == 0); |
| 392 | 457 | |
| … |
… |
|
| 396 | 461 | |
| 397 | 462 | |
| 398 | 463 | /* Pick up moves that we know of already. */ |
| | 464 | #ifndef GG_TURN_OFF_TRACES |
| 399 | 465 | save_verbose = verbose; |
| 400 | 466 | if (verbose > 0) |
| 401 | 467 | verbose--; |
| | 468 | #endif |
| | 469 | |
| 402 | 470 | collect_move_reasons(color); |
| | 471 | |
| | 472 | #ifndef GG_TURN_OFF_TRACES |
| 403 | 473 | verbose = save_verbose; |
| 404 | 474 | time_report(1, "generate move reasons", NO_MOVE, 1.0); |
| | 475 | #endif |
| 405 | 476 | |
| 406 | 477 | /* Try to find empty corner moves. */ |
| 407 | 478 | fuseki(color); |
| … |
… |
|
| 420 | 491 | |
| 421 | 492 | /* The general pattern database. */ |
| 422 | 493 | shapes(color); |
| | 494 | |
| | 495 | #ifndef GG_TURN_OFF_TRACES |
| 423 | 496 | time_report(1, "shapes", NO_MOVE, 1.0); |
| | 497 | #endif |
| | 498 | |
| 424 | 499 | gg_assert(stackp == 0); |
| 425 | 500 | |
| 426 | 501 | /* Look for combination attacks and defenses against them. */ |
| 427 | 502 | combinations(color); |
| | 503 | |
| | 504 | #ifndef GG_TURN_OFF_TRACES |
| 428 | 505 | time_report(1, "combinations", NO_MOVE, 1.0); |
| | 506 | #endif |
| | 507 | |
| 429 | 508 | gg_assert(stackp == 0); |
| 430 | 509 | |
| 431 | 510 | /* Review the move reasons and estimate move values. */ |
| … |
… |
|
| 433 | 512 | pure_threat_value, pessimistic_score, allowed_moves, |
| 434 | 513 | use_thrashing_dragon_heuristics)) |
| 435 | 514 | TRACE("Move generation likes %1m with value %f\n", move, *value); |
| | 515 | |
| 436 | 516 | gg_assert(stackp == 0); |
| | 517 | |
| | 518 | #ifndef GG_TURN_OFF_TRACES |
| 437 | 519 | time_report(1, "review move reasons", NO_MOVE, 1.0); |
| | 520 | #endif |
| 438 | 521 | |
| 439 | 522 | |
| 440 | 523 | /* If the move value is 6 or lower, we look for endgame patterns too. */ |
| … |
… |
|
| 447 | 530 | use_thrashing_dragon_heuristics)) |
| 448 | 531 | TRACE("Move generation likes %1m with value %f\n", move, *value); |
| 449 | 532 | gg_assert(stackp == 0); |
| | 533 | |
| | 534 | #ifndef GG_TURN_OFF_TRACES |
| 450 | 535 | time_report(1, "endgame", NO_MOVE, 1.0); |
| | 536 | #endif |
| 451 | 537 | } |
| 452 | 538 | |
| 453 | 539 | /* If no move found yet, revisit any semeai and change the |
| … |
… |
|
| 465 | 551 | move, *value); |
| 466 | 552 | } |
| 467 | 553 | } |
| 468 | | time_report(1, "move reasons with revised semeai status", |
| 469 | | NO_MOVE, 1.0); |
| | 554 | |
| | 555 | #ifndef GG_TURN_OFF_TRACES |
| | 556 | time_report(1, "move reasons with revised semeai status", NO_MOVE, 1.0); |
| | 557 | #endif |
| 470 | 558 | } |
| 471 | 559 | |
| 472 | 560 | /* If still no move, fill a remaining liberty. This should pick up |
| … |
… |
|
| 478 | 566 | *value = 1.0; |
| 479 | 567 | TRACE("Filling a liberty at %1m\n", move); |
| 480 | 568 | record_top_move(move, *value); |
| 481 | | move_considered(move, *value); |
| | 569 | |
| | 570 | #ifndef GG_TURN_OFF_TRACES |
| | 571 | move_considered(move, *value); |
| 482 | 572 | time_report(1, "fill liberty", NO_MOVE, 1.0); |
| | 573 | #endif |
| 483 | 574 | } |
| 484 | 575 | else |
| 485 | 576 | move = PASS_MOVE; |
| … |
… |
|
| 492 | 583 | if (move == PASS_MOVE) { |
| 493 | 584 | if (play_out_aftermath |
| 494 | 585 | || capture_all_dead |
| 495 | | || (!doing_scoring && thrashing_dragon && pessimistic_score > 15.0)) |
| | 586 | || (!doing_scoring && thrashing_dragon && pessimistic_score > 1.0)) |
| 496 | 587 | move = aftermath_genmove(color, 0, allowed_moves); |
| 497 | 588 | |
| 498 | 589 | /* If we're instructed to capture all dead opponent stones, generate |
| … |
… |
|
| 506 | 597 | *value = 1.0; |
| 507 | 598 | TRACE("Aftermath move at %1m\n", move); |
| 508 | 599 | record_top_move(move, *value); |
| 509 | | move_considered(move, *value); |
| | 600 | |
| | 601 | #ifndef GG_TURN_OFF_TRACES |
| | 602 | move_considered(move, *value); |
| 510 | 603 | time_report(1, "aftermath_genmove", NO_MOVE, 1.0); |
| | 604 | #endif |
| 511 | 605 | } |
| 512 | 606 | } |
| 513 | 607 | |
| … |
… |
|
| 534 | 628 | *resign = 1; |
| 535 | 629 | } |
| 536 | 630 | |
| | 631 | #ifndef GG_TURN_OFF_STATS |
| 537 | 632 | /* If statistics is turned on, this is the place to show it. */ |
| 538 | 633 | if (showstatistics) |
| 539 | 634 | showstats(); |
| | 635 | #endif |
| 540 | 636 | |
| | 637 | #ifndef GG_TURN_OFF_TRACES |
| 541 | 638 | if (showtime) { |
| 542 | 639 | double spent = time_report(0, "TIME to generate move at ", move, 1.0); |
| 543 | 640 | total_time += spent; |
| … |
… |
|
| 547 | 644 | slowest_movenum = movenum + 1; |
| 548 | 645 | } |
| 549 | 646 | } |
| | 647 | #endif |
| 550 | 648 | |
| 551 | 649 | /* Some consistency checks to verify that things are properly |
| 552 | 650 | * restored and/or have not been corrupted. |
| 553 | 651 | */ |
| 554 | 652 | gg_assert(stackp == 0); |
| 555 | 653 | gg_assert(test_gray_border() < 0); |
| | 654 | |
| | 655 | #ifndef GG_TURN_OFF_ASSERTS |
| 556 | 656 | gg_assert(depth == save_depth); |
| | 657 | #endif |
| 557 | 658 | |
| 558 | 659 | return move; |
| 559 | 660 | } |
| … |
… |
|
| 585 | 686 | int found_one = 0; |
| 586 | 687 | int other = OTHER_COLOR(color); |
| 587 | 688 | |
| 588 | | if (stones_on_board(BLACK | WHITE) == 0) |
| 589 | | return 0; |
| 590 | | |
| 591 | 689 | if (doing_scoring) |
| 592 | 690 | return 0; |
| 593 | 691 | |
| 594 | 692 | gg_assert(dragon2 != NULL); |
| 595 | 693 | |
| 596 | | for (pos = BOARDMIN; pos < BOARDMAX; pos++) { |
| 597 | | if (ON_BOARD(pos) |
| 598 | | && dragon[pos].color == other |
| | 694 | scan_board(pos, |
| | 695 | if (dragon[pos].color == other |
| 599 | 696 | && DRAGON2(pos).semeais |
| 600 | 697 | && dragon[pos].status == DEAD) { |
| 601 | 698 | found_one = 1; |
| … |
… |
|
| 604 | 701 | TRACE("revise_semeai: changed status of dragon %1m from DEAD to UNKNOWN\n", |
| 605 | 702 | pos); |
| 606 | 703 | } |
| 607 | | } |
| | 704 | ) |
| 608 | 705 | |
| 609 | 706 | return found_one; |
| 610 | 707 | } |
| … |
… |
|
| 622 | 719 | int pos; |
| 623 | 720 | signed char safe_stones[BOARDMAX]; |
| 624 | 721 | float strength[BOARDMAX]; |
| | 722 | int other_color; |
| 625 | 723 | |
| 626 | 724 | /* Trust the owl code's opinion if we are behind. */ |
| 627 | 725 | if (our_score < advantage) |
| … |
… |
|
| 632 | 730 | || dragon[thrashing_dragon].status != DEAD) |
| 633 | 731 | return 0; |
| 634 | 732 | |
| 635 | | for (pos = BOARDMIN; pos < BOARDMAX; pos++) |
| 636 | | if (ON_BOARD(pos) && thrashing_stone[pos] |
| | 733 | scan_board(pos, |
| | 734 | if (thrashing_stone[pos] |
| 637 | 735 | && worm[pos].unconditional_status != DEAD) { |
| 638 | 736 | dragon[pos].status = UNKNOWN; |
| 639 | 737 | DRAGON2(pos).safety = ALIVE; |
| 640 | 738 | } |
| | 739 | ) |
| 641 | 740 | |
| 642 | | set_strength_data(OTHER_COLOR(color), safe_stones, strength); |
| 643 | | compute_influence(OTHER_COLOR(color), safe_stones, strength, |
| | 741 | other_color = OTHER_COLOR(color); |
| | 742 | set_strength_data(other_color, safe_stones, strength); |
| | 743 | compute_influence(other_color, safe_stones, strength, |
| 644 | 744 | OPPOSITE_INFLUENCE(color), |
| 645 | 745 | NO_MOVE, "revised thrashing dragon"); |
| 646 | 746 | compute_refined_dragon_weaknesses(); |
| … |
… |
|
| 670 | 770 | } |
| 671 | 771 | } |
| 672 | 772 | else { |
| 673 | | for (mirror_move = BOARDMIN; mirror_move < BOARDMAX; mirror_move++) { |
| 674 | | if (ON_BOARD(mirror_move) |
| 675 | | && test_symmetry_after_move(mirror_move, color, 0)) { |
| | 773 | scan_board(mirror_move, |
| | 774 | if (test_symmetry_after_move(mirror_move, color, 0)) { |
| 676 | 775 | *move = mirror_move; |
| 677 | 776 | return 1; |
| 678 | 777 | } |
| 679 | | } |
| | 778 | ) |
| 680 | 779 | } |
| 681 | 780 | |
| 682 | 781 | return 0; |
| … |
… |
|
| 701 | 800 | NO_MOVE, "White territory estimate"); |
| 702 | 801 | black_score = influence_score(&move_influence, use_chinese_rules); |
| 703 | 802 | |
| | 803 | #ifndef GG_TURN_OFF_TRACES |
| 704 | 804 | if (verbose || showscore) { |
| 705 | 805 | if (white_score == black_score) |
| 706 | 806 | gprintf("Score estimate: %s %f\n", |
| … |
… |
|
| 711 | 811 | white_score > 0 ? "W " : "B ", gg_abs(white_score)); |
| 712 | 812 | fflush(stderr); |
| 713 | 813 | } |
| | 814 | #endif |
| 714 | 815 | } |
| 715 | 816 | |
| 716 | 817 | |
| … |
… |
|
| 749 | 850 | * it looks like all our dragons are dead and the generated move |
| 750 | 851 | * is a pass. |
| 751 | 852 | */ |
| 752 | | if (board_size > 2 && move == PASS_MOVE && !lively_dragon_exists(color)) |
| | 853 | if (move == PASS_MOVE && !lively_dragon_exists(color)) |
| 753 | 854 | return 1; |
| 754 | 855 | |
| 755 | 856 | if (move == PASS_MOVE |