diff -N -r -u -X .ignore gnugo-copy/config.vcin gnugo/config.vcin
|
old
|
new
|
|
| 30 | 30 | /* GAIN/LOSS codes. Disabled by default. */ |
| 31 | 31 | #define EXPERIMENTAL_OWL_EXT 0 |
| 32 | 32 | |
| | 33 | /* Disable unneeded things. 0 standard. */ |
| | 34 | #define FINAL_RELEASE 0 |
| | 35 | |
| 33 | 36 | /* Define as 1 to use the grid optimisation, or 2 to run it in self-test mode |
| 34 | 37 | */ |
| 35 | 38 | #define GRID_OPT 1 |
diff -N -r -u -X .ignore gnugo-copy/doc/dfa.texi gnugo/doc/dfa.texi
|
old
|
new
|
|
| 1 | 1 | In this chapter, we describe the principles of the GNU Go DFA |
| 2 | 2 | pattern matcher. The aim of this system is to permit a fast |
| 3 | | pattern matching when it becomes time critical like in owl |
| 4 | | module (@ref{The Owl Code}). Since GNU Go 3.2, this is enabled |
| | 3 | pattern matching. Since GNU Go 3.2, this is enabled |
| 5 | 4 | by default. You can still get back the traditional pattern matcher |
| 6 | 5 | by running @command{configure --disable-dfa} and then recompiling |
| 7 | 6 | GNU Go. |
diff -N -r -u -X .ignore gnugo-copy/doc/dragon.texi gnugo/doc/dragon.texi
|
old
|
new
|
|
| 17 | 17 | Later routines called by @code{genmove()} will then have access to this |
| 18 | 18 | information. This document attempts to explain the philosophy and |
| 19 | 19 | algorithms of this preliminary analysis, which is carried out by the |
| 20 | | two routines @code{make_worm()} and @code{make_dragon()} in |
| 21 | | @file{dragon.c}. |
| | 20 | two routines @code{make_worms()} (in @file{worm.c}) and |
| | 21 | @code{make_dragons()} (in @file{dragon.c}). |
| 22 | 22 | |
| 23 | 23 | @cindex dragon |
| 24 | 24 | @cindex worm |
| … |
… |
|
| 83 | 83 | int unconditional_status; |
| 84 | 84 | int attack_points[MAX_TACTICAL_POINTS]; |
| 85 | 85 | int attack_codes[MAX_TACTICAL_POINTS]; |
| | 86 | int discarded_attacks[MAX_TACTICAL_POINTS]; |
| 86 | 87 | int defense_points[MAX_TACTICAL_POINTS]; |
| 87 | 88 | int defend_codes[MAX_TACTICAL_POINTS]; |
| | 89 | int discarded_defenses[MAX_TACTICAL_POINTS]; |
| 88 | 90 | int attack_threat_points[MAX_TACTICAL_POINTS]; |
| 89 | | int attack_threat_codes[MAX_TACTICAL_POINTS]; |
| | 91 | int attack_threat_codes[MAX_TACTICAL_POINTS]; |
| | 92 | int discarded_att_threats[MAX_TACTICAL_POINTS]; |
| 90 | 93 | int defense_threat_points[MAX_TACTICAL_POINTS]; |
| 91 | 94 | int defense_threat_codes[MAX_TACTICAL_POINTS]; |
| | 95 | int discarded_def_threats[MAX_TACTICAL_POINTS]; |
| 92 | 96 | @}; |
| 93 | 97 | @end example |
| 94 | 98 | |
| … |
… |
|
| 109 | 113 | other worm. Intersections that are shared are counted with equal |
| 110 | 114 | fractional values for each worm. This measures the direct territorial |
| 111 | 115 | value of capturing a worm. @dfn{effective_size} is a floating point number. |
| 112 | | Only intersections at a distance of 4 or less are counted. |
| | 116 | Only intersections at a distance (empty vertices between a worm and an |
| | 117 | intersection) of 5 or less are counted. |
| 113 | 118 | @end quotation |
| 114 | 119 | @item @code{origin} |
| 115 | 120 | @quotation |
| … |
… |
|
| 220 | 225 | @end quotation |
| 221 | 226 | @item @code{cutstone2} |
| 222 | 227 | @quotation |
| 223 | | Cutting points are identified by the patterns in the connections |
| 224 | | database. Proper cuts are handled by the fact that attacking and |
| | 228 | Number of potential cuts involving the worm. Cutting points are |
| | 229 | identified by the patterns in the connections database. Proper |
| | 230 | cuts are handled by the fact that attacking and |
| 225 | 231 | defending moves also count as moves cutting or connecting the |
| 226 | 232 | surrounding dragons. The @code{cutstone2} field is set during |
| 227 | 233 | @code{find_cuts()}, called from @code{make_domains()}. |
| … |
… |
|
| 248 | 254 | opposite color can be killed. More precisely an |
| 249 | 255 | @dfn{inessential string} is a string S of genus zero, |
| 250 | 256 | not adjacent to any opponent string which can be easily |
| 251 | | captured, and which has no edge liberties or second |
| | 257 | captured, which is not cutstone, and which has up to |
| | 258 | 2 edge liberties and no second |
| 252 | 259 | order liberties, and which satisfies the following |
| 253 | 260 | further property: If the string is removed from the |
| 254 | 261 | board, then the remaining cavity only borders worms of the |
| … |
… |
|
| 266 | 273 | even if the opponent is allowed an arbitrary number of consecutive |
| 267 | 274 | moves. |
| 268 | 275 | @end quotation |
| 269 | | @item unconditional_status |
| | 276 | @item @code{unconditional_status} |
| 270 | 277 | @quotation |
| 271 | 278 | Unconditional status is also set by the function |
| 272 | 279 | @code{unconditional_life}. This is set @code{ALIVE} for stones which are |
| … |
… |
|
| 285 | 292 | transformed into an invincible group by some number of consecutive |
| 286 | 293 | moves. Well, this is not entirely true because there is a rare class of |
| 287 | 294 | seki groups not satisfying this condition. Exactly which these are is |
| 288 | | left as an exercise for the reader. Currently @code{unconditional_life}, |
| 289 | | which strictly follows the definitions above, calls such seki groups |
| 290 | | unconditionally dead, which of course is a misfeature. It is possible to |
| 291 | | avoid this problem by making the algorithm slightly more complex, but |
| 292 | | this is left for a later revision. |
| | 295 | shown in a comment in @file{unconditional.c}. |
| 293 | 296 | @end quotation |
| 294 | | @item @code{int attack_points[MAX_TACTICAL_POINTS]} |
| 295 | | @item @code{attack_codes[MAX_TACTICAL_POINTS]} |
| | 297 | @item @code{int attack_points[MAX_TACTICAL_POINTS];} |
| | 298 | @item @code{int attack_codes[MAX_TACTICAL_POINTS];} |
| 296 | 299 | @item @code{int defense_points[MAX_TACTICAL_POINTS];} |
| 297 | 300 | @item @code{int defend_codes[MAX_TACTICAL_POINTS];} |
| 298 | 301 | @quotation |
| … |
… |
|
| 310 | 313 | @quotation |
| 311 | 314 | These are points that threaten to attack or defend a worm. |
| 312 | 315 | @end quotation |
| | 316 | @item @code{int discarded_attacks[MAX_TACTICAL_POINTS];} |
| | 317 | @item @code{int discarded_defenses[MAX_TACTICAL_POINTS];} |
| | 318 | @item @code{int discarded_att_threats[MAX_TACTICAL_POINTS];} |
| | 319 | @item @code{int discarded_def_threats[MAX_TACTICAL_POINTS];} |
| | 320 | @quotation |
| | 321 | These are checked points that haven't led to any positive result. |
| | 322 | Used to not check the same point more than once. |
| | 323 | @end quotation |
| 313 | 324 | @end itemize |
| 314 | 325 | |
| 315 | 326 | The function @code{makeworms()} will generate data for all worms. |
| … |
… |
|
| 343 | 354 | XXX... |
| 344 | 355 | |
| 345 | 356 | @end example |
| 346 | | @findex dragon_eye |
| 347 | | |
| 348 | | The code for this type of amalgamation is in the routine |
| 349 | | @code{dragon_eye()}, discussed further in EYES. |
| 350 | 357 | |
| 351 | 358 | Next, we amalgamate strings which seem uncuttable. We amalgamate dragons |
| 352 | 359 | which either share two or more common liberties, or share one liberty |
| … |
… |
|
| 367 | 374 | @section Connection |
| 368 | 375 | @cindex connections |
| 369 | 376 | |
| 370 | | The fields @code{black_eye.cut} and @code{white_eye.cut} are set where the |
| | 377 | The fields in @code{cutting_points} are set where the |
| 371 | 378 | opponent can cut, and this is done by the B (break) class patterns in |
| 372 | | @file{conn.db}. There are two important uses for this field, which can be |
| | 379 | @file{conn.db}. There are two important uses for this table, which can be |
| 373 | 380 | accessed by the autohelper functions @code{xcut()} and @code{ocut()}. The |
| 374 | 381 | first use is to stop amalgamation in positions like |
| 375 | 382 | |
| … |
… |
|
| 534 | 541 | int safety; |
| 535 | 542 | float weakness; |
| 536 | 543 | float weakness_pre_owl; |
| | 544 | float strategic_size; |
| 537 | 545 | int escape_route; |
| 538 | 546 | struct eyevalue genus; |
| 539 | 547 | int heye; |
| … |
… |
|
| 541 | 549 | int surround_status; |
| 542 | 550 | int surround_size; |
| 543 | 551 | int semeais; |
| 544 | | int semeai_margin_of_safety; |
| | 552 | int semeai_defense_code; |
| 545 | 553 | int semeai_defense_point; |
| 546 | | int semeai_defense_certain; |
| | 554 | int semeai_defense_certain; |
| | 555 | int semeai_defense_target; |
| | 556 | int semeai_attack_code; |
| 547 | 557 | int semeai_attack_point; |
| 548 | 558 | int semeai_attack_certain; |
| | 559 | int semeai_attack_target; |
| 549 | 560 | int owl_threat_status; |
| 550 | 561 | int owl_status; |
| 551 | 562 | int owl_attack_point; |
| 552 | 563 | int owl_attack_code; |
| 553 | 564 | int owl_attack_certain; |
| | 565 | int owl_attack_node_count; |
| 554 | 566 | int owl_second_attack_point; |
| 555 | 567 | int owl_defense_point; |
| 556 | 568 | int owl_defense_code; |
| … |
… |
|
| 607 | 619 | @quotation |
| 608 | 620 | The dragon number, used as a key into the @code{dragon2} array. |
| 609 | 621 | @end quotation |
| 610 | | @item origin |
| | 622 | @item @code{origin} |
| 611 | 623 | @cindex dragon origin |
| 612 | 624 | @quotation |
| 613 | 625 | The origin of the dragon is a unique particular vertex |
| … |
… |
|
| 616 | 628 | copied to the dragon origins. Amalgamation of two dragons |
| 617 | 629 | amounts to changing the origin of one. |
| 618 | 630 | @end quotation |
| 619 | | @item size |
| | 631 | @item @code{size} |
| 620 | 632 | @cindex dragon size |
| 621 | 633 | @quotation |
| 622 | 634 | The number of stones in the dragon. |
| 623 | 635 | @end quotation |
| 624 | | @item effective size |
| | 636 | @item @code{effective size} |
| 625 | 637 | @cindex effective size |
| 626 | 638 | @quotation |
| 627 | 639 | The sum of the effective sizes of the constituent worms. |
| … |
… |
|
| 630 | 642 | cardinality of the dragon plus the number of empty vertices which are |
| 631 | 643 | nearer this dragon than any other. |
| 632 | 644 | @end quotation |
| 633 | | @item crude_status |
| | 645 | @item @code{crude_status} |
| 634 | 646 | @quotation |
| 635 | 647 | (ALIVE, DEAD, UNKNOWN, CRITICAL). An early measure of the life |
| 636 | 648 | potential of the dragon. It is computed before the owl code is |
| 637 | 649 | run and is superceded by the status as soon as that becomes |
| 638 | 650 | available. |
| 639 | 651 | @end quotation |
| 640 | | @item status |
| | 652 | @item @code{status} |
| 641 | 653 | @cindex dragon status |
| 642 | 654 | @quotation |
| 643 | 655 | The dragon status is the best measure of the dragon's health. |
| … |
… |
|
| 649 | 661 | Here are definitions of the fields in the @code{dragon2} array. |
| 650 | 662 | |
| 651 | 663 | @itemize @bullet |
| 652 | | @item origin |
| | 664 | @item @code{origin} |
| 653 | 665 | @quotation |
| 654 | 666 | The origin field is duplicated here. |
| 655 | 667 | @end quotation |
| 656 | | @item adjacent |
| 657 | 668 | @item @code{adjacent[MAX_NEIGHBOR_DRAGONS]} |
| 658 | | @cindex neighbor dragons |
| 659 | | @cindex adjacent dragons |
| 660 | | @findex find_neighbor_dragons |
| 661 | | @quotation |
| 662 | | Dragons of either color near the given one are called @dfn{neighbors}. |
| 663 | | They are computed by the function @code{find_neighbor_dragons()}. |
| 664 | | The @code{dragon2.adjacent} array gives the dragon numbers of |
| 665 | | these dragons. |
| 666 | | @end quotation |
| 667 | 669 | @item @code{neighbors} |
| 668 | 670 | @cindex neighbor dragons |
| 669 | 671 | @cindex adjacent dragons |
| … |
… |
|
| 671 | 673 | @quotation |
| 672 | 674 | Dragons of either color near the given one are called @dfn{neighbors}. |
| 673 | 675 | They are computed by the function @code{find_neighbor_dragons()}. |
| 674 | | The @code{dragon2.adjacent} array gives the dragon numbers of |
| 675 | | these dragons. |
| | 676 | The @code{adjacent} array gives the dragon numbers of |
| | 677 | these dragons and @code{neighbors} gives the number of them. |
| 676 | 678 | @end quotation |
| 677 | | @item neighbors |
| 678 | | @quotation |
| 679 | | The number of neighbor dragons. |
| 680 | | @end quotation |
| 681 | | @item hostile_neighbors |
| | 679 | @item @code{hostile_neighbors} |
| 682 | 680 | @quotation |
| 683 | 681 | The number of neighbor dragons of the opposite color. |
| 684 | 682 | @end quotation |
| 685 | | @item moyo_size |
| 686 | | @item float moyo_territorial_value |
| | 683 | @item @code{moyo_size} |
| | 684 | @item @code{moyo_territorial_value} |
| 687 | 685 | @findex compute_surrounding_moyo_sizes |
| 688 | 686 | @quotation |
| 689 | 687 | The function @code{compute_surrounding_moyo_sizes()} assigns |
| … |
… |
|
| 691 | 689 | each dragon (@pxref{Territory and Moyo}). This is the |
| 692 | 690 | moyo size. They are recorded in these fields. |
| 693 | 691 | @end quotation |
| 694 | | @item safety |
| | 692 | @item @code{safety} |
| 695 | 693 | @cindex dragon safety |
| 696 | 694 | @quotation |
| 697 | 695 | The dragon safety can take on one of the values |
| … |
… |
|
| 707 | 705 | @item INESSENTIAL - the dragon is unimportant (e.g. nakade stones) and dead |
| 708 | 706 | @end itemize |
| 709 | 707 | @end quotation |
| 710 | | @item weakness |
| 711 | | @item weakness_pre_owl |
| | 708 | @item @code{weakness} |
| | 709 | @item @code{weakness_pre_owl} |
| 712 | 710 | @cindex dragon weakness |
| 713 | 711 | @cindex weakness |
| 714 | 712 | @quotation |
| … |
… |
|
| 717 | 715 | dragons in greater need of safety. The field @code{weakness_pre_owl} |
| 718 | 716 | is a preliminary computation before the owl code is run. |
| 719 | 717 | @end quotation |
| 720 | | @item escape_route |
| | 718 | @item @code{strategic_size} |
| | 719 | @cindex strategic_size |
| | 720 | @quotation |
| | 721 | An effective size including weakness of neighbors. |
| | 722 | @end quotation |
| | 723 | @item @code{escape_route} |
| 721 | 724 | @cindex dragon escape_route |
| 722 | 725 | @cindex escape_route |
| 723 | 726 | @findex compute_escape |
| … |
… |
|
| 726 | 729 | in case it cannot make two eyes locally. Documentation |
| 727 | 730 | may be found in @ref{Escape}. |
| 728 | 731 | @end quotation |
| 729 | | @item struct eyevalue genus |
| | 732 | @item @code{genus} |
| 730 | 733 | @cindex dragon genus |
| 731 | 734 | @cindex genus |
| 732 | 735 | @quotation |
| … |
… |
|
| 744 | 747 | |
| 745 | 748 | @end example |
| 746 | 749 | @end quotation |
| 747 | | @item heye |
| | 750 | @item @code{heye} |
| 748 | 751 | @quotation |
| 749 | 752 | Location of a half eye attached to the dragon. |
| 750 | 753 | @end quotation |
| 751 | | @item lunch |
| | 754 | @item @code{lunch} |
| 752 | 755 | @cindex dragon lunch |
| 753 | 756 | @cindex lunch |
| 754 | 757 | @quotation |
| … |
… |
|
| 756 | 759 | can be captured. In contrast with worm lunches, a dragon |
| 757 | 760 | lunch must be able to defend itself. |
| 758 | 761 | @end quotation |
| 759 | | @item surround_status |
| 760 | | @item surround_size |
| | 762 | @item @code{surround_status} |
| | 763 | @item @code{surround_size} |
| 761 | 764 | @cindex surround_status |
| 762 | 765 | @cindex surround_size |
| 763 | 766 | @cindex surround |
| … |
… |
|
| 766 | 769 | it is @dfn{surrounded}. See @ref{Surrounded Dragons} and |
| 767 | 770 | the comments in @file{surround.c} for more information about the |
| 768 | 771 | algorithm. Used in computing the escape_route, and also callable |
| 769 | | from patterns (currently used by CB258). |
| | 772 | from patterns. |
| 770 | 773 | @end quotation |
| 771 | | @item semeais |
| 772 | | @item semeai_defense_point |
| 773 | | @item semeai_defense_certain |
| 774 | | @item semeai_attack_point |
| 775 | | @item semeai_attack_certain |
| 776 | | @cindex semeai |
| | 774 | @item @code{semeais} |
| | 775 | @item @code{semeai_defense_code} |
| | 776 | @item @code{semeai_defense_point} |
| | 777 | @item @code{semeai_defense_certain} |
| | 778 | @item @code{semeai_defense_target} |
| | 779 | @item @code{semeai_attack_code} |
| | 780 | @item @code{semeai_attack_point} |
| | 781 | @item @code{semeai_attack_certain} |
| | 782 | @item @code{semeai_attack_target} |
| | 783 | @cindex semeais |
| | 784 | @cindex semeai_defense_code |
| 777 | 785 | @cindex semeai_defense_point |
| 778 | 786 | @cindex semeai_defense_certain |
| | 787 | @cindex semeai_defense_target |
| | 788 | @cindex semeai_attack_code |
| 779 | 789 | @cindex semeai_attack_point |
| 780 | 790 | @cindex semeai_attack_certain |
| | 791 | @cindex semeai_attack_target |
| 781 | 792 | @quotation |
| 782 | 793 | If two dragons of opposite color both have the status CRITICAL |
| 783 | 794 | or DEAD they are in a @dfn{semeai} (capturing race), and their |
| … |
… |
|
| 785 | 796 | @code{owl_analyze_semeai()} in @file{owl.c}, which attempts to |
| 786 | 797 | determine which is alive, which dead, or if the result is |
| 787 | 798 | seki, and whether it is important who moves first. The |
| 788 | | function @file{new_semeai()} in @file{semeai.c} attempts |
| | 799 | function @code{semeai()} in @file{semeai.c} attempts |
| 789 | 800 | to revise the statuses and to generate move reasons based |
| 790 | 801 | on these results. The field @code{dragon2.semeais} is nonzero |
| 791 | 802 | if the dragon is an element of a semeai, and equals the |
| 792 | 803 | number of semeais (seldom more than one). The semeai defense |
| 793 | 804 | and attack points are locations the defender or attacker |
| 794 | | must move to win the semeai. The field @code{semeai_margin_of_safety} |
| 795 | | is intended to indicate whether the semeai is close or not |
| 796 | | but currently this field is not maintained. The fields |
| | 805 | must move to win the semeai and the result code of these moves is |
| | 806 | also stored. In @code{semeai_defense_target} and |
| | 807 | @code{semeai_attack_target} an origin of an opponent dragon in |
| | 808 | semeai, on which the move has impact, is stored. The fields |
| 797 | 809 | @code{semeai_defense_certain} and @code{semeai_attack_certain} |
| 798 | 810 | indicate that the semeai code was able to finish analysis |
| 799 | 811 | without running out of nodes. |
| 800 | 812 | @end quotation |
| 801 | | @item owl_status |
| | 813 | @item @code{owl_threat_status} |
| | 814 | @quotation |
| | 815 | Informs, whether the dragon has any defense or attack threats |
| | 816 | (@code{CAN_THREATEN_ATTACK} or @code{CAN_THREATEN_DEFENSE}). |
| | 817 | @end quotation |
| | 818 | @item @code{owl_status} |
| 802 | 819 | @quotation |
| 803 | 820 | This is a classification similar to @code{dragon.crude_status}, but |
| 804 | 821 | based on the life and death reading in @file{owl.c}. |
| … |
… |
|
| 810 | 827 | @code{owl_defend()} is run, and if it can be defended it |
| 811 | 828 | is classified as @code{CRITICAL}, and if not, as @code{DEAD}. |
| 812 | 829 | @end quotation |
| 813 | | @item owl_attack_point |
| | 830 | @item @code{owl_attack_point} |
| 814 | 831 | @cindex owl_attack_point |
| 815 | 832 | @quotation |
| 816 | 833 | If the dragon can be attacked this is the point to attack the dragon. |
| 817 | 834 | @end quotation |
| 818 | | @item owl_attack_code |
| | 835 | @item @code{owl_attack_code} |
| 819 | 836 | @cindex owl_attack_code |
| 820 | 837 | @quotation |
| 821 | | The owl attack code, It can be WIN, KO_A, KO_B or 0 (@pxref{Return Codes}). |
| | 838 | The owl attack code, It can be WIN, KO_A, GAIN, LOSS, |
| | 839 | KO_B or 0 (@pxref{Return Codes}). |
| 822 | 840 | @end quotation |
| 823 | | @item owl_attack_certain |
| | 841 | @item @code{owl_attack_certain} |
| 824 | 842 | @cindex owl_attack_certain |
| 825 | 843 | @quotation |
| 826 | 844 | The owl reading is able to finish analyzing the attack |
| 827 | 845 | without running out of nodes. |
| 828 | 846 | @end quotation |
| 829 | | @item owl_second_attack_point |
| | 847 | @item @code{owl_attack_node_count} |
| | 848 | @cindex owl_attack_node_count |
| | 849 | @quotation |
| | 850 | Number of nodes used during analyze of attack move. |
| | 851 | @end quotation |
| | 852 | @item @code{owl_second_attack_point} |
| 830 | 853 | @cindex owl_second_attack_point |
| 831 | 854 | @quotation |
| 832 | 855 | A second attack point. |
| 833 | 856 | @end quotation |
| 834 | | @item owl_defense_point |
| | 857 | @item @code{owl_defense_point} |
| 835 | 858 | @cindex owl_defense_point |
| 836 | 859 | @quotation |
| 837 | 860 | If the dragon can be defended, this is the place to play. |
| 838 | 861 | @end quotation |
| 839 | | @item owl_defense_code |
| | 862 | @item @code{owl_defense_code} |
| 840 | 863 | @cindex owl_defense_code |
| 841 | 864 | @quotation |
| 842 | | The owl defense code, It can be WIN, KO_A, KO_B or 0 (@pxref{Return Codes}). |
| | 865 | The owl defense code, It can be WIN, KO_A, GAIN, LOSS, |
| | 866 | KO_B or 0 (@pxref{Return Codes}). |
| 843 | 867 | @end quotation |
| 844 | | @item owl_defense_certain |
| | 868 | @item @code{owl_defense_certain} |
| 845 | 869 | @cindex owl_defense_certain |
| 846 | 870 | @quotation |
| 847 | 871 | The owl code is able to finish analyzing the defense without |
| 848 | 872 | running out of nodes. |
| 849 | 873 | @end quotation |
| 850 | | @item owl_second_defense_point |
| | 874 | @item @code{owl_second_defense_point} |
| 851 | 875 | @cindex owl_second_defense_point |
| 852 | 876 | @quotation |
| 853 | 877 | A second owl defense point. |
| 854 | 878 | @end quotation |
| | 879 | @item @code{owl_attack_kworm} |
| | 880 | @cindex owl_attack_kworm |
| | 881 | @quotation |
| | 882 | Position of a worm, which can be killed during attack on the dragon |
| | 883 | (@code{owl_attack_code} has to be @code{GAIN}). |
| | 884 | @end quotation |
| | 885 | @item @code{owl_defense_kworm} |
| | 886 | @cindex owl_defense_kworm |
| | 887 | @quotation |
| | 888 | Position of our worm (part of the dragon) abandoned during defense of |
| | 889 | the dragon (@code{owl_defend_code} has to be @code{LOSS}). |
| | 890 | @end quotation |
| 855 | 891 | @end itemize |
| 856 | 892 | |
| 857 | 893 | @node Dragons in Color |
diff -N -r -u -X .ignore gnugo-copy/doc/move_generation.texi gnugo/doc/move_generation.texi
|
old
|
new
|
|
| 214 | 214 | the simultaneous attack of one worm and the defense of another. As for |
| 215 | 215 | attack and defense moves, it's important that all moves which win a |
| 216 | 216 | semeai are found, so an informed choice can be made between them. |
| | 217 | Semeai move reasons are set by the semeai module. |
| | 218 | |
| | 219 | One might also wish to list moves which increase the lead in a semeai |
| | 220 | race (removes ko threats) for use as secondary move reasons. Analogously, |
| | 221 | if we are behind in the race. However this has not been implemented yet. |
| 217 | 222 | |
| 218 | | Semeai move reasons should be set by the semeai module. However this |
| 219 | | has not been implemented yet. One might also wish to list moves |
| 220 | | which increase the lead in a semeai race (removes ko threats) for use |
| 221 | | as secondary move reasons. Analogously if we are behind in the race. |
| 222 | 223 | |
| 223 | 224 | @node Making eyes |
| 224 | 225 | @subsection Making or destroying eyes |
| … |
… |
|
| 229 | 230 | will be valued substantially higher if this is the case. As usual it's |
| 230 | 231 | important to find all moves that change the eye count. |
| 231 | 232 | |
| 232 | | (This is part of what eye_finder was doing. Currently it only finds |
| 233 | | one vital point for each unstable eye space.) |
| | 233 | The eye module (@file{optics.c}) is handling this. It uses eyes patterns |
| | 234 | database @file{patterns/eyes.db}. |
| 234 | 235 | |
| 235 | 236 | @node Antisuji moves |
| 236 | 237 | @subsection Antisuji moves |
| … |
… |
|
| 247 | 248 | territory move reason. That move reason is added by the @samp{e} |
| 248 | 249 | patterns in @file{patterns/patterns.db}. Similarly the @samp{E} patterns |
| 249 | 250 | attempt to generate or mitigate a moyo, which is a region of influence |
| 250 | | not yet secure territory, yet valuable. Such a pattern sets the ``expand |
| 251 | | moyo'' move reason. |
| | 251 | not yet secure territory, yet valuable. There are also other patterns for |
| | 252 | reducing territory, invasions and making bariers (to defend before |
| | 253 | invasions) - they are in @file{patterns/influence.db} and |
| | 254 | @file{patterns/barriers.db}. These patterns set the ``expand moyo'', |
| | 255 | ``expand territory'' and ``invasion'' move reasons. They also have |
| | 256 | influence on a move territorial valuation. |
| 252 | 257 | |
| 253 | 258 | @node Owl attack and defense |
| 254 | 259 | @subsection Attacking and Defending Dragons |
| … |
… |
|
| 310 | 315 | as explained for example in @emph{The Endgame} by Ogawa |
| 311 | 316 | and Davies. |
| 312 | 317 | |
| 313 | | Moves are valued with respect to four different criteria. These are |
| | 318 | Moves are valued with respect to four different main criteria. These |
| | 319 | are |
| 314 | 320 | |
| 315 | 321 | @itemize @bullet |
| 316 | 322 | @item territorial value |
| … |
… |
|
| 362 | 368 | * Minimum Value:: Minimum value |
| 363 | 369 | * Secondary Value:: Other, more indirect, gains from a move |
| 364 | 370 | * Threats and Followup Value:: Valuation of attack and defense threats |
| | 371 | * Additional ko value:: Additional threat value for a ko fight |
| 365 | 372 | @end menu |
| 366 | 373 | |
| 367 | 374 | @node Territorial value |
| … |
… |
|
| 384 | 391 | |
| 385 | 392 | @node Strategical value |
| 386 | 393 | @subsection Strategical Value |
| | 394 | @findex estimate_strategical_value |
| 387 | 395 | |
| 388 | 396 | Strategical defense or attack reasons are assigned to any move |
| 389 | 397 | which matches a pattern of type @samp{a} or @samp{d}. These are |
| … |
… |
|
| 394 | 402 | to check its status or safety. This is done later, during |
| 395 | 403 | the valuation phase. |
| 396 | 404 | |
| | 405 | The whole algorithm is placed in @code{estimate_strategical_value}. |
| | 406 | |
| 397 | 407 | @node Shape factor |
| 398 | 408 | @subsection Shape Factor |
| 399 | 409 | |
| … |
… |
|
| 451 | 461 | which we cannot legally take, then such a move becomes attractive as a ko |
| 452 | 462 | threat and the full followup value is taken into account. |
| 453 | 463 | |
| | 464 | @node Additional ko value |
| | 465 | @subsection Additional ko value |
| | 466 | |
| | 467 | Some moves give us additional threats and some give them to an opponent. |
| | 468 | In such situations we should give some bonus or penalty for creating ko |
| | 469 | threats. As for now only positive contribution is counted. |
| | 470 | |
| 454 | 471 | @node End Game |
| 455 | 472 | @section End Game |
| 456 | 473 | |
diff -N -r -u -X .ignore gnugo-copy/doc/patterns.texi gnugo/doc/patterns.texi
|
old
|
new
|
|
| 85 | 85 | Elements are not generated for @samp{?} markers, but they are not |
| 86 | 86 | completely ignored - see below. |
| 87 | 87 | |
| 88 | | The line beginning @samp{:} describes various attributes of the pattern, such |
| 89 | | as its symmetry and its class. Optionally, a function called a |
| 90 | | ``helper'' can be provided to assist the matcher in deciding whether |
| 91 | | to accept move. Most patterns do not require a helper, and this field |
| 92 | | is filled with NULL. |
| 93 | | |
| 94 | 88 | @findex shapes_callback |
| 95 | 89 | The matcher in @file{matchpat.c} searches the board for places where this |
| 96 | 90 | layout appears on the board, and the callback function |
| … |
… |
|
| 100 | 94 | After the pattern, there is some supplementary information in the format: |
| 101 | 95 | @example |
| 102 | 96 | |
| 103 | | :trfno, classification, [values], helper_function |
| | 97 | :trfno, attributes, [values], helper_function |
| 104 | 98 | |
| 105 | 99 | @end example |
| 106 | 100 | |
| … |
… |
|
| 110 | 104 | represents the axis of symmetry. (E.g. @samp{|} means symmetrical about a |
| 111 | 105 | vertical axis.) |
| 112 | 106 | |
| | 107 | @code{helper_function} is a function that can be provided to assist the matcher |
| | 108 | in deciding whether to accept move. Most patterns do not require a helper, |
| | 109 | and this field is filled with NULL. |
| | 110 | |
| 113 | 111 | The above pattern could equally well be written on the left edge: |
| 114 | 112 | |
| 115 | 113 | @example |
| … |
… |
|
| 127 | 125 | way, or for that matter, on the top or right edges, or in any |
| 128 | 126 | of the four corners. As a matter of convention all the edge patterns |
| 129 | 127 | in @file{patterns.db} are written on the bottom edge or in the lower left |
| 130 | | corners. In the @file{patterns/} directory there is a program called |
| 131 | | @code{transpat} which can rotate or otherwise transpose patterns. |
| 132 | | This program is not built by default---if you think you need it, |
| 133 | | @code{make transpat} in the @file{patterns/} directory and |
| 134 | | consult the usage remarks at the beginning of @file{patterns/transpat.c}. |
| | 128 | corners. |
| 135 | 129 | |
| 136 | 130 | @node Pattern Classification |
| 137 | 131 | @section Pattern Attributes |
| … |
… |
|
| 415 | 409 | need to remove the stones we placed from the reading stack. This is done |
| 416 | 410 | with the function @code{popgo()}. |
| 417 | 411 | |
| | 412 | IMPORTANT: The macro @code{OFFSET} is not used anymore, because it has |
| | 413 | fixed coordinates and patterns can be now rotated randomly by DFA |
| | 414 | optimizer. All helpers that require usage of this macro have to be moved |
| | 415 | to autohelpers. |
| | 416 | |
| 418 | 417 | @node Autohelpers and Constraints |
| 419 | 418 | @section Autohelpers and Constraints |
| 420 | 419 | |
| … |
… |
|
| 566 | 565 | The autohelper functions are translated into C code by the program in |
| 567 | 566 | @file{mkpat.c}. To see exactly how the functions are implemented, |
| 568 | 567 | consult the autohelper function definitions in that file. Autohelper |
| 569 | | functions can be used in both constraint and action lines. |
| | 568 | functions can be used in both constraint and action lines. Here is |
| | 569 | a partial list of them: |
| 570 | 570 | |
| 571 | 571 | @example |
| 572 | 572 | |
| … |
… |
|
| 1063 | 1063 | |
| 1064 | 1064 | The patterns in @file{conn.db} are used for helping @code{make_dragons()} |
| 1065 | 1065 | amalgamate worms into dragons and to some extent for modifying eye spaces. |
| 1066 | | The patterns in this database use the classifications @samp{B}, |
| 1067 | | @samp{C}, and @samp{e}. @samp{B} patterns are used for finding cutting points, |
| | 1066 | The patterns in this database use the classifications @samp{B} and |
| | 1067 | @samp{C}. @samp{B} patterns are used for finding cutting points, |
| 1068 | 1068 | where amalgamation should not be performed, @samp{C} patterns are used for |
| 1069 | | finding existing connections, over which amalgamation is to be done, and |
| 1070 | | @samp{e} patterns are used for modifying eye spaces and reevaluating lunches. |
| | 1069 | finding existing connections, over which amalgamation is to be done. |
| 1071 | 1070 | There are also some patterns without classification, which use action lines to |
| 1072 | 1071 | have an impact. These are matched together with the @samp{C} patterns. Further |
| 1073 | 1072 | details and examples can be found in @xref{Worms and Dragons}. |
| … |
… |
|
| 1181 | 1180 | @findex find_connections |
| 1182 | 1181 | @quotation |
| 1183 | 1182 | Find explicit connection patterns and amalgamate the involved dragons. |
| 1184 | | This goes through the connection database consulting patterns except those of |
| 1185 | | type B, E or e. When such a function is found, the function |
| | 1183 | This goes through the connection database consulting only patterns of type C. |
| | 1184 | When such a function is found, the function |
| 1186 | 1185 | @code{cut_connect_callback} is invoked. |
| 1187 | 1186 | @end quotation |
| 1188 | | @item void modify_eye_spaces1(void) |
| 1189 | | @findex modify_eye_spaces1 |
| 1190 | | @quotation |
| 1191 | | Find explicit connection patterns and amalgamate the involved dragons. |
| 1192 | | This goes through the connection database consulting only patterns |
| 1193 | | of type E (@pxref{Connections Database}). When such a function is found, the |
| 1194 | | function @code{cut_connect_callback} is invoked. |
| 1195 | | @end quotation |
| 1196 | | @item void modify_eye_spaces1(void) |
| 1197 | | @findex modify_eye_spaces1 |
| 1198 | | @quotation |
| 1199 | | Find explicit connection patterns and amalgamate the involved dragons. |
| 1200 | | This goes through the connection database consulting only patterns |
| 1201 | | of type e (@pxref{Connections Database}). When such a function is found, the |
| 1202 | | function @code{cut_connect_callback} is invoked. |
| 1203 | | @end quotation |
| 1204 | 1187 | @end itemize |
| 1205 | 1188 | |
| 1206 | 1189 | @node Tuning |
diff -N -r -u -X .ignore gnugo-copy/doc/reading.texi gnugo/doc/reading.texi
|
old
|
new
|
|
| 66 | 66 | |
| 67 | 67 | The function @code{do_attack} and @code{do_find_defense} are wrappers |
| 68 | 68 | themselves and call @code{attack1}, @code{attack2}, @code{attack3} or |
| 69 | | @code{attack4} resp. @code{defend1}, @code{defend1}, @code{defend1} |
| 70 | | or @code{defend1} depending on the number of liberties. |
| | 69 | @code{attack4} resp. @code{defend1}, @code{defend2}, @code{defend3} |
| | 70 | or @code{defend4} depending on the number of liberties. |
| 71 | 71 | |
| 72 | 72 | These are fine-tuned to generate and try out the moves in an efficient |
| 73 | 73 | order. They generate a few moves themselves (mostly direct liberties |
| … |
… |
|
| 123 | 123 | 3 liberties are considered, but branching is inhibited, so fewer |
| 124 | 124 | variations are considered. |
| 125 | 125 | |
| 126 | | %@findex small_semeai |
| 127 | | %Currently the reading code does not try to defend a string by |
| 128 | | %attacking a boundary string with more than two liberties. Because |
| 129 | | %of this restriction, it can make oversights. A symptom of this is |
| 130 | | %two adjacent strings, each having three or four liberties, each |
| 131 | | %classified as @code{DEAD}. To resolve such situations, a function |
| 132 | | %@code{small_semeai()} (in @file{engine/semeai.c}) looks for such |
| 133 | | %pairs of strings and corrects their classification. |
| 134 | | |
| 135 | 126 | The @code{backfill_depth} is a similar variable with a default 12. Below |
| 136 | 127 | this depth, GNU Go will try "backfilling" to capture stones. |
| 137 | 128 | For example in this situation: |
| … |
… |
|
| 173 | 164 | be attacked, and if so, @code{*move} returns the attacking move, |
| 174 | 165 | unless @code{*movei} is a null pointer. (Use null pointers if |
| 175 | 166 | you are interested in the result of the attack but not the |
| 176 | | attacking move itself.) Returns @code{WIN}, if the attack succeeds, |
| 177 | | 0 if it fails, and @code{KO_A} or @code{KO_B} if the result depends on ko |
| 178 | | @ref{Return Codes}. |
| | 167 | attacking move itself.) Returns a result code of the move |
| | 168 | @xref{Return Codes}. |
| 179 | 169 | @end quotation |
| 180 | 170 | @findex find_defense |
| 181 | 171 | @item @code{find_defense(int str, int *move)} |
| 182 | 172 | @quotation |
| 183 | | Attempts to find a move that will save the string at @code{str}. It |
| 184 | | returns true if such a move is found, with @code{*move} the location |
| | 173 | Attempts to find a move that will save the string at @code{str}, and if |
| | 174 | so, @code{*move} returns the location |
| 185 | 175 | of the saving move (unless @code{*move} is a null pointer). It is not |
| 186 | 176 | checked that tenuki defends, so this may give an erroneous answer if |
| 187 | | @code{!attack(str)}. Returns @code{KO_A} or @code{KO_B} if the |
| 188 | | result depends on ko @xref{Return Codes}. |
| | 177 | @code{!attack(str)}. Returns a result code of the move |
| | 178 | @xref{Return Codes}. |
| 189 | 179 | @end quotation |
| 190 | 180 | @findex safe_move |
| 191 | 181 | @item @code{safe_move(int str, int color)} : |
| 192 | 182 | @quotation |
| 193 | 183 | The function @code{safe_move(str, color)} checks whether a move at |
| 194 | 184 | @code{str} is illegal or can immediately be captured. If @code{stackp==0} |
| 195 | | the result is cached. If the move only can be captured by a ko, it's |
| 196 | | considered safe. This may or may not be a good convention. |
| | 185 | the result is cached. Returns a result code of an attack on the placed |
| | 186 | stone. |
| 197 | 187 | @end quotation |
| 198 | 188 | @end itemize |
| 199 | 189 | |
| … |
… |
|
| 388 | 378 | Some calculations can be safely saved from move to move. If the |
| 389 | 379 | opponent's move is not close to our worm or dragon, we do not have to |
| 390 | 380 | reconsider the life or death of that group on the next move. So |
| 391 | | the result is saved in a persistent cache. Persistent caches are used for |
| | 381 | the result is saved in a persistent cache. Persistent caches |
| 392 | 382 | are used in the engine for several types of read results. |
| 393 | 383 | |
| 394 | 384 | @itemize @bullet |
diff -N -r -u -X .ignore gnugo-copy/engine/board.c gnugo/engine/board.c
|
old
|
new
|
|
| 222 | 222 | */ |
| 223 | 223 | |
| 224 | 224 | #define LIBERTY(pos) \ |
| 225 | | (board[pos] == EMPTY) |
| | 225 | (!board[pos]) |
| 226 | 226 | |
| 227 | 227 | #define UNMARKED_LIBERTY(pos) \ |
| 228 | | (board[pos] == EMPTY && ml[pos] != liberty_mark) |
| | 228 | (!board[pos] && ml[pos] != liberty_mark) |
| 229 | 229 | |
| 230 | 230 | #define MARK_LIBERTY(pos) \ |
| 231 | 231 | ml[pos] = liberty_mark |
| … |
… |
|
| 683 | 683 | /* 1. The color must be BLACK or WHITE. */ |
| 684 | 684 | gg_assert(color == BLACK || color == WHITE); |
| 685 | 685 | |
| 686 | | if (pos != PASS_MOVE) { |
| | 686 | if (pos) { |
| 687 | 687 | /* 2. Unless pass, the move must be inside the board. */ |
| 688 | 688 | ASSERT_ON_BOARD1(pos); |
| 689 | 689 | |
| … |
… |
|
| 691 | 691 | shadow[pos] = 1; |
| 692 | 692 | |
| 693 | 693 | /* 3. The location must be empty. */ |
| 694 | | if (board[pos] != EMPTY) |
| | 694 | if (board[pos]) |
| 695 | 695 | return 0; |
| 696 | 696 | |
| 697 | 697 | /* 4. Test if the location is the ko point. */ |
| … |
… |
|
| 838 | 838 | * undone stones */ |
| 839 | 839 | memcpy(&board_hash_stack[stackp], &board_hash, sizeof(board_hash)); |
| 840 | 840 | |
| 841 | | if (board_ko_pos != NO_MOVE) |
| | 841 | if (board_ko_pos) |
| 842 | 842 | hashdata_invert_ko(&board_hash, board_ko_pos); |
| 843 | 843 | |
| 844 | 844 | board_ko_pos = NO_MOVE; |
| 845 | 845 | |
| 846 | 846 | stackp++; |
| 847 | 847 | |
| 848 | | if (pos != PASS_MOVE) { |
| | 848 | if (pos) { |
| 849 | 849 | PUSH_VALUE(black_captured); |
| 850 | 850 | PUSH_VALUE(white_captured); |
| 851 | 851 | do_play_move(pos, color); |
| … |
… |
|
| 864 | 864 | /* 1. The color must be BLACK or WHITE. */ |
| 865 | 865 | gg_assert(color == BLACK || color == WHITE); |
| 866 | 866 | |
| 867 | | if (pos != PASS_MOVE) { |
| | 867 | if (pos) { |
| 868 | 868 | /* 2. Unless pass, the move must be inside the board. */ |
| 869 | 869 | ASSERT_ON_BOARD1(pos); |
| 870 | 870 | |
| … |
… |
|
| 872 | 872 | shadow[pos] = 1; |
| 873 | 873 | |
| 874 | 874 | /* 3. The location must be empty. */ |
| 875 | | if (board[pos] != EMPTY) |
| | 875 | if (board[pos]) |
| 876 | 876 | return 0; |
| 877 | 877 | |
| 878 | 878 | /* 4. The location must not be the ko point, unless ignore_ko == 1. */ |
| … |
… |
|
| 1049 | 1049 | { |
| 1050 | 1050 | ASSERT1(stackp == 0, pos); |
| 1051 | 1051 | ASSERT_ON_BOARD1(pos); |
| 1052 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 1052 | ASSERT1(!board[pos], pos); |
| 1053 | 1053 | |
| 1054 | 1054 | board[pos] = color; |
| 1055 | 1055 | hashdata_invert_stone(&board_hash, pos, color); |
| … |
… |
|
| 1094 | 1094 | gg_assert(hashdata_is_equal(oldkey, board_hash)); |
| 1095 | 1095 | #endif |
| 1096 | 1096 | |
| 1097 | | if (board_ko_pos != NO_MOVE) |
| | 1097 | if (board_ko_pos) |
| 1098 | 1098 | hashdata_invert_ko(&board_hash, board_ko_pos); |
| 1099 | 1099 | board_ko_pos = NO_MOVE; |
| 1100 | 1100 | |
| 1101 | 1101 | /* If the move is a pass, we can skip some steps. */ |
| 1102 | | if (pos != PASS_MOVE) { |
| | 1102 | if (pos) { |
| 1103 | 1103 | ASSERT_ON_BOARD1(pos); |
| 1104 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 1104 | ASSERT1(!board[pos], pos); |
| 1105 | 1105 | |
| 1106 | 1106 | /* Do play the move. */ |
| 1107 | 1107 | if (!is_suicide(pos, color)) |
| … |
… |
|
| 1159 | 1159 | { |
| 1160 | 1160 | ASSERT1(stackp == 0, pos); |
| 1161 | 1161 | ASSERT1(color == WHITE || color == BLACK, pos); |
| 1162 | | ASSERT1(pos == PASS_MOVE || ON_BOARD1(pos), pos); |
| 1163 | | ASSERT1(pos == PASS_MOVE || board[pos] == EMPTY, pos); |
| 1164 | | ASSERT1(komaster == EMPTY && kom_pos == NO_MOVE, pos); |
| | 1162 | ASSERT1(!pos || ON_BOARD1(pos), pos); |
| | 1163 | ASSERT1(!pos || !board[pos], pos); |
| | 1164 | ASSERT1(!komaster && !kom_pos, pos); |
| 1165 | 1165 | |
| 1166 | 1166 | if (move_history_pointer >= MAX_MOVE_HISTORY) { |
| 1167 | 1167 | /* The move history is full. We resolve this by collapsing the |
| … |
… |
|
| 1199 | 1199 | move_history_color[move_history_pointer] = color; |
| 1200 | 1200 | move_history_pos[move_history_pointer] = pos; |
| 1201 | 1201 | move_history_hash[move_history_pointer] = board_hash; |
| 1202 | | if (board_ko_pos != NO_MOVE) |
| | 1202 | if (board_ko_pos) |
| 1203 | 1203 | hashdata_invert_ko(&move_history_hash[move_history_pointer], board_ko_pos); |
| 1204 | 1204 | move_history_pointer++; |
| 1205 | 1205 | |
| … |
… |
|
| 1251 | 1251 | int |
| 1252 | 1252 | get_last_move() |
| 1253 | 1253 | { |
| 1254 | | if (move_history_pointer == 0) |
| | 1254 | if (!move_history_pointer) |
| 1255 | 1255 | return PASS_MOVE; |
| 1256 | 1256 | |
| 1257 | 1257 | return move_history_pos[move_history_pointer - 1]; |
| … |
… |
|
| 1263 | 1263 | int |
| 1264 | 1264 | get_last_player() |
| 1265 | 1265 | { |
| 1266 | | if (move_history_pointer == 0) |
| | 1266 | if (!move_history_pointer) |
| 1267 | 1267 | return EMPTY; |
| 1268 | 1268 | |
| 1269 | 1269 | return move_history_color[move_history_pointer - 1]; |
| … |
… |
|
| 1282 | 1282 | int |
| 1283 | 1283 | is_pass(int pos) |
| 1284 | 1284 | { |
| 1285 | | return pos == PASS_MOVE; |
| | 1285 | return !pos; |
| 1286 | 1286 | } |
| 1287 | 1287 | |
| 1288 | 1288 | |
| … |
… |
|
| 1300 | 1300 | is_legal(int pos, int color) |
| 1301 | 1301 | { |
| 1302 | 1302 | /* 0. A pass move is always legal. */ |
| 1303 | | if (pos == PASS_MOVE) |
| | 1303 | if (!pos) |
| 1304 | 1304 | return 1; |
| 1305 | 1305 | |
| 1306 | 1306 | /* 1. The move must be inside the board. */ |
| 1307 | 1307 | ASSERT_ON_BOARD1(pos); |
| 1308 | 1308 | |
| 1309 | 1309 | /* 2. The location must be empty. */ |
| 1310 | | if (board[pos] != EMPTY) |
| | 1310 | if (board[pos]) |
| 1311 | 1311 | return 0; |
| 1312 | 1312 | |
| 1313 | 1313 | /* 3. The location must not be the ko point. */ |
| … |
… |
|
| 1357 | 1357 | int checked_pos; |
| 1358 | 1358 | int stone; |
| 1359 | 1359 | ASSERT_ON_BOARD1(pos); |
| 1360 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 1360 | ASSERT1(!board[pos], pos); |
| 1361 | 1361 | |
| 1362 | 1362 | /* Check for suicide. */ |
| 1363 | 1363 | checked_pos = SOUTH(pos); |
| 1364 | 1364 | stone = board[checked_pos]; |
| 1365 | | if (stone == EMPTY |
| | 1365 | if (!stone |
| 1366 | 1366 | || (ON_BOARD(checked_pos) |
| 1367 | 1367 | && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1)))) |
| 1368 | 1368 | return 0; |
| 1369 | 1369 | |
| 1370 | 1370 | checked_pos = WEST(pos); |
| 1371 | 1371 | stone = board[checked_pos]; |
| 1372 | | if (stone == EMPTY |
| | 1372 | if (!stone |
| 1373 | 1373 | || (ON_BOARD(checked_pos) |
| 1374 | 1374 | && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1)))) |
| 1375 | 1375 | return 0; |
| 1376 | 1376 | |
| 1377 | 1377 | checked_pos = NORTH(pos); |
| 1378 | 1378 | stone = board[checked_pos]; |
| 1379 | | if (stone == EMPTY |
| | 1379 | if (!stone |
| 1380 | 1380 | || (ON_BOARD(checked_pos) |
| 1381 | 1381 | && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1)))) |
| 1382 | 1382 | return 0; |
| 1383 | 1383 | |
| 1384 | 1384 | checked_pos = EAST(pos); |
| 1385 | 1385 | stone = board[checked_pos]; |
| 1386 | | if (stone == EMPTY |
| | 1386 | if (!stone |
| 1387 | 1387 | || (ON_BOARD(checked_pos) |
| 1388 | 1388 | && ((stone == color) ^ (LIBERTIES(string_number[checked_pos]) == 1)))) |
| 1389 | 1389 | return 0; |
| … |
… |
|
| 1400 | 1400 | is_illegal_ko_capture(int pos, int color) |
| 1401 | 1401 | { |
| 1402 | 1402 | ASSERT_ON_BOARD1(pos); |
| 1403 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 1403 | ASSERT1(!board[pos], pos); |
| 1404 | 1404 | |
| 1405 | 1405 | return (pos == board_ko_pos |
| 1406 | 1406 | /* The ko position is guaranteed to have all neighbors of the |
| … |
… |
|
| 1426 | 1426 | gg_assert(stackp == 0); |
| 1427 | 1427 | |
| 1428 | 1428 | /* 1. A pass move is always legal, no matter what. */ |
| 1429 | | if (pos == PASS_MOVE) |
| | 1429 | if (!pos) |
| 1430 | 1430 | return 1; |
| 1431 | 1431 | |
| 1432 | 1432 | /* 2. The move must be inside the board. */ |
| 1433 | 1433 | ASSERT_ON_BOARD1(pos); |
| 1434 | 1434 | |
| 1435 | 1435 | /* 3. The location must be empty. */ |
| 1436 | | if (board[pos] != EMPTY) |
| | 1436 | if (board[pos]) |
| 1437 | 1437 | return 0; |
| 1438 | 1438 | |
| 1439 | 1439 | /* 4. Simple ko repetition is only allowed if no ko rule is in use. |
| … |
… |
|
| 1612 | 1612 | *is_conditional_ko = 1; |
| 1613 | 1613 | |
| 1614 | 1614 | /* Conditional ko capture, set komaster parameters (1b and 5c). */ |
| 1615 | | if (komaster == EMPTY || komaster == WEAK_KO) { |
| | 1615 | if (!komaster || komaster == WEAK_KO) { |
| 1616 | 1616 | set_new_komaster(color); |
| 1617 | 1617 | set_new_kom_pos(kpos); |
| 1618 | 1618 | return 1; |
| … |
… |
|
| 1631 | 1631 | || (komaster == GRAY_WHITE && color == WHITE) |
| 1632 | 1632 | || (komaster == GRAY_BLACK && color == BLACK)) |
| 1633 | 1633 | && (board[kom_pos] == color |
| 1634 | | || (board[kom_pos] == EMPTY |
| | 1634 | || (!board[kom_pos] |
| 1635 | 1635 | && is_suicide(kom_pos, OTHER_COLOR(color))))) { |
| 1636 | 1636 | set_new_komaster(EMPTY); |
| 1637 | 1637 | set_new_kom_pos(NO_MOVE); |
| … |
… |
|
| 1660 | 1660 | /* We can reach here when komaster is EMPTY or WEAK_KO. If previous |
| 1661 | 1661 | * move was also a ko capture, we now set komaster to WEAK_KO (1a and 5b). |
| 1662 | 1662 | */ |
| 1663 | | if (previous_board_ko_pos != NO_MOVE) { |
| | 1663 | if (previous_board_ko_pos) { |
| 1664 | 1664 | set_new_komaster(WEAK_KO); |
| 1665 | 1665 | set_new_kom_pos(previous_board_ko_pos); |
| 1666 | 1666 | } |
| … |
… |
|
| 1724 | 1724 | int |
| 1725 | 1725 | are_neighbors(int pos1, int pos2) |
| 1726 | 1726 | { |
| 1727 | | if (board[pos1] == EMPTY) { |
| 1728 | | if (board[pos2] == EMPTY) |
| | 1727 | if (!board[pos1]) { |
| | 1728 | if (!board[pos2]) |
| 1729 | 1729 | return (gg_abs(pos1 - pos2) == NS || gg_abs(pos1 - pos2) == WE); |
| 1730 | 1730 | else |
| 1731 | 1731 | return neighbor_of_string(pos1, pos2); |
| 1732 | 1732 | } |
| 1733 | 1733 | else { |
| 1734 | | if (board[pos2] == EMPTY) |
| | 1734 | if (!board[pos2]) |
| 1735 | 1735 | return neighbor_of_string(pos2, pos1); |
| 1736 | 1736 | else |
| 1737 | 1737 | return adjacent_strings(pos1, pos2); |
| … |
… |
|
| 1768 | 1768 | int str_nr; |
| 1769 | 1769 | |
| 1770 | 1770 | ASSERT1(IS_STONE(board[str_pos]), str_pos); |
| 1771 | | ASSERT1(libs != NULL, str_pos); |
| | 1771 | ASSERT1(libs, str_pos); |
| 1772 | 1772 | |
| 1773 | 1773 | /* We already have the list of liberties and only need to copy it to |
| 1774 | 1774 | * libs[]. |
| … |
… |
|
| 1863 | 1863 | int checked_pos; |
| 1864 | 1864 | int str_nr; |
| 1865 | 1865 | |
| 1866 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 1866 | ASSERT1(!board[pos], pos); |
| 1867 | 1867 | ASSERT1(IS_STONE(color), pos); |
| 1868 | 1868 | |
| 1869 | 1869 | /* Find neighboring strings of the same color. If there are more than two of |
| … |
… |
|
| 2045 | 2045 | |
| 2046 | 2046 | struct board_cache_entry *entry = &approxlib_cache[pos][color - WHITE]; |
| 2047 | 2047 | |
| 2048 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 2048 | ASSERT1(!board[pos], pos); |
| 2049 | 2049 | ASSERT1(IS_STONE(color), pos); |
| 2050 | 2050 | |
| 2051 | 2051 | if (!libs) { |
| … |
… |
|
| 2086 | 2086 | |
| 2087 | 2087 | #else /* not USE_BOARD_CACHES */ |
| 2088 | 2088 | |
| 2089 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 2089 | ASSERT1(!board[pos], pos); |
| 2090 | 2090 | ASSERT1(IS_STONE(color), pos); |
| 2091 | 2091 | |
| 2092 | 2092 | if (!libs) { |
| … |
… |
|
| 2130 | 2130 | MARK_LIBERTY(pos); |
| 2131 | 2131 | |
| 2132 | 2132 | checked_pos = SOUTH(pos); |
| 2133 | | if (board[checked_pos] == EMPTY) { |
| | 2133 | if (!board[checked_pos]) { |
| 2134 | 2134 | if (ml[checked_pos] != liberty_mark) { |
| 2135 | | if (libs != NULL) |
| | 2135 | if (libs) |
| 2136 | 2136 | libs[liberties] = checked_pos; |
| 2137 | 2137 | liberties++; |
| 2138 | 2138 | /* Stop counting if we reach maxlib. */ |
| … |
… |
|
| 2147 | 2147 | last_lib = cur_lib + string[str_nr].liberties; |
| 2148 | 2148 | for (; cur_lib < last_lib; cur_lib++) { |
| 2149 | 2149 | if (UNMARKED_LIBERTY(*cur_lib)) { |
| 2150 | | if (libs != NULL) |
| | 2150 | if (libs) |
| 2151 | 2151 | libs[liberties] = *cur_lib; |
| 2152 | 2152 | liberties++; |
| 2153 | 2153 | if (liberties >= maxlib) |
| … |
… |
|
| 2158 | 2158 | } |
| 2159 | 2159 | |
| 2160 | 2160 | checked_pos = WEST(pos); |
| 2161 | | if (board[checked_pos] == EMPTY) { |
| | 2161 | if (!board[checked_pos]) { |
| 2162 | 2162 | if (ml[checked_pos] != liberty_mark) { |
| 2163 | | if (libs != NULL) |
| | 2163 | if (libs) |
| 2164 | 2164 | libs[liberties] = checked_pos; |
| 2165 | 2165 | liberties++; |
| 2166 | 2166 | /* Stop counting if we reach maxlib. */ |
| … |
… |
|
| 2175 | 2175 | last_lib = cur_lib + string[str_nr].liberties; |
| 2176 | 2176 | for (; cur_lib < last_lib; cur_lib++) { |
| 2177 | 2177 | if (UNMARKED_LIBERTY(*cur_lib)) { |
| 2178 | | if (libs != NULL) |
| | 2178 | if (libs) |
| 2179 | 2179 | libs[liberties] = *cur_lib; |
| 2180 | 2180 | liberties++; |
| 2181 | 2181 | if (liberties >= maxlib) |
| … |
… |
|
| 2186 | 2186 | } |
| 2187 | 2187 | |
| 2188 | 2188 | checked_pos = NORTH(pos); |
| 2189 | | if (board[checked_pos] == EMPTY) { |
| | 2189 | if (!board[checked_pos]) { |
| 2190 | 2190 | if (ml[checked_pos] != liberty_mark) { |
| 2191 | | if (libs != NULL) |
| | 2191 | if (libs) |
| 2192 | 2192 | libs[liberties] = checked_pos; |
| 2193 | 2193 | liberties++; |
| 2194 | 2194 | /* Stop counting if we reach maxlib. */ |
| … |
… |
|
| 2203 | 2203 | last_lib = cur_lib + string[str_nr].liberties; |
| 2204 | 2204 | for (; cur_lib < last_lib; cur_lib++) { |
| 2205 | 2205 | if (UNMARKED_LIBERTY(*cur_lib)) { |
| 2206 | | if (libs != NULL) |
| | 2206 | if (libs) |
| 2207 | 2207 | libs[liberties] = *cur_lib; |
| 2208 | 2208 | liberties++; |
| 2209 | 2209 | if (liberties >= maxlib) |
| … |
… |
|
| 2214 | 2214 | } |
| 2215 | 2215 | |
| 2216 | 2216 | checked_pos = EAST(pos); |
| 2217 | | if (board[checked_pos] == EMPTY) { |
| | 2217 | if (!board[checked_pos]) { |
| 2218 | 2218 | if (ml[checked_pos] != liberty_mark) { |
| 2219 | | if (libs != NULL) |
| | 2219 | if (libs) |
| 2220 | 2220 | libs[liberties] = checked_pos; |
| 2221 | 2221 | liberties++; |
| 2222 | 2222 | /* Unneeded since we're about to leave. */ |
| … |
… |
|
| 2233 | 2233 | last_lib = cur_lib + string[str_nr].liberties; |
| 2234 | 2234 | for (; cur_lib < last_lib; cur_lib++) { |
| 2235 | 2235 | if (UNMARKED_LIBERTY(*cur_lib)) { |
| 2236 | | if (libs != NULL) |
| | 2236 | if (libs) |
| 2237 | 2237 | libs[liberties] = *cur_lib; |
| 2238 | 2238 | liberties++; |
| 2239 | 2239 | if (liberties >= maxlib) |
| … |
… |
|
| 2275 | 2275 | |
| 2276 | 2276 | for (delta_o = delta; delta_o < last_delta_4; delta_o++) { |
| 2277 | 2277 | checked_pos = pos + *delta_o; |
| 2278 | | if (board[checked_pos] == EMPTY) { |
| | 2278 | if (!board[checked_pos]) { |
| 2279 | 2279 | if (ml[checked_pos] != liberty_mark) { |
| 2280 | 2280 | if (libs) |
| 2281 | 2281 | libs[liberties] = checked_pos; |
| … |
… |
|
| 2359 | 2359 | |
| 2360 | 2360 | struct board_cache_entry *entry = &accuratelib_cache[pos][color - WHITE]; |
| 2361 | 2361 | |
| 2362 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 2362 | ASSERT1(!board[pos], pos); |
| 2363 | 2363 | ASSERT1(IS_STONE(color), pos); |
| 2364 | 2364 | |
| 2365 | 2365 | if (!libs) { |
| … |
… |
|
| 2396 | 2396 | |
| 2397 | 2397 | #else /* not USE_BOARD_CACHES */ |
| 2398 | 2398 | |
| 2399 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 2399 | ASSERT1(!board[pos], pos); |
| 2400 | 2400 | ASSERT1(IS_STONE(color), pos); |
| 2401 | 2401 | |
| 2402 | 2402 | if (!libs) { |
| … |
… |
|
| 2434 | 2434 | |
| 2435 | 2435 | for (act_delta = delta; act_delta < last_delta_4; act_delta++) { |
| 2436 | 2436 | int checked_pos = pos + *act_delta; |
| 2437 | | if (board[checked_pos] == EMPTY) { |
| | 2437 | if (!board[checked_pos]) { |
| 2438 | 2438 | if (ml[checked_pos] != liberty_mark) { |
| 2439 | 2439 | /* A trivial liberty */ |
| 2440 | 2440 | if (libs) |
| … |
… |
|
| 2609 | 2609 | int |
| 2610 | 2610 | count_common_libs(int str1_pos, int str2_pos) |
| 2611 | 2611 | { |
| 2612 | | int all_libs1[MAXLIBS], *libs1; |
| 2613 | | int *last_lib; |
| | 2612 | static int all_libs1[MAXLIBS]; |
| | 2613 | int *last_lib, *libs1; |
| 2614 | 2614 | int liberties1, liberties2; |
| 2615 | 2615 | int str1_nr, str2_nr; |
| 2616 | 2616 | int commonlibs = 0; |
| … |
… |
|
| 2683 | 2683 | int |
| 2684 | 2684 | find_common_libs(int str1_pos, int str2_pos, int maxlib, int *libs) |
| 2685 | 2685 | { |
| 2686 | | int all_libs1[MAXLIBS], *libs1; |
| 2687 | | int *last_lib; |
| | 2686 | static int all_libs1[MAXLIBS]; |
| | 2687 | int *last_lib, *libs1; |
| 2688 | 2688 | int liberties1, liberties2; |
| 2689 | 2689 | int str1_nr, str2_nr; |
| 2690 | 2690 | int commonlibs = 0; |
| … |
… |
|
| 2694 | 2694 | ASSERT_ON_BOARD1(str2_pos); |
| 2695 | 2695 | ASSERT1(IS_STONE(board[str1_pos]), str1_pos); |
| 2696 | 2696 | ASSERT1(IS_STONE(board[str2_pos]), str2_pos); |
| 2697 | | ASSERT1(libs != NULL, str1_pos); |
| | 2697 | ASSERT1(libs, str1_pos); |
| 2698 | 2698 | |
| 2699 | 2699 | str1_nr = string_number[str1_pos]; |
| 2700 | 2700 | str2_nr = string_number[str2_pos]; |
| … |
… |
|
| 2759 | 2759 | int |
| 2760 | 2760 | have_common_lib(int str1_pos, int str2_pos, int *lib) |
| 2761 | 2761 | { |
| 2762 | | int all_libs1[MAXLIBS], *libs1; |
| 2763 | | int *last_lib; |
| | 2762 | static int all_libs1[MAXLIBS]; |
| | 2763 | int *last_lib, *libs1; |
| 2764 | 2764 | int liberties1, liberties2; |
| 2765 | 2765 | int str1_nr, str2_nr; |
| 2766 | 2766 | int color; |
| … |
… |
|
| 2984 | 2984 | extended_chainlinks(int str_pos, int adj[MAXCHAIN], int both_colors) |
| 2985 | 2985 | { |
| 2986 | 2986 | int *cur_neighbor, *last_neigbor; |
| 2987 | | int libs[MAXLIBS]; |
| | 2987 | static int libs[MAXLIBS]; |
| 2988 | 2988 | int *cur_lib, *last_lib; |
| 2989 | 2989 | int checked_pos; |
| 2990 | 2990 | int color; |
| … |
… |
|
| 3104 | 3104 | int liberties; |
| 3105 | 3105 | |
| 3106 | 3106 | ASSERT_ON_BOARD1(pos); |
| 3107 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 3107 | ASSERT1(!board[pos], pos); |
| 3108 | 3108 | ASSERT1(IS_STONE(color), pos); |
| 3109 | 3109 | |
| 3110 | 3110 | /* 1. Try first to solve the problem without much work. */ |
| … |
… |
|
| 3112 | 3112 | |
| 3113 | 3113 | checked_pos = SOUTH(pos); |
| 3114 | 3114 | stone = board[checked_pos]; |
| 3115 | | if (stone == EMPTY) |
| | 3115 | if (!stone) |
| 3116 | 3116 | trivial_liberties++; |
| 3117 | 3117 | else if (stone == color) { |
| 3118 | 3118 | liberties = LIBERTIES(string_number[checked_pos]); |
| … |
… |
|
| 3131 | 3131 | |
| 3132 | 3132 | checked_pos = WEST(pos); |
| 3133 | 3133 | stone = board[checked_pos]; |
| 3134 | | if (stone == EMPTY) |
| | 3134 | if (!stone) |
| 3135 | 3135 | trivial_liberties++; |
| 3136 | 3136 | else if (stone == color) { |
| 3137 | 3137 | liberties = LIBERTIES(string_number[checked_pos]); |
| … |
… |
|
| 3150 | 3150 | |
| 3151 | 3151 | checked_pos = NORTH(pos); |
| 3152 | 3152 | stone = board[checked_pos]; |
| 3153 | | if (stone == EMPTY) |
| | 3153 | if (!stone) |
| 3154 | 3154 | trivial_liberties++; |
| 3155 | 3155 | else if (stone == color) { |
| 3156 | 3156 | liberties = LIBERTIES(string_number[checked_pos]); |
| … |
… |
|
| 3169 | 3169 | |
| 3170 | 3170 | checked_pos = EAST(pos); |
| 3171 | 3171 | stone = board[checked_pos]; |
| 3172 | | if (stone == EMPTY) |
| | 3172 | if (!stone) |
| 3173 | 3173 | trivial_liberties++; |
| 3174 | 3174 | else if (stone == color) { |
| 3175 | 3175 | liberties = LIBERTIES(string_number[checked_pos]); |
| … |
… |
|
| 3198 | 3198 | if ((far_liberties > 0) + captures >= 2) |
| 3199 | 3199 | return 0; |
| 3200 | 3200 | |
| 3201 | | if (captures == 0 && far_liberties + trivial_liberties <= 1) |
| | 3201 | if (!captures && far_liberties + trivial_liberties <= 1) |
| 3202 | 3202 | return 1; |
| 3203 | 3203 | |
| 3204 | 3204 | /* 2. It was not so easy. We use accuratelib() in this case. */ |
| … |
… |
|
| 3253 | 3253 | |
| 3254 | 3254 | ASSERT_ON_BOARD1(pos); |
| 3255 | 3255 | ASSERT_ON_BOARD1(str_pos); |
| 3256 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 3256 | ASSERT1(!board[pos], pos); |
| 3257 | 3257 | ASSERT1(IS_STONE(board[str_pos]), str_pos); |
| 3258 | 3258 | |
| 3259 | 3259 | color = board[str_pos]; |
| 3260 | 3260 | str_nr = string_number[str_pos]; |
| 3261 | 3261 | |
| 3262 | | if (board[SOUTH(pos)] == EMPTY |
| | 3262 | if (!board[SOUTH(pos)] |
| 3263 | 3263 | && NEIGHBOR_OF_STRING(SOUTH(pos), str_nr, color)) |
| 3264 | 3264 | return 1; |
| 3265 | 3265 | |
| 3266 | | if (board[EAST(pos)] == EMPTY |
| | 3266 | if (!board[EAST(pos)] |
| 3267 | 3267 | && NEIGHBOR_OF_STRING(EAST(pos), str_nr, color)) |
| 3268 | 3268 | return 1; |
| 3269 | 3269 | |
| 3270 | | if (board[NORTH(pos)] == EMPTY |
| | 3270 | if (!board[NORTH(pos)] |
| 3271 | 3271 | && NEIGHBOR_OF_STRING(NORTH(pos), str_nr, color)) |
| 3272 | 3272 | return 1; |
| 3273 | 3273 | |
| 3274 | | if (board[WEST(pos)] == EMPTY |
| | 3274 | if (!board[WEST(pos)] |
| 3275 | 3275 | && NEIGHBOR_OF_STRING(WEST(pos), str_nr, color)) |
| 3276 | 3276 | return 1; |
| 3277 | 3277 | |
| … |
… |
|
| 3490 | 3490 | { |
| 3491 | 3491 | ASSERT_ON_BOARD1(pos); |
| 3492 | 3492 | |
| 3493 | | if (board[pos] == EMPTY) { |
| | 3493 | if (!board[pos]) { |
| 3494 | 3494 | int color; |
| 3495 | 3495 | if (ON_BOARD(SOUTH(pos))) |
| 3496 | 3496 | color = board[SOUTH(pos)]; |
| … |
… |
|
| 3533 | 3533 | |
| 3534 | 3534 | this_board_hash = board_hash; |
| 3535 | 3535 | |
| 3536 | | if (board_ko_pos != NO_MOVE) |
| | 3536 | if (board_ko_pos) |
| 3537 | 3537 | hashdata_invert_ko(&this_board_hash, board_ko_pos); |
| 3538 | 3538 | |
| 3539 | 3539 | really_do_trymove(pos, color); |
| 3540 | 3540 | new_board_hash = board_hash; |
| 3541 | | if (board_ko_pos != NO_MOVE) |
| | 3541 | if (board_ko_pos) |
| 3542 | 3542 | hashdata_invert_ko(&new_board_hash, board_ko_pos); |
| 3543 | 3543 | undo_trymove(); |
| 3544 | 3544 | |
| … |
… |
|
| 3564 | 3564 | { |
| 3565 | 3565 | int other = OTHER_COLOR(color); |
| 3566 | 3566 | |
| 3567 | | ASSERT1(board[pos] == EMPTY, pos); |
| | 3567 | ASSERT1(!board[pos], pos); |
| 3568 | 3568 | |
| 3569 | 3569 | if (board[SOUTH(pos)] == other && LIBERTIES(string_number[SOUTH(pos)]) == 1) |
| 3570 | 3570 | return 1; |
| … |
… |
|
| 3754 | 3754 | for (pos = BOARDMIN; pos < BOARDMAX; pos++) { |
| 3755 | 3755 | if (!ON_BOARD(pos)) |
| 3756 | 3756 | continue; |
| 3757 | | if (board[pos] == EMPTY) |
| | 3757 | if (!board[pos]) |
| 3758 | 3758 | fprintf(stderr, " . "); |
| 3759 | 3759 | else |
| 3760 | 3760 | fprintf(stderr, "%2d ", string_number[pos]); |
| … |
… |
|
| 3766 | 3766 | } |
| 3767 | 3767 | |
| 3768 | 3768 | for (s = 0; s < next_string; s++) { |
| 3769 | | if (board[string[s].origin] == EMPTY) |
| | 3769 | if (!board[string[s].origin]) |
| 3770 | 3770 | continue; |
| 3771 | 3771 | |
| 3772 | 3772 | gprintf("%o%d %s %1m size %d, %d liberties, %d neighbors\n", s, |
| … |
… |
|
| 3858 | 3858 | * already visited liberties and neighbors. |
| 3859 | 3859 | */ |
| 3860 | 3860 | checked_pos = SOUTH(pos); |
| 3861 | | if (board[checked_pos] == EMPTY) { |
| | 3861 | if (!board[checked_pos]) { |
| 3862 | 3862 | if (ml[checked_pos] != liberty_mark) { |
| 3863 | 3863 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| 3864 | 3864 | } |
| … |
… |
|
| 3872 | 3872 | } |
| 3873 | 3873 | |
| 3874 | 3874 | checked_pos = WEST(pos); |
| 3875 | | if (board[checked_pos] == EMPTY) { |
| | 3875 | if (!board[checked_pos]) { |
| 3876 | 3876 | if (ml[checked_pos] != liberty_mark) { |
| 3877 | 3877 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| 3878 | 3878 | } |
| … |
… |
|
| 3886 | 3886 | } |
| 3887 | 3887 | |
| 3888 | 3888 | checked_pos = NORTH(pos); |
| 3889 | | if (board[checked_pos] == EMPTY) { |
| | 3889 | if (!board[checked_pos]) { |
| 3890 | 3890 | if (ml[checked_pos] != liberty_mark) { |
| 3891 | 3891 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| 3892 | 3892 | } |
| … |
… |
|
| 3900 | 3900 | } |
| 3901 | 3901 | |
| 3902 | 3902 | checked_pos = EAST(pos); |
| 3903 | | if (board[checked_pos] == EMPTY) { |
| | 3903 | if (!board[checked_pos]) { |
| 3904 | 3904 | if (ml[checked_pos] != liberty_mark) { |
| 3905 | 3905 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| 3906 | 3906 | } |
| … |
… |
|
| 4481 | 4481 | */ |
| 4482 | 4482 | checked_pos = SOUTH(pos); |
| 4483 | 4483 | stone = board[checked_pos]; |
| 4484 | | if (stone == EMPTY) { |
| | 4484 | if (!stone) { |
| 4485 | 4485 | if (ml[checked_pos] != liberty_mark) |
| 4486 | 4486 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| 4487 | 4487 | } |
| … |
… |
|
| 4501 | 4501 | |
| 4502 | 4502 | checked_pos = WEST(pos); |
| 4503 | 4503 | stone = board[checked_pos]; |
| 4504 | | if (stone == EMPTY) { |
| | 4504 | if (!stone) { |
| 4505 | 4505 | if (ml[checked_pos] != liberty_mark) |
| 4506 | 4506 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| 4507 | 4507 | } |
| … |
… |
|
| 4521 | 4521 | |
| 4522 | 4522 | checked_pos = NORTH(pos); |
| 4523 | 4523 | stone = board[checked_pos]; |
| 4524 | | if (stone == EMPTY) { |
| | 4524 | if (!stone) { |
| 4525 | 4525 | if (ml[checked_pos] != liberty_mark) |
| 4526 | 4526 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| 4527 | 4527 | } |
| … |
… |
|
| 4541 | 4541 | |
| 4542 | 4542 | checked_pos = EAST(pos); |
| 4543 | 4543 | stone = board[checked_pos]; |
| 4544 | | if (stone == EMPTY) { |
| | 4544 | if (!stone) { |
| 4545 | 4545 | if (ml[checked_pos] != liberty_mark) |
| 4546 | 4546 | #if 0 |
| 4547 | 4547 | ADD_AND_MARK_LIBERTY(str_nr, checked_pos); |
| … |
… |
|
| 4709 | 4709 | } |
| 4710 | 4710 | |
| 4711 | 4711 | /* Choose strategy depending on the number of friendly neighbors. */ |
| 4712 | | if (neighbor_allies == 0) |
| | 4712 | if (!neighbor_allies) |
| 4713 | 4713 | create_new_string(pos, color); |
| 4714 | 4714 | else if (neighbor_allies == 1) { |
| 4715 | 4715 | gg_assert(extend_nr >= 0); |
| … |
… |
|
| 4732 | 4732 | if (string[str_nr].liberties == 1 |
| 4733 | 4733 | && captured_stones == 1) { |
| 4734 | 4734 | /* In case of a double ko: clear old ko position first. */ |
| 4735 | | if (board_ko_pos != NO_MOVE) |
| | 4735 | if (board_ko_pos) |
| 4736 | 4736 | hashdata_invert_ko(&board_hash, board_ko_pos); |
| 4737 | 4737 | board_ko_pos = string_libs[str_nr].list[0]; |
| 4738 | 4738 | hashdata_invert_ko(&board_hash, board_ko_pos); |
| … |
… |
|
| 4772 | 4772 | pos = move + delta[k]; |
| 4773 | 4773 | if (!ON_BOARD(pos)) |
| 4774 | 4774 | (*number_edges)++; |
| 4775 | | else if (board[pos] == EMPTY) |
| | 4775 | else if (!board[pos]) |
| 4776 | 4776 | (*number_open)++; |
| 4777 | 4777 | else { |
| 4778 | 4778 | int s = string_number[pos]; |
| … |
… |
|
| 4808 | 4808 | #define code1(pos, stone) \ |
| 4809 | 4809 | if (stone == GRAY) \ |
| 4810 | 4810 | (*number_edges)++; \ |
| 4811 | | else if (stone == EMPTY) \ |
| | 4811 | else if (!stone) \ |
| 4812 | 4812 | (*number_open)++; \ |
| 4813 | 4813 | else { \ |
| 4814 | 4814 | int str_nr = string_number[pos]; \ |
diff -N -r -u -X .ignore gnugo-copy/engine/board.vcproj gnugo/engine/board.vcproj
|
old
|
new
|
|
| 200 | 200 | </FileConfiguration> |
| 201 | 201 | </File> |
| 202 | 202 | <File |
| 203 | | RelativePath="board.h" |
| 204 | | > |
| 205 | | </File> |
| 206 | | <File |
| 207 | 203 | RelativePath="boardlib.c" |
| 208 | 204 | > |
| 209 | 205 | <FileConfiguration |
| … |
… |
|
| 341 | 337 | Name="Header Files" |
| 342 | 338 | Filter="h;hpp;hxx;hm;inl" |
| 343 | 339 | > |
| | 340 | <File |
| | 341 | RelativePath="board.h" |
| | 342 | > |
| | 343 | </File> |
| | 344 | <File |
| | 345 | RelativePath="..\config.h" |
| | 346 | > |
| | 347 | </File> |
| 344 | 348 | </Filter> |
| 345 | 349 | </Files> |
| 346 | 350 | <Globals> |
diff -N -r -u -X .ignore gnugo-copy/engine/engine.vcproj gnugo/engine/engine.vcproj
|
old
|
new
|
|
| 986 | 986 | > |
| 987 | 987 | </File> |
| 988 | 988 | <File |
| | 989 | RelativePath="..\config.h" |
| | 990 | > |
| | 991 | </File> |
| | 992 | <File |
| 989 | 993 | RelativePath="gnugo.h" |
| 990 | 994 | > |
| 991 | 995 | </File> |
diff -N -r -u -X .ignore gnugo-copy/engine/genmove.c gnugo/engine/genmove.c
|
old
|
new
|
|
| 167 | 167 | return; |
| 168 | 168 | } |
| 169 | 169 | |
| 170 | | if (stones_on_board(BLACK | WHITE) != 0) { |
| 171 | | if (NEEDS_UPDATE(initial_influence_examined)) |
| 172 | | compute_worm_influence(); |
| | 170 | if (!stones_on_board(BLACK | WHITE)) { |
| | 171 | initialize_dragon_data(); |
| | 172 | compute_scores(chinese_rules || aftermath_play); |
| 173 | 173 | |
| 174 | | if (how_much == EXAMINE_INITIAL_INFLUENCE) { |
| | 174 | #ifndef GG_TURN_OFF_TRACES |
| | 175 | verbose = save_verbose; |
| | 176 | #endif |
| | 177 | |
| | 178 | gg_assert(test_gray_border() < 0); |
| 175 | 179 | |
| 176 | 180 | #ifndef GG_TURN_OFF_TRACES |
| 177 | | verbose = save_verbose; |
| | 181 | if (printworms) |
| | 182 | show_dragons(); |
| 178 | 183 | #endif |
| 179 | 184 | |
| 180 | | gg_assert(test_gray_border() < 0); |
| 181 | | return; |
| 182 | | } |
| | 185 | return; |
| | 186 | } |
| | 187 | |
| | 188 | if (NEEDS_UPDATE(initial_influence_examined)) |
| | 189 | compute_worm_influence(); |
| 183 | 190 | |
| 184 | | if (how_much == EXAMINE_DRAGONS_WITHOUT_OWL) { |
| 185 | | if (NEEDS_UPDATE(dragons_examined_without_owl)) |
| 186 | | make_dragons(1); |
| | 191 | if (how_much == EXAMINE_INITIAL_INFLUENCE) { |
| 187 | 192 | |
| 188 | 193 | #ifndef GG_TURN_OFF_TRACES |
| 189 | | verbose = save_verbose; |
| | 194 | verbose = save_verbose; |
| 190 | 195 | #endif |
| 191 | 196 | |
| 192 | | gg_assert(test_gray_border() < 0); |
| 193 | | return; |
| 194 | | } |
| 195 | | |
| 196 | | if (NEEDS_UPDATE(dragons_examined)) { |
| 197 | | make_dragons(0); |
| 198 | | compute_scores(chinese_rules || aftermath_play); |
| 199 | | /* We have automatically done a partial dragon analysis as well. */ |
| 200 | | dragons_examined_without_owl = position_number; |
| 201 | | } |
| 202 | | if (how_much == EXAMINE_DRAGONS) { |
| | 197 | gg_assert(test_gray_border() < 0); |
| | 198 | return; |
| | 199 | } |
| | 200 | |
| | 201 | if (how_much == EXAMINE_DRAGONS_WITHOUT_OWL) { |
| | 202 | if (NEEDS_UPDATE(dragons_examined_without_owl)) |
| | 203 | make_dragons(1); |
| 203 | 204 | |
| 204 | 205 | #ifndef GG_TURN_OFF_TRACES |
| 205 | | verbose = save_verbose; |
| | 206 | verbose = save_verbose; |
| 206 | 207 | #endif |
| 207 | 208 | |
| 208 | | gg_assert(test_gray_border() < 0); |
| 209 | | return; |
| 210 | | } |
| | 209 | gg_assert(test_gray_border() < 0); |
| | 210 | return; |
| 211 | 211 | } |
| 212 | | else if (how_much == EXAMINE_INITIAL_INFLUENCE |
| 213 | | || how_much == EXAMINE_DRAGONS |
| 214 | | || how_much == EXAMINE_ALL) { |
| 215 | | initialize_dragon_data(); |
| | 212 | |
| | 213 | if (NEEDS_UPDATE(dragons_examined)) { |
| | 214 | make_dragons(0); |
| 216 | 215 | compute_scores(chinese_rules || aftermath_play); |
| | 216 | /* We have automatically done a partial dragon analysis as well. */ |
| | 217 | dragons_examined_without_owl = position_number; |
| | 218 | } |
| | 219 | |
| | 220 | if (how_much == EXAMINE_DRAGONS) { |
| 217 | 221 | |
| 218 | 222 | #ifndef GG_TURN_OFF_TRACES |
| 219 | 223 | verbose = save_verbose; |
diff -N -r -u -X .ignore gnugo-copy/engine/influence.c gnugo/engine/influence.c
|
old
|
new
|
|
| 1152 | 1152 | * the -m command line option). |
| 1153 | 1153 | * |
| 1154 | 1154 | * It is assumed that color is in turn to move. (This affects the |
| 1155 | | * barrier patterns (class A, D) and intrusions (class B)). Color |
| | 1155 | * barrier patterns (class A, D) and intrusions (class B)). |
| 1156 | 1156 | */ |
| 1157 | 1157 | |
| 1158 | 1158 | void |
diff -N -r -u -X .ignore gnugo-copy/engine/liberty.h gnugo/engine/liberty.h
|
old
|
new
|
|
| 832 | 832 | |
| 833 | 833 | /* The following arrays keeps track of up to MAX_TACTICAL_POINTS |
| 834 | 834 | * different attack, defense, attack threat, and defense threat |
| 835 | | * points with corresponding result codes. (0 = loss, 1 = bad ko, 2 |
| 836 | | * = good ko, 3 = win). The arrays are guaranteed to be sorted with |
| 837 | | * respect to the codes so that the first element contains the best |
| 838 | | * result. Checked and discarded moves are stored, too. |
| | 835 | * points with corresponding result codes. The arrays are guaranteed to |
| | 836 | * be sorted with respect to the codes so that the first element contains |
| | 837 | * the best result. Checked and discarded moves are stored, too. |
| 839 | 838 | */ |
| 840 | 839 | int attack_points[MAX_TACTICAL_POINTS]; |
| 841 | 840 | int attack_codes[MAX_TACTICAL_POINTS]; |
| … |
… |
|
| 924 | 923 | enum dragon_status owl_threat_status; /* CAN_THREATEN_ATTACK/DEFENSE */ |
| 925 | 924 | enum dragon_status owl_status; /* (ALIVE, DEAD, UNKNOWN, CRITICAL, UNCHECKED) */ |
| 926 | 925 | int owl_attack_point; /* vital point for attack */ |
| 927 | | int owl_attack_code; /* ko result code */ |
| | 926 | int owl_attack_code; /* result code */ |
| 928 | 927 | int owl_attack_certain; /* 0 if owl reading node limit is reached */ |
| 929 | 928 | int owl_attack_node_count; |
| 930 | 929 | int owl_second_attack_point;/* if attacker gets both attack points, wins */ |
| 931 | 930 | int owl_defense_point; /* vital point for defense */ |
| 932 | | int owl_defense_code; /* ko result code */ |
| | 931 | int owl_defense_code; /* result code */ |
| 933 | 932 | int owl_defense_certain; /* 0 if owl reading node limit is reached */ |
| 934 | 933 | int owl_second_defense_point;/* if defender gets both attack points, wins */ |
| 935 | 934 | int owl_attack_kworm; /* only valid when owl_attack_code is GAIN */ |
diff -N -r -u -X .ignore gnugo-copy/engine/worm.c gnugo/engine/worm.c
|
old
|
new
|
|
| 39 | 39 | static int find_lunch(int str, int *lunch); |
| 40 | 40 | static void propagate_worm2(int str); |
| 41 | 41 | static int genus(int str); |
| 42 | | static void markcomponent(int str, int pos, int mg[BOARDMAX]); |
| | 42 | static void markcomponent(int pos, signed char mg[BOARDMAX]); |
| 43 | 43 | static int examine_cavity(int pos, int *edge); |
| 44 | 44 | static void cavity_recurse(int pos, int mx[BOARDMAX], |
| 45 | 45 | int *border_color, int *edge, int str); |
| 46 | 46 | static void ping_cave(int str, int *result1, int *result2, |
| 47 | 47 | int *result3, int *result4); |
| 48 | 48 | static void ping_recurse(int pos, int *counter, |
| 49 | | int mx[BOARDMAX], |
| 50 | | int mr[BOARDMAX], int color); |
| | 49 | int mx[BOARDSIZE], |
| | 50 | int mr[BOARDSIZE], int color, int other); |
| 51 | 51 | static int touching(int pos, int color); |
| 52 | 52 | static void find_attack_patterns(void); |
| 53 | 53 | static void attack_callback(int anchor, int color, |
| … |
… |
|
| 434 | 434 | * - the genus must be zero |
| 435 | 435 | * - there can be no second order liberties |
| 436 | 436 | * - it can't be a cutstone |
| | 437 | * - there is no neighboring attackable worm (lunch) |
| 437 | 438 | * - if it is removed from the board, the remaining cavity has |
| 438 | 439 | * border color the opposite color of the string |
| 439 | 440 | * - it contains at most two edge vertices. |
| … |
… |
|
| 1296 | 1297 | * to the string by placing n stones of the same color on the board, |
| 1297 | 1298 | * but no fewer. The path of connection may pass through an intervening group |
| 1298 | 1299 | * of the same color. The stones placed at distance >1 may not touch a |
| 1299 | | * group of the opposite color. At the edge, also diagonal neighbors |
| 1300 | | * count as touching. The path may also not pass through a liberty at distance |
| 1301 | | * 1 if that liberty is flanked by two stones of the opposing color. This |
| 1302 | | * reflects the fact that the O stone is blocked from expansion to the |
| 1303 | | * left by the two X stones in the following situation: |
| | 1300 | * group of the opposite color. The path may also not pass through a liberty |
| | 1301 | * at distance 1 if that liberty is flanked by two stones of the opposing |
| | 1302 | * color. This reflects the fact that the O stone is blocked from expansion |
| | 1303 | * to the left by the two X stones in the following situation: |
| 1304 | 1304 | * |
| 1305 | 1305 | * X. |
| 1306 | 1306 | * .O |
| … |
… |
|
| 1317 | 1317 | ping_cave(int str, int *lib1, int *lib2, int *lib3, int *lib4) |
| 1318 | 1318 | { |
| 1319 | 1319 | int pos; |
| 1320 | | int k; |
| 1321 | 1320 | int libs[MAXLIBS]; |
| 1322 | | int mrc[BOARDMAX]; |
| 1323 | | int mse[BOARDMAX]; |
| | 1321 | int *cur_lib, *last_lib; |
| | 1322 | int mrc[BOARDSIZE]; |
| | 1323 | int mse[BOARDSIZE]; |
| 1324 | 1324 | int color = board[str]; |
| 1325 | 1325 | int other = OTHER_COLOR(color); |
| 1326 | 1326 | |
| … |
… |
|
| 1328 | 1328 | |
| 1329 | 1329 | /* Find and mark the first order liberties. */ |
| 1330 | 1330 | *lib1 = findlib(str, MAXLIBS, libs); |
| 1331 | | for (k = 0; k < *lib1; k++) |
| 1332 | | mse[libs[k]] = 1; |
| | 1331 | cur_lib = libs; |
| | 1332 | last_lib = libs + *lib1; |
| | 1333 | for (; cur_lib < last_lib; cur_lib++) |
| | 1334 | mse[*cur_lib] = 1; |
| 1333 | 1335 | |
| 1334 | 1336 | /* Reset mse at liberties which are flanked by two stones of the |
| 1335 | 1337 | * opposite color, or one stone and the edge. |
| 1336 | 1338 | */ |
| 1337 | 1339 | |
| 1338 | 1340 | for (pos = BOARDMIN; pos < BOARDMAX; pos++) |
| 1339 | | if (ON_BOARD(pos) |
| 1340 | | && mse[pos] |
| | 1341 | if (mse[pos] |
| 1341 | 1342 | && ((( !ON_BOARD(SOUTH(pos)) || board[SOUTH(pos)] == other) |
| 1342 | 1343 | && ( !ON_BOARD(NORTH(pos)) || board[NORTH(pos)] == other)) |
| 1343 | 1344 | || (( !ON_BOARD(WEST(pos)) || board[WEST(pos)] == other) |
| … |
… |
|
| 1346 | 1347 | |
| 1347 | 1348 | *lib2 = 0; |
| 1348 | 1349 | memset(mrc, 0, sizeof(mrc)); |
| 1349 | | ping_recurse(str, lib2, mse, mrc, color); |
| | 1350 | ping_recurse(str, lib2, mse, mrc, color, other); |
| 1350 | 1351 | |
| 1351 | 1352 | *lib3 = 0; |
| 1352 | 1353 | memset(mrc, 0, sizeof(mrc)); |
| 1353 | | ping_recurse(str, lib3, mse, mrc, color); |
| | 1354 | ping_recurse(str, lib3, mse, mrc, color, other); |
| 1354 | 1355 | |
| 1355 | 1356 | *lib4 = 0; |
| 1356 | 1357 | memset(mrc, 0, sizeof(mrc)); |
| 1357 | | ping_recurse(str, lib4, mse, mrc, color); |
| | 1358 | ping_recurse(str, lib4, mse, mrc, color, other); |
| 1358 | 1359 | } |
| 1359 | 1360 | |
| 1360 | 1361 | |
| 1361 | | /* recursive function called by ping_cave */ |
| | 1362 | /* recursive function called by ping_cave |
| | 1363 | * mx - marked liberties of any order |
| | 1364 | * mr - marked checked positions */ |
| 1362 | 1365 | |
| 1363 | 1366 | static void |
| 1364 | 1367 | ping_recurse(int pos, int *counter, |
| 1365 | | int mx[BOARDMAX], int mr[BOARDMAX], |
| 1366 | | int color) |
| | 1368 | int mx[BOARDSIZE], int mr[BOARDSIZE], |
| | 1369 | int color, int other) |
| 1367 | 1370 | { |
| 1368 | | int k; |
| | 1371 | int apos; |
| | 1372 | const int *cur_delta; |
| 1369 | 1373 | mr[pos] = 1; |
| 1370 | 1374 | |
| 1371 | | for (k = 0; k < 4; k++) { |
| 1372 | | int apos = pos + delta[k]; |
| 1373 | | if (board[apos] == EMPTY |
| 1374 | | && mx[apos] == 0 |
| 1375 | | && mr[apos] == 0 |
| 1376 | | && !touching(apos, OTHER_COLOR(color))) { |
| | 1375 | for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { |
| | 1376 | apos = pos + *cur_delta; |
| | 1377 | if (!board[apos] |
| | 1378 | && !mr[apos] |
| | 1379 | && !mx[apos] |
| | 1380 | && !touching(apos, other)) { |
| 1377 | 1381 | (*counter)++; |
| 1378 | 1382 | mr[apos] = 1; |
| 1379 | 1383 | mx[apos] = 1; |
| … |
… |
|
| 1381 | 1385 | } |
| 1382 | 1386 | |
| 1383 | 1387 | if (!is_ko_point(pos)) { |
| 1384 | | for (k = 0; k < 4; k++) { |
| 1385 | | int apos = pos + delta[k]; |
| 1386 | | if (ON_BOARD(apos) |
| 1387 | | && mr[apos] == 0 |
| 1388 | | && (mx[apos] == 1 |
| | 1388 | for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { |
| | 1389 | apos = pos + *cur_delta; |
| | 1390 | if (!mr[apos] |
| | 1391 | && (mx[apos] |
| 1389 | 1392 | || board[apos] == color)) |
| 1390 | | ping_recurse(apos, counter, mx, mr, color); |
| | 1393 | ping_recurse(apos, counter, mx, mr, color, other); |
| 1391 | 1394 | } |
| 1392 | 1395 | } |
| 1393 | 1396 | } |
| … |
… |
|
| 1416 | 1419 | genus(int str) |
| 1417 | 1420 | { |
| 1418 | 1421 | int pos; |
| 1419 | | int mg[BOARDMAX]; |
| | 1422 | signed char mg[BOARDMAX]; |
| 1420 | 1423 | int gen = -1; |
| 1421 | 1424 | |
| 1422 | 1425 | memset(mg, 0, sizeof(mg)); |
| | 1426 | mark_string(str, mg, 1); |
| | 1427 | |
| 1423 | 1428 | for (pos = BOARDMIN; pos < BOARDMAX; pos++) { |
| 1424 | | if (ON_BOARD(pos) |
| 1425 | | && !mg[pos] |
| 1426 | | && (board[pos] == EMPTY || !is_same_worm(pos, str))) { |
| 1427 | | markcomponent(str, pos, mg); |
| | 1429 | if (!mg[pos] |
| | 1430 | && ON_BOARD(pos)) { |
| | 1431 | markcomponent(pos, mg); |
| 1428 | 1432 | gen++; |
| 1429 | 1433 | } |
| 1430 | 1434 | } |
| … |
… |
|
| 1434 | 1438 | |
| 1435 | 1439 | |
| 1436 | 1440 | /* This recursive function marks the component at (pos) of |
| 1437 | | * the complement of the string with origin (str) |
| | 1441 | * the complement of the string. |
| 1438 | 1442 | */ |
| 1439 | 1443 | |
| 1440 | 1444 | static void |
| 1441 | | markcomponent(int str, int pos, int mg[BOARDMAX]) |
| | 1445 | markcomponent(int pos, signed char mg[BOARDMAX]) |
| 1442 | 1446 | { |
| 1443 | | int k; |
| | 1447 | const int *cur_delta; |
| 1444 | 1448 | mg[pos] = 1; |
| 1445 | | for (k = 0; k < 4; k++) { |
| 1446 | | int apos = pos + delta[k]; |
| 1447 | | if (ON_BOARD(apos) |
| 1448 | | && mg[apos] == 0 |
| 1449 | | && (board[apos] == EMPTY || !is_same_worm(apos, str))) |
| 1450 | | markcomponent(str, apos, mg); |
| | 1449 | for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { |
| | 1450 | int apos = pos + *cur_delta; |
| | 1451 | if (!mg[apos] |
| | 1452 | && ON_BOARD(apos)) |
| | 1453 | markcomponent(apos, mg); |
| 1451 | 1454 | } |
| 1452 | 1455 | } |
| 1453 | 1456 | |
| … |
… |
|
| 1468 | 1471 | { |
| 1469 | 1472 | int border_color = EMPTY; |
| 1470 | 1473 | int ml[BOARDMAX]; |
| 1471 | | int origin = NO_MOVE; |
| | 1474 | int origin; |
| 1472 | 1475 | |
| 1473 | 1476 | ASSERT_ON_BOARD1(pos); |
| 1474 | 1477 | gg_assert(edge != NULL); |
| … |
… |
|
| 1479 | 1482 | |
| 1480 | 1483 | if (IS_STONE(board[pos])) |
| 1481 | 1484 | origin = find_origin(pos); |
| | 1485 | else |
| | 1486 | origin = NO_MOVE; |
| 1482 | 1487 | |
| 1483 | 1488 | cavity_recurse(pos, ml, &border_color, edge, origin); |
| 1484 | 1489 | |
| 1485 | | if (border_color != EMPTY) |
| | 1490 | if (border_color) |
| 1486 | 1491 | return border_color; |
| 1487 | 1492 | |
| 1488 | 1493 | /* We should have returned now, unless the board is completely empty. |
| … |
… |
|
| 1491 | 1496 | * Notice that the board appears completely empty if there's only a |
| 1492 | 1497 | * single string and pos points to it. |
| 1493 | 1498 | */ |
| 1494 | | gg_assert(border_color == EMPTY |
| 1495 | | && ((pos == NO_MOVE |
| 1496 | | && stones_on_board(BLACK | WHITE) == 0) |
| 1497 | | || (pos != NO_MOVE |
| 1498 | | && stones_on_board(BLACK | WHITE) == countstones(pos)))); |
| | 1499 | gg_assert((origin == NO_MOVE |
| | 1500 | && stones_on_board(BLACK | WHITE) == 0) |
| | 1501 | || (origin != NO_MOVE |
| | 1502 | && stones_on_board(BLACK | WHITE) == countstones(pos))); |
| 1499 | 1503 | |
| 1500 | 1504 | return GRAY; |
| 1501 | 1505 | } |
| … |
… |
|
| 1522 | 1526 | cavity_recurse(int pos, int mx[BOARDMAX], |
| 1523 | 1527 | int *border_color, int *edge, int str) |
| 1524 | 1528 | { |
| 1525 | | int k; |
| 1526 | | ASSERT1(mx[pos] == 0, pos); |
| | 1529 | const int *cur_delta; |
| | 1530 | ASSERT1(!mx[pos], pos); |
| 1527 | 1531 | |
| 1528 | 1532 | mx[pos] = 1; |
| 1529 | 1533 | |
| 1530 | | if (is_edge_vertex(pos) && board[pos] == EMPTY) |
| | 1534 | if (is_edge_vertex(pos) && !board[pos]) |
| 1531 | 1535 | (*edge)++; |
| 1532 | 1536 | |
| 1533 | 1537 | /* Loop over the four neighbors. */ |
| 1534 | | for (k = 0; k < 4; k++) { |
| 1535 | | int apos = pos + delta[k]; |
| | 1538 | for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { |
| | 1539 | int apos = pos + *cur_delta; |
| 1536 | 1540 | if (ON_BOARD(apos) && !mx[apos]) { |
| 1537 | | int neighbor_empty = 0; |
| 1538 | | |
| 1539 | | if (board[apos] == EMPTY) |
| 1540 | | neighbor_empty = 1; |
| 1541 | | else { |
| 1542 | | /* Count the neighbor as empty if it is part of the (ai, aj) string. */ |
| 1543 | | if (str == find_origin(apos)) |
| 1544 | | neighbor_empty = 1; |
| 1545 | | else |
| 1546 | | neighbor_empty = 0; |
| 1547 | | } |
| 1548 | | |
| 1549 | | if (!neighbor_empty) |
| 1550 | | *border_color |= board[apos]; |
| 1551 | | else |
| | 1541 | /* Count the neighbor as empty if it is part of the (ai, aj) string. */ |
| | 1542 | if (!board[apos] || str == find_origin(apos)) |
| 1552 | 1543 | cavity_recurse(apos, mx, border_color, edge, str); |
| | 1544 | else |
| | 1545 | *border_color |= board[apos]; |
| 1553 | 1546 | } |
| 1554 | 1547 | } |
| 1555 | 1548 | } |
diff -N -r -u -X .ignore gnugo-copy/interface/gnugo.vcproj gnugo/interface/gnugo.vcproj
|
old
|
new
|
|
| 400 | 400 | Filter="h;hpp;hxx;hm;inl" |
| 401 | 401 | > |
| 402 | 402 | <File |
| | 403 | RelativePath="..\config.h" |
| | 404 | > |
| | 405 | </File> |
| | 406 | <File |
| 403 | 407 | RelativePath=".\interface.h" |
| 404 | 408 | > |
| 405 | 409 | </File> |
diff -N -r -u -X .ignore gnugo-copy/makevcdist.pl gnugo/makevcdist.pl
|
old
|
new
|
|
| 17 | 17 | EXPERIMENTAL_SEMEAI => 1, |
| 18 | 18 | EXPERIMENTAL_OWL_EXT => 0, |
| 19 | 19 | EXPERIMENTAL_CONNECTIONS => 1, |
| | 20 | FINAL_RELEASE => 0, |
| 20 | 21 | LARGE_SCALE => 0, |
| 21 | 22 | GRID_OPT => 1, |
| 22 | 23 | OWL_THREATS => 0, |
diff -N -r -u -X .ignore gnugo-copy/patterns/patterns.vcproj gnugo/patterns/patterns.vcproj
|
old
|
new
|
|
| 623 | 623 | Filter="h;hpp;hxx;hm;inl" |
| 624 | 624 | > |
| 625 | 625 | <File |
| | 626 | RelativePath="..\config.h" |
| | 627 | > |
| | 628 | </File> |
| | 629 | <File |
| 626 | 630 | RelativePath="dfa.h" |
| 627 | 631 | > |
| 628 | 632 | </File> |