Ticket #97: new_amalgamation_7_9.1.diff
| File new_amalgamation_7_9.1.diff, 38.3 KB (added by gunnar, 4 years ago) |
|---|
-
engine/dragon.c
RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v retrieving revision 1.160 diff -u -r1.160 dragon.c
49 49 50 50 #include "liberty.h" 51 51 #include "gg_utils.h" 52 #include "readconnect.h" 52 53 53 54 static void initialize_supplementary_dragon_data(void); 55 static void amalgamate_dragons(int color); 56 static void build_dragon(int w, int amalgamated[BOARDMAX], 57 float effective_sizes[BOARDMAX]); 54 58 static void find_lunches(void); 55 59 static void eye_computations(void); 56 60 static void revise_inessentiality(void); … … 113 117 * involved dragons. 114 118 */ 115 119 memset(cutting_points, 0, sizeof(cutting_points)); 120 if (experimental_connections) 121 initialize_static_worm_connections(); 116 122 find_cuts(); 117 123 find_connections(); 124 if (experimental_connections) { 125 analyze_worm_connections(); 126 amalgamate_dragons(BLACK); 127 amalgamate_dragons(WHITE); 128 } 118 129 119 130 /* At this time, all dragons have been finalized and we can 120 131 * initialize the dragon2[] array. After that we can no longer allow … … 744 755 } 745 756 746 757 758 static void 759 amalgamate_dragons(int color) 760 { 761 int amalgamated[BOARDMAX]; 762 int pos; 763 float effective_sizes[BOARDMAX]; 764 765 if (stackp == 0) { 766 for (pos = BOARDMIN; pos < BOARDMAX; pos++) 767 if (IS_STONE(board[pos])) 768 effective_sizes[pos] = worm[pos].effective_size; 769 } 770 else { 771 compute_effective_string_sizes(effective_sizes); 772 for (pos = BOARDMIN; pos < BOARDMAX; pos++) 773 if (IS_STONE(board[pos])) 774 effective_sizes[pos] = effective_sizes[find_origin(pos)]; 775 } 776 777 memset(amalgamated, 0, sizeof(amalgamated)); 778 while (1) { 779 int biggest_remaining_string = NO_MOVE; 780 float biggest_remaining_string_size = 0.0; 781 for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 782 if (board[pos] == color 783 && find_origin(pos) == pos 784 && !amalgamated[pos] 785 && effective_sizes[pos] > biggest_remaining_string_size) { 786 biggest_remaining_string = pos; 787 biggest_remaining_string_size = effective_sizes[pos]; 788 } 789 } 790 if (biggest_remaining_string == NO_MOVE) 791 break; 792 793 build_dragon(biggest_remaining_string, amalgamated, effective_sizes); 794 } 795 } 796 797 static void 798 build_dragon(int starting_worm, int amalgamated[BOARDMAX], 799 float effective_sizes[BOARDMAX]) 800 { 801 int color = board[starting_worm]; 802 int worms_in_this_dragon[BOARDMAX]; 803 int num_worms; 804 int aspiring_worms[BOARDMAX]; 805 int num_aspiring; 806 int considered[BOARDMAX]; 807 int k; 808 int pos; 809 810 DEBUG(DEBUG_DRAGONS, "Build dragon starting at %1m.\n", starting_worm); 811 812 amalgamated[starting_worm] = 1; 813 worms_in_this_dragon[0] = starting_worm; 814 num_worms = 1; 815 num_aspiring = 0; 816 memset(considered, 0, sizeof(considered)); 817 818 for (k = 0; k < num_worms; k++) { 819 int this_worm = worms_in_this_dragon[k]; 820 for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 821 if (board[pos] != color || find_origin(pos) != pos 822 || amalgamated[pos] || considered[pos] 823 || !worms_are_connected(this_worm, pos)) 824 continue; 825 826 DEBUG(DEBUG_DRAGONS, " queueing %1m.\n", pos); 827 considered[pos] = 1; 828 aspiring_worms[num_aspiring] = pos; 829 num_aspiring++; 830 } 831 832 while (num_aspiring > 0) { 833 int j; 834 int w; 835 int largest_worm = -1; 836 float largest_size = 0.0; 837 838 for (j = 0; j < num_aspiring; j++) { 839 if (effective_sizes[aspiring_worms[j]] > largest_size) { 840 largest_worm = j; 841 largest_size = effective_sizes[aspiring_worms[j]]; 842 } 843 } 844 845 w = aspiring_worms[largest_worm]; 846 num_aspiring--; 847 aspiring_worms[largest_worm] = aspiring_worms[num_aspiring]; 848 849 for (j = 0; j < num_worms; j++) { 850 if (worms_are_intransitively_connected(w, worms_in_this_dragon[j])) { 851 DEBUG(DEBUG_DRAGONS, 852 " intransitive connection to %1m, discarding %1m.\n", 853 worms_in_this_dragon[j], w); 854 break; 855 } 856 } 857 858 if (j == num_worms) { 859 worms_in_this_dragon[num_worms] = w; 860 num_worms++; 861 amalgamated[w] = 1; 862 join_dragons(starting_worm, w); 863 break; 864 } 865 } 866 } 867 } 868 747 869 /* Examine which dragons are adjacent to each other. This is 748 870 * complicated by the fact that adjacency may involve a certain 749 871 * amount of empty space. … … 1601 1723 int pos; 1602 1724 int saved_cutting_points[BOARDMAX]; 1603 1725 1604 /* This is currently necessary in order not to mess up the 1605 * worm[].cutstone2 field. See cutstone2_helper in 1606 * patterns/helpers.c. On the other hand it shouldn't be very 1726 /* This is currently necessary in order not to mess up various 1727 * information such as the worm[].cutstone2 field (see 1728 * cutstone2_helper in patterns/helpers.c) and the static worm 1729 * connection analysis. On the other hand it shouldn't be very 1607 1730 * interesting to recompute dragons in the original position. 1608 1731 */ 1609 1732 gg_assert(stackp > 0); … … 1618 1741 new_dragon_origins[pos] = find_origin(pos); 1619 1742 } 1620 1743 1744 if (experimental_connections) 1745 initialize_static_worm_connections(); 1621 1746 find_cuts(); 1622 1747 find_connections(); 1748 if (experimental_connections) { 1749 analyze_worm_connections(); 1750 amalgamate_dragons(BLACK); 1751 amalgamate_dragons(WHITE); 1752 } 1623 1753 1624 1754 memcpy(cutting_points, saved_cutting_points, sizeof(cutting_points)); 1625 1755 memcpy(dragon_origins, new_dragon_origins, sizeof(new_dragon_origins)); -
engine/liberty.h
RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v retrieving revision 1.255 diff -u -r1.255 liberty.h
325 325 void mark_inessential_stones(int color, signed char safe_stones[BOARDMAX]); 326 326 327 327 void get_lively_stones(int color, signed char safe_stones[BOARDMAX]); 328 void compute_effective_string_sizes(float effective_sizes[BOARDMAX]); 328 329 int is_same_worm(int w1, int w2); 329 330 int is_worm_origin(int w, int pos); 330 331 void propagate_worm(int pos); 331 332 void find_cuts(void); 332 333 void find_connections(void); 333 334 335 void initialize_static_worm_connections(void); 336 void analyze_worm_connections(void); 337 void register_potential_worm_connection(int w1, int w2); 338 int worms_are_connected(int w1, int w2); 339 int worms_are_connected_with_ko(int w1, int w2); 340 int worms_are_close(int w1, int w2); 341 int worms_are_intransitively_connected(int w1, int w2); 342 334 343 /* movelist.c */ 335 344 int movelist_move_known(int move, int max_points, int points[], int codes[]); 336 345 void movelist_change_point(int move, int code, int max_points, -
engine/owl.c
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v retrieving revision 1.246 diff -u -r1.246 owl.c
72 72 /* Same as goal, except never anything is removed from it. */ 73 73 signed char cumulative_goal[BOARDMAX]; 74 74 75 int original_goal_strings[MAX_GOAL_WORMS]; 76 int num_original_goal_strings; 77 75 78 /* FIXME: neighbors[] and escape_values[] are never recomputed. 76 79 * Consider moving these arrays from stack to a static or 77 80 * dynamic variable so it is not copied around in … … 1839 1842 int value1; 1840 1843 int value2; 1841 1844 int this_variation_number = count_variations - 1; 1845 int all_original_strings_tactically_unstable; 1846 SGFTree *save_sgf_dumptree; 1847 int save_count_variations; 1842 1848 1843 1849 SETUP_TRACE_INFO("owl_attack", str); 1844 1850 … … 1880 1886 READ_RETURN(OWL_ATTACK, str, depth - stackp, move, 0, 0); 1881 1887 } 1882 1888 1889 /* Do not give up if all original strings are tactically unstable. 1890 */ 1891 save_sgf_dumptree = sgf_dumptree; 1892 save_count_variations = count_variations; 1893 sgf_dumptree = NULL; 1894 count_variations = 0; 1895 all_original_strings_tactically_unstable = 1; 1896 for (k = 0; k < owl->num_original_goal_strings; k++) { 1897 if (!attack(owl->original_goal_strings[k], NULL)) { 1898 all_original_strings_tactically_unstable = 0; 1899 break; 1900 } 1901 } 1902 sgf_dumptree = save_sgf_dumptree; 1903 count_variations = save_count_variations; 1904 1883 1905 memset(mw, 0, sizeof(mw)); 1884 1906 global_owl_node_counter++; 1885 1907 local_owl_node_counter++; … … 1889 1911 1890 1912 /* First see whether there is any chance to kill. */ 1891 1913 if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 1, 1892 &probable_eyes, &eyemin, &eyemax)) { 1914 &probable_eyes, &eyemin, &eyemax) 1915 && !all_original_strings_tactically_unstable) { 1893 1916 /* 1894 1917 * We need to check here if there's a worm under atari. If yes, 1895 1918 * locate it and report a (gote) GAIN. … … 1931 1954 1932 1955 /* We try moves in five passes. 1933 1956 * stackp==0 stackp>0 1934 * 0. Vital moves in the interval [70..] [45..] 1935 * 1. Shape moves 1936 * 2. Vital moves in the interval [..69] [..44] 1937 * 3. Tactical attack moves (except certain kos) 1938 * 4. Moves found by the defender 1939 * 5. Tactical ko attack moves which were not tried in pass 3 1957 * 1. Tactical attack moves if all original strings are unstable. 1958 * 2. Vital moves in the interval [70..] [45..] 1959 * 3. Shape moves 1960 * 4. Vital moves in the interval [..69] [..44] 1961 * 5. Tactical attack moves (except certain kos) 1962 * 6. Moves found by the defender 1963 * 7. Tactical ko attack moves which were not tried in pass 3 1940 1964 */ 1941 for (pass = 0; pass < 6; pass++) {1965 for (pass = 1; pass < 8; pass++) { 1942 1966 moves = NULL; 1943 1967 move_cutoff = 1; 1944 1968 1945 1969 current_owl_data = owl; 1946 1970 /* Get the shape moves if we are in the right pass. */ 1947 1971 switch (pass) { 1948 case 1:1972 case 3: 1949 1973 if (stackp > owl_branch_depth && number_tried_moves > 0) 1950 1974 continue; 1951 1975 … … 1953 1977 moves = shape_moves; 1954 1978 break; 1955 1979 1956 case 0:1957 1980 case 2: 1981 case 4: 1958 1982 if (stackp > owl_branch_depth && number_tried_moves > 0) 1959 1983 continue; 1960 1984 1961 1985 moves = vital_moves; 1962 if (pass == 0|| stackp > owl_distrust_depth) {1986 if (pass == 2 || stackp > owl_distrust_depth) { 1963 1987 if (stackp == 0) 1964 1988 move_cutoff = 70; 1965 1989 else … … 1969 1993 move_cutoff = 99; /* Effectively disable vital moves. */ 1970 1994 break; 1971 1995 1972 case 3: 1996 case 1: 1997 if (!all_original_strings_tactically_unstable) 1998 break; 1999 /* Otherwise fall through. */ 1973 2000 case 5: 2001 case 7: 1974 2002 { 1975 2003 /* Look for a tactical attack. This is primarily intended for 1976 2004 * the case where the whole dragon is a single string, therefore … … 1979 2007 * We must be wary with attacks giving ko. Unless the dragon 1980 2008 * otherwise looks alive, this may turn a dead dragon into one 1981 2009 * which can live by ko. Such moves will be tried anyway in 1982 * pass 5. Notice though that we can only reach there if an owl1983 * defense was found in pass 4.2010 * pass 7. Notice though that we can only reach there if an owl 2011 * defense was found in pass 6. 1984 2012 */ 1985 2013 int apos; 1986 2014 int result; … … 1992 2020 result = attack(str, &apos); 1993 2021 if (result == WIN 1994 2022 || (result != 0 && (min_eyes(&probable_eyes) >= 2 1995 || pass == 5))) {2023 || pass == 7))) { 1996 2024 set_single_owl_move(shape_moves, apos, "tactical attack"); 1997 2025 moves = shape_moves; 1998 2026 } … … 2004 2032 /* If we found no move in the first four passes we ask the defender 2005 2033 * for a move suggestion. 2006 2034 */ 2007 case 4:2035 case 6: 2008 2036 if (number_tried_moves == 0) { 2009 2037 int dpos; 2010 2038 int dcode = do_owl_defend(str, &dpos, NULL, owl, escape); … … 2091 2119 current_owl_data = owl; 2092 2120 2093 2121 /* Shape moves are selected on demand. */ 2094 if (pass == 1) {2122 if (pass == 3) { 2095 2123 if (!get_next_move_from_list(&shape_patterns, other, 2096 2124 shape_moves, move_cutoff, owl)) 2097 2125 break; … … 2134 2162 */ 2135 2163 if (IS_STONE(board[str])) 2136 2164 origin = str; 2165 else if (owl->num_original_goal_strings > 0) 2166 origin = owl->original_goal_strings[0]; 2137 2167 else 2138 origin = select_new_goal_origin(NO_MOVE, owl);2168 origin = NO_MOVE; 2139 2169 2140 2170 /* Test whether the move cut the goal dragon apart. */ 2141 2171 if (moves[k].cuts[0] != NO_MOVE) { … … 2147 2177 2148 2178 if (origin == NO_MOVE) 2149 2179 dcode = 0; 2150 else 2180 else { 2151 2181 dcode = do_owl_defend(origin, NULL, &wid, owl, escape); 2182 } 2152 2183 2153 2184 if (!ko_move) { 2154 2185 if (dcode == 0) { … … 2473 2504 int eyemin = -1; /* Lower bound on the number of eyes. */ 2474 2505 int eyemax = -1; /* Upper bound on the number of eyes. */ 2475 2506 struct eyevalue probable_eyes; /* Best guess of eyevalue. */ 2476 int escape_route;2477 2507 const char *live_reason; 2478 2508 int move_cutoff; 2479 2509 int xpos; 2480 2510 int value1; 2481 2511 int value2; 2482 2512 int this_variation_number = count_variations - 1; 2513 int all_original_strings_tactically_unstable; 2514 SGFTree *save_sgf_dumptree; 2515 int save_count_variations; 2483 2516 2484 2517 SETUP_TRACE_INFO("owl_defend", str); 2485 2518 … … 2514 2547 return value1; 2515 2548 } 2516 2549 2550 /* Do not declare victory if all original strings are tactically 2551 * unstable. 2552 */ 2553 save_sgf_dumptree = sgf_dumptree; 2554 save_count_variations = count_variations; 2555 sgf_dumptree = NULL; 2556 count_variations = 0; 2557 all_original_strings_tactically_unstable = 1; 2558 for (k = 0; k < owl->num_original_goal_strings; k++) { 2559 if (!attack(owl->original_goal_strings[k], NULL)) { 2560 all_original_strings_tactically_unstable = 0; 2561 break; 2562 } 2563 } 2564 sgf_dumptree = save_sgf_dumptree; 2565 count_variations = save_count_variations; 2566 2517 2567 /* In order to get a defense move even if we seem to already have 2518 2568 * escaped and to reduce the impact of overestimated escape 2519 2569 * possibilities, we don't declare escape victory on the first move. … … 2521 2571 * FIXME: Should introduce a new owl depth value rather than having 2522 2572 * this hardwired value. 2523 2573 */ 2524 escape_route = owl_escape_route(owl); 2525 if (stackp > 2 && escape_route >= 5) { 2526 /* FIXME: We probably should make distinction in the returned 2527 * result whether the dragon lives by making two eyes or by 2528 * escaping. 2529 */ 2530 TRACE("%oVariation %d: ALIVE (escaped)\n", this_variation_number); 2531 SGFTRACE(0, WIN, "escaped"); 2532 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN); 2574 if (stackp > 2 && !all_original_strings_tactically_unstable) { 2575 int escape_route = owl_escape_route(owl); 2576 if (escape_route >= 5) { 2577 /* FIXME: We probably should make distinction in the returned 2578 * result whether the dragon lives by making two eyes or by 2579 * escaping. 2580 */ 2581 TRACE("%oVariation %d: ALIVE (escaped)\n", this_variation_number); 2582 SGFTRACE(0, WIN, "escaped"); 2583 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN); 2584 } 2533 2585 } 2534 2586 2535 /* If reading goes to deep or we run out of nodes, we assume life. */2587 /* If reading goes too deep or we run out of nodes, we assume life. */ 2536 2588 if (reading_limit_reached(&live_reason, this_variation_number)) { 2537 2589 SGFTRACE(0, WIN, live_reason); 2538 2590 READ_RETURN(OWL_DEFEND, str, depth - stackp, move, 0, WIN); … … 2545 2597 current_owl_data = owl; 2546 2598 memset(owl->safe_move_cache, 0, sizeof(owl->safe_move_cache)); 2547 2599 2548 /* First see whether we might already be ali fe. */2600 /* First see whether we might already be alive. */ 2549 2601 if (escape < MAX_ESCAPE) { 2550 2602 if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 0, 2551 &probable_eyes, &eyemin, &eyemax)) { 2603 &probable_eyes, &eyemin, &eyemax) 2604 && !all_original_strings_tactically_unstable) { 2552 2605 SGFTRACE(0, WIN, live_reason); 2553 2606 TRACE("%oVariation %d: ALIVE (%s)\n", 2554 2607 this_variation_number, live_reason); … … 2571 2624 2572 2625 /* We try moves in four passes. 2573 2626 * stackp==0 stackp>0 2574 * 0. Vital moves in the interval [70..] [45..] 2575 * 1. Shape moves 2576 * 2. Vital moves in the interval [..69] [..44] 2577 * 3. Tactical defense moves 2627 * 1. Tactical defense moves if all original strings unstable 2628 * 2. Vital moves in the interval [70..] [45..] 2629 * 3. Shape moves 2630 * 4. Vital moves in the interval [..69] [..44] 2631 * 5. Tactical defense moves 2578 2632 */ 2579 for (pass = 0; pass < 4; pass++) {2633 for (pass = 1; pass < 6; pass++) { 2580 2634 moves = NULL; 2581 2635 move_cutoff = 1; 2582 2636 2583 2637 current_owl_data = owl; 2584 2638 switch (pass) { 2585 2639 /* Get the shape moves if we are in the right pass. */ 2586 case 1:2640 case 3: 2587 2641 2588 2642 if (stackp > owl_branch_depth && number_tried_moves > 0) 2589 2643 continue; … … 2592 2646 moves = shape_moves; 2593 2647 break; 2594 2648 2595 case 0:2596 2649 case 2: 2650 case 4: 2597 2651 if (stackp > owl_branch_depth && number_tried_moves > 0) 2598 2652 continue; 2599 2653 2600 2654 moves = vital_moves; 2601 if (pass == 0|| stackp > owl_distrust_depth) {2655 if (pass == 2 || stackp > owl_distrust_depth) { 2602 2656 if (stackp == 0) 2603 2657 move_cutoff = 70; 2604 2658 else if (eyemin + min_eyes(&probable_eyes) > 3) … … 2612 2666 move_cutoff = 99; /* Effectively disable vital moves. */ 2613 2667 break; 2614 2668 2615 case 3: 2669 case 1: 2670 case 5: 2616 2671 { 2617 2672 int goalcount = 0; 2618 2673 … … 2622 2677 if (ON_BOARD(k)) 2623 2678 goalcount += owl->goal[k]; 2624 2679 2625 if (goalcount < 5) { 2680 if ((pass == 5 && all_original_strings_tactically_unstable) 2681 || (pass == 5 && goalcount < 5)) { 2626 2682 2627 2683 /* Look for a tactical defense. This is primarily intended for 2628 2684 * the case where the whole dragon is a single string, therefore … … 2635 2691 * confusing the eye analysis. 2636 2692 */ 2637 2693 int dpos; 2638 SGFTree *save_sgf_dumptree = sgf_dumptree;2639 intsave_count_variations = count_variations;2694 save_sgf_dumptree = sgf_dumptree; 2695 save_count_variations = count_variations; 2640 2696 2641 2697 sgf_dumptree = NULL; 2642 2698 count_variations = 0; … … 2676 2732 2677 2733 current_owl_data = owl; 2678 2734 2679 if (pass == 1) {2735 if (pass == 3) { 2680 2736 if (!get_next_move_from_list(&shape_patterns, color, shape_moves, 2681 2737 move_cutoff, owl)) 2682 2738 break; … … 4452 4508 int color = board[apos]; 4453 4509 4454 4510 ASSERT1(bpos == NO_MOVE || board[bpos] == color, bpos); 4455 4511 4456 4512 if (new_dragons == NULL) { 4457 4513 for (pos = BOARDMIN; pos < BOARDMAX; pos++) 4458 4514 if (ON_BOARD(pos)) { … … 4474 4530 } 4475 4531 } 4476 4532 4533 owl->num_original_goal_strings = 0; 4534 for (pos = BOARDMIN; pos < BOARDMAX; pos++) 4535 if (IS_STONE(board[pos]) 4536 && owl->goal[pos] 4537 && owl->num_original_goal_strings < MAX_GOAL_WORMS 4538 && find_origin(pos) == pos) { 4539 owl->original_goal_strings[owl->num_original_goal_strings] = pos; 4540 owl->num_original_goal_strings++; 4541 } 4542 4477 4543 memcpy(owl->cumulative_goal, owl->goal, sizeof(owl->goal)); 4478 4544 owl->color = color; 4479 4545 owl_mark_boundary(owl); 4546 if (owl->num_original_goal_strings == 1) 4547 owl_update_goal(apos, 2, NO_MOVE, owl, 0); 4480 4548 } 4481 4549 4482 4550 … … 4620 4688 int stones[MAX_BOARD * MAX_BOARD]; 4621 4689 int num_stones; 4622 4690 int k; 4691 int m; 4623 4692 int do_add = 1; 4624 4693 SGFTree *save_sgf_dumptree = sgf_dumptree; 4625 4694 int save_count_variations = count_variations; … … 4676 4745 } 4677 4746 } 4678 4747 4748 /* Update the list of original goal strings. This move may have 4749 * merged two or more of the strings. 4750 */ 4751 for (k = 0; k < owl->num_original_goal_strings; k++) { 4752 for (m = 0; m < k; m++) 4753 if (same_string(owl->original_goal_strings[k], 4754 owl->original_goal_strings[m])) { 4755 owl->num_original_goal_strings--; 4756 owl->original_goal_strings[k] = 4757 owl->original_goal_strings[owl->num_original_goal_strings]; 4758 k--; 4759 break; 4760 } 4761 } 4762 4763 /* It might also have recreated a previously captured string. */ 4764 if (owl->goal[pos] == 1 4765 && owl->num_original_goal_strings < MAX_GOAL_WORMS) { 4766 for (k = 0; k < owl->num_original_goal_strings; k++) { 4767 if (same_string(owl->original_goal_strings[k], pos)) 4768 break; 4769 } 4770 if (k == owl->num_original_goal_strings) { 4771 owl->original_goal_strings[owl->num_original_goal_strings] = pos; 4772 owl->num_original_goal_strings++; 4773 } 4774 } 4775 4679 4776 if (1 && verbose) 4680 4777 goaldump(owl->goal); 4681 4778 } … … 4898 4995 } 4899 4996 4900 4997 mark_string(pos, owl->boundary, boundary_mark); 4998 4999 /* The move may have captured one or more of the original goal strings. */ 5000 for (k = 0; k < owl->num_original_goal_strings; k++) { 5001 if (board[owl->original_goal_strings[k]] == EMPTY) { 5002 owl->num_original_goal_strings--; 5003 owl->original_goal_strings[k] = 5004 owl->original_goal_strings[owl->num_original_goal_strings]; 5005 k--; 5006 } 5007 } 4901 5008 } 4902 5009 4903 5010 /* Lists the goal array. For use in GDB: … … 5964 6071 int result; 5965 6072 double start = 0.0; 5966 6073 struct local_owl_data *owl; 6074 int pos; 5967 6075 int num_moves = 0; 5968 6076 5969 6077 if (debug & DEBUG_OWL_PERFORMANCE) … … 6041 6149 /* FIXME: We would want to use init_owl() here too, but it doesn't 6042 6150 * fit very well with the construction of the goal array above. 6043 6151 */ 6152 owl->num_original_goal_strings = 0; 6153 for (pos = BOARDMIN; pos < BOARDMAX; pos++) 6154 if (ON_BOARD(pos) 6155 && owl->goal[pos] 6156 && owl->num_original_goal_strings < MAX_GOAL_WORMS 6157 && find_origin(pos) == pos) { 6158 owl->original_goal_strings[owl->num_original_goal_strings] = pos; 6159 owl->num_original_goal_strings++; 6160 } 6161 6044 6162 memcpy(owl->cumulative_goal, owl->goal, BOARDMAX); 6045 6163 compute_owl_escape_values(owl); 6046 6164 owl_mark_boundary(owl); … … 6651 6769 memcpy(new_owl->cumulative_goal, (*owl)->cumulative_goal, 6652 6770 sizeof(new_owl->cumulative_goal)); 6653 6771 memcpy(new_owl->boundary, (*owl)->boundary, sizeof(new_owl->boundary)); 6772 memcpy(new_owl->original_goal_strings, (*owl)->original_goal_strings, 6773 sizeof(new_owl->original_goal_strings)); 6774 new_owl->num_original_goal_strings = (*owl)->num_original_goal_strings; 6654 6775 memcpy(new_owl->neighbors, (*owl)->neighbors, sizeof(new_owl->neighbors)); 6655 6776 memcpy(new_owl->escape_values, (*owl)->escape_values, 6656 6777 sizeof(new_owl->escape_values)); -
engine/worm.c
RCS file: /cvsroot/gnugo/gnugo/engine/worm.c,v retrieving revision 1.71 diff -u -r1.71 worm.c
32 32 static void compute_effective_worm_sizes(void); 33 33 static void do_compute_effective_worm_sizes(int color, 34 34 int (*cw)[MAX_CLOSE_WORMS], 35 int *ncw, int max_distance); 35 int *ncw, float *effective_sizes, 36 int max_distance); 36 37 static void compute_unconditional_status(void); 37 38 static void find_worm_attacks_and_defenses(void); 38 39 static void find_worm_threats(void); … … 566 567 static void 567 568 compute_effective_worm_sizes() 568 569 { 570 float effective_sizes[BOARDMAX]; 571 int pos; 572 569 573 do_compute_effective_worm_sizes(BLACK | WHITE, close_worms, 570 number_close_worms, 3); 574 number_close_worms, effective_sizes, 3); 575 576 for (pos = BOARDMIN; pos < BOARDMAX; pos++) 577 if (IS_STONE(board[pos])) 578 worm[pos].effective_size = effective_sizes[worm[pos].origin]; 579 571 580 do_compute_effective_worm_sizes(BLACK, close_black_worms, 572 number_close_black_worms, 5); 581 number_close_black_worms, NULL, 5); 582 573 583 do_compute_effective_worm_sizes(WHITE, close_white_worms, 574 number_close_white_worms, 5); 584 number_close_white_worms, NULL, 5); 585 } 586 587 /* Same as above but does not write to the worm array or update the 588 * close worms arrays. Intended to be used when stackp > 0. 589 */ 590 void 591 compute_effective_string_sizes(float effective_sizes[BOARDMAX]) 592 { 593 do_compute_effective_worm_sizes(BLACK | WHITE, NULL, NULL, 594 effective_sizes, 3); 575 595 } 576 596 577 597 static void 578 598 do_compute_effective_worm_sizes(int color, int (*cw)[MAX_CLOSE_WORMS], 579 int *ncw, int max_distance) 599 int *ncw, float *effective_sizes, 600 int max_distance) 580 601 { 581 602 int pos; 582 603 … … 647 668 } 648 669 } 649 670 650 /* Compute the effective sizes but only when all worms are considered. */ 651 if (color == (BLACK | WHITE)) { 671 /* Compute the effective sizes if caller wants them. */ 672 if (effective_sizes) { 673 for (pos = BOARDMIN; pos < BOARDMAX; pos++) 674 if (ON_BOARD(pos)) 675 effective_sizes[pos] = 0.0; 676 652 677 /* Distribute (fractional) contributions to the worms. */ 653 678 for (pos = BOARDMIN; pos < BOARDMAX; pos++) { 654 679 if (!ON_BOARD(pos)) … … 657 682 for (k = 0; k < nworms[pos]; k++) { 658 683 int w = worms[pos][k]; 659 684 if (board[pos] == EMPTY) 660 worm[w].effective_size+= 0.5/nworms[pos];685 effective_sizes[w] += 0.5/nworms[pos]; 661 686 else 662 worm[w].effective_size+= 1.0;687 effective_sizes[w] += 1.0; 663 688 } 664 689 } 665 666 /* Propagate the effective size values all over the worms. */667 for (pos = BOARDMIN; pos < BOARDMAX; pos++)668 if (IS_STONE(board[pos]) && is_worm_origin(pos, pos))669 propagate_worm(pos);670 690 } 671 691 672 692 /* Fill in the appropriate close_*_worms (cw) and … … 676 696 if (!ON_BOARD(pos)) 677 697 continue; 678 698 679 if (nworms[pos] > MAX_CLOSE_WORMS) 680 ncw[pos] = 0; 681 else 682 ncw[pos] = nworms[pos]; 699 if (ncw) { 700 if (nworms[pos] > MAX_CLOSE_WORMS) 701 ncw[pos] = 0; 702 else 703 ncw[pos] = nworms[pos]; 704 } 683 705 684 for (k = 0; k < ncw[pos]; k++) 685 cw[pos][k] = worms[pos][k]; 706 if (cw) 707 for (k = 0; k < ncw[pos]; k++) 708 cw[pos][k] = worms[pos][k]; 686 709 } 687 710 } 688 711 … … 1621 1644 * possible that it only has a ko defense and then we would 1622 1645 * risk to find an irrelevant move to attack with ko. 1623 1646 */ 1624 if (dcode != WIN && REVERSE_RESULT(dcode) >= worm[str].attack_codes[0]) { 1647 if (dcode != WIN 1648 && REVERSE_RESULT(dcode) >= worm[str].attack_codes[0]) { 1625 1649 change_attack(str, move, REVERSE_RESULT(dcode)); 1626 1650 DEBUG(DEBUG_WORMS, 1627 1651 "Attack pattern %s+%d found attack on %1m at %1m with code %d\n", … … 1732 1756 } 1733 1757 1734 1758 /* ================================================================ */ 1759 /* Static worm connection analysis */ 1760 /* ================================================================ */ 1761 1762 /* The static worm connection analysis uses the C patterns in conn.db 1763 * to find worms which are close enough so that the connection reading 1764 * can be expected to determine that they are expected unless there is 1765 * a serious connection problem. Then connection reading is done to 1766 * see which of these are indeed connected and intransitive 1767 * connections (A connected to B and B connected to C but A not 1768 * connected to C) are detected. 1769 * 1770 * The results are stored in a two-dimensional array for each pair of 1771 * worms. Only the worm origins have valid data. Each entry is an 1772 * unsigned char where the three lowest bits contain the disconnect 1773 * result code, the fourth bit marks potential connections (as found 1774 * by the C patterns in conn.db) and the fifth bit is set for pairs of 1775 * strings being intransitively connected. 1776 * 1777 * There are two parallel worm connection matrices. The primary one is 1778 * used at stackp==0 and contains the static information for the 1779 * original position. The secondary array is used when stackp>0, 1780 * primarily to allow computation of a new set of dragons after a move 1781 * has been made. 1782 */ 1783 static unsigned char primary_worm_connection_matrix[BOARDMAX][BOARDMAX]; 1784 static unsigned char secondary_worm_connection_matrix[BOARDMAX][BOARDMAX]; 1785 /* The three lowest bits in the matrix store the disconnect result. */ 1786 #define POTENTIAL_WORM_CONNECTION 8 1787 #define INTRANSITIVE_WORM_CONNECTION 16 1788 1789 void 1790 initialize_static_worm_connections(void) 1791 { 1792 int w1; 1793 int w2; 1794 1795 unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 1796 if (stackp == 0) 1797 worm_connection_matrix = &primary_worm_connection_matrix; 1798 else 1799 worm_connection_matrix = &secondary_worm_connection_matrix; 1800 1801 #if 0 1802 memset(worm_connection_matrix, 0, sizeof(worm_connection_matrix)); 1803 #else 1804 for (w1 = BOARDMIN; w1 < BOARDMAX; w1++) 1805 for (w2 = BOARDMIN; w2 < BOARDMAX; w2++) 1806 (*worm_connection_matrix)[w1][w2] = 0; 1807 #endif 1808 } 1809 1810 #define DEBUG_EXPERIMENTAL_CONNECTIONS \ 1811 ((debug & DEBUG_DRAGONS) && experimental_connections) 1812 1813 1814 void 1815 analyze_worm_connections() 1816 { 1817 int w1; 1818 int w2; 1819 int w3; 1820 1821 unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 1822 if (stackp == 0) 1823 worm_connection_matrix = &primary_worm_connection_matrix; 1824 else 1825 worm_connection_matrix = &secondary_worm_connection_matrix; 1826 1827 if (DEBUG_EXPERIMENTAL_CONNECTIONS) 1828 gprintf("analyze_worm_connections\n"); 1829 1830 for (w1 = BOARDMIN; w1 < BOARDMAX; w1++) { 1831 if (!IS_STONE(board[w1]) || w1 != find_origin(w1)) 1832 continue; 1833 1834 for (w2 = w1 + 1; w2 < BOARDMAX; w2++) { 1835 if (board[w2] != board[w1] || w2 != find_origin(w2)) 1836 continue; 1837 1838 if ((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) { 1839 int nodes = get_connection_node_counter(); 1840 unsigned char disconnect_result = disconnect(w1, w2, NULL); 1841 gg_assert(disconnect_result < 8); 1842 (*worm_connection_matrix)[w1][w2] |= disconnect_result; 1843 (*worm_connection_matrix)[w2][w1] |= disconnect_result; 1844 if (DEBUG_EXPERIMENTAL_CONNECTIONS) 1845 gprintf("disconnect %1m %1m = %d, %d nodes %d %d\n", w1, w2, 1846 disconnect_result, get_connection_node_counter() - nodes, 1847 (*worm_connection_matrix)[w1][w2], 1848 (*worm_connection_matrix)[w2][w1]); 1849 } 1850 } 1851 } 1852 1853 for (w1 = BOARDMIN; w1 < BOARDMAX; w1++) { 1854 if (!IS_STONE(board[w1]) || w1 != find_origin(w1)) 1855 continue; 1856 1857 for (w2 = BOARDMIN; w2 < BOARDMAX; w2++) { 1858 if (w2 == w1 || board[w2] != board[w1] || w2 != find_origin(w2)) 1859 continue; 1860 1861 if (!((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) 1862 || ((*worm_connection_matrix)[w1][w2] & 7) != 0) 1863 continue; 1864 1865 for (w3 = BOARDMIN; w3 < BOARDMAX; w3++) { 1866 if (w3 == w2 || board[w3] != board[w2] || w3 != find_origin(w3)) 1867 continue; 1868 1869 if (!((*worm_connection_matrix)[w2][w3] & POTENTIAL_WORM_CONNECTION) 1870 || ((*worm_connection_matrix)[w2][w3] & 7) != 0) 1871 continue; 1872 1873 if (((*worm_connection_matrix)[w1][w3] & POTENTIAL_WORM_CONNECTION) 1874 && ((*worm_connection_matrix)[w1][w3] & 7) != 0) { 1875 if (DEBUG_EXPERIMENTAL_CONNECTIONS) 1876 gprintf("intransitive connection %1m - %1m - %1m %d\n", w1, w2, w3, 1877 (*worm_connection_matrix)[w1][w3], 1878 (*worm_connection_matrix)[w3][w1]); 1879 (*worm_connection_matrix)[w1][w3] |= INTRANSITIVE_WORM_CONNECTION; 1880 (*worm_connection_matrix)[w3][w1] |= INTRANSITIVE_WORM_CONNECTION; 1881 } 1882 } 1883 } 1884 } 1885 } 1886 1887 static void 1888 normalize_worms(int *w1, int *w2) 1889 { 1890 *w1 = find_origin(*w1); 1891 *w2 = find_origin(*w2); 1892 } 1893 1894 void 1895 register_potential_worm_connection(int w1, int w2) 1896 { 1897 unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 1898 if (stackp == 0) 1899 worm_connection_matrix = &primary_worm_connection_matrix; 1900 else 1901 worm_connection_matrix = &secondary_worm_connection_matrix; 1902 1903 normalize_worms(&w1, &w2); 1904 if (DEBUG_EXPERIMENTAL_CONNECTIONS 1905 && !((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION)) 1906 gprintf("Registered potential worm connection %1m - %1m %d %d\n", w1, w2, 1907 (*worm_connection_matrix)[w1][w2], 1908 (*worm_connection_matrix)[w2][w1]); 1909 (*worm_connection_matrix)[w1][w2] |= POTENTIAL_WORM_CONNECTION; 1910 (*worm_connection_matrix)[w2][w1] |= POTENTIAL_WORM_CONNECTION; 1911 } 1912 1913 int 1914 worms_are_connected(int w1, int w2) 1915 { 1916 unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 1917 if (stackp == 0) 1918 worm_connection_matrix = &primary_worm_connection_matrix; 1919 else 1920 worm_connection_matrix = &secondary_worm_connection_matrix; 1921 1922 normalize_worms(&w1, &w2); 1923 if (((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) 1924 && ((*worm_connection_matrix)[w1][w2] & 7) == 0) 1925 return 1; 1926 1927 return 0; 1928 } 1929 1930 int 1931 worms_are_connected_with_ko(int w1, int w2) 1932 { 1933 unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 1934 if (stackp == 0) 1935 worm_connection_matrix = &primary_worm_connection_matrix; 1936 else 1937 worm_connection_matrix = &secondary_worm_connection_matrix; 1938 1939 normalize_worms(&w1, &w2); 1940 if (((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION) 1941 && (((*worm_connection_matrix)[w1][w2] & 7) == KO_A 1942 || ((*worm_connection_matrix)[w1][w2] & 7) == KO_B)) 1943 return 1; 1944 1945 return 0; 1946 } 1947 1948 int 1949 worms_are_close(int w1, int w2) 1950 { 1951 unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 1952 if (stackp == 0) 1953 worm_connection_matrix = &primary_worm_connection_matrix; 1954 else 1955 worm_connection_matrix = &secondary_worm_connection_matrix; 1956 1957 normalize_worms(&w1, &w2); 1958 return ((*worm_connection_matrix)[w1][w2] & POTENTIAL_WORM_CONNECTION); 1959 } 1960 1961 int 1962 worms_are_intransitively_connected(int w1, int w2) 1963 { 1964 unsigned char (*worm_connection_matrix)[BOARDMAX][BOARDMAX]; 1965 if (stackp == 0) 1966 worm_connection_matrix = &primary_worm_connection_matrix; 1967 else 1968 worm_connection_matrix = &secondary_worm_connection_matrix; 1969 1970 normalize_worms(&w1, &w2); 1971 return ((*worm_connection_matrix)[w1][w2] & INTRANSITIVE_WORM_CONNECTION); 1972 } 1973 1974 /* ================================================================ */ 1735 1975 /* Debugger functions */ 1736 1976 /* ================================================================ */ 1737 1977 -
patterns/conn.db
RCS file: /cvsroot/gnugo/gnugo/patterns/conn.db,v retrieving revision 1.43 diff -u -r1.43 conn.db
77 77 # 78 78 ######################## 79 79 80 callback_data X! 80 callback_data OX! 81 82 Pattern EB1 83 84 OxOxO 85 ..*.. 86 ----- 87 88 :|,BY 81 89 82 90 83 91 ########################## … … 86 94 # 87 95 ########################## 88 96 89 callback_data X!97 callback_data OX! 90 98 91 99 92 100 Pattern CB1b … … 443 451 # 444 452 ############################ 445 453 454 Pattern CC330 455 456 O.o 457 XOo 458 O.o 459 XOo 460 461 :8,CY 462 463 464 446 465 #################################################################### 447 466 # 448 467 # CC4xx - fragile double connections … … 489 508 Xaf 490 509 ?e. 491 510 492 ;xcut(a) 511 ;xcut(a) && !experimental_connections 493 512 494 513 >if (!xplay_attack_either(b,c,d,b,d) || !xplay_attack_either(c,b,a,c,a)) 495 514 > amalgamate(e,f); -
patterns/connections.c
RCS file: /cvsroot/gnugo/gnugo/patterns/connections.c,v retrieving revision 1.44 diff -u -r1.44 connections.c
40 40 int first_dragon = NO_MOVE; 41 41 int second_dragon = NO_MOVE; 42 42 43 /* Strings of our color. */ 44 int o_strings[BOARDMAX]; 45 int o_nstrings = 0; 46 43 47 int other = OTHER_COLOR(color); 44 48 UNUSED(data); 45 49 46 50 move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor); 47 51 48 if ((pattern->class & CLASS_B) && !safe_move(move, other)) 52 if ((pattern->class & CLASS_B) && !safe_move(move, other) 53 && !experimental_connections) 54 return; 55 56 if ((pattern->class & CLASS_Y) && !experimental_connections) 49 57 return; 50 58 51 if ( pattern->class & CLASS_C) {59 if ((pattern->class & CLASS_C) || experimental_connections) { 52 60 /* If C pattern, test if there are more than one dragon in this 53 61 * pattern so that there is something to connect, before doing any 54 62 * expensive reading. … … 57 65 for (k = 0; k < pattern->patlen; ++k) { /* match each point */ 58 66 /* transform pattern real coordinate */ 59 67 int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor); 60 61 /* Look for distinct dragons. */ 68 62 69 if (pattern->patn[k].att == ATT_O) { 63 if (first_dragon == NO_MOVE) 64 first_dragon = dragon[pos].origin; 65 else if (second_dragon == NO_MOVE 66 && dragon[pos].origin != first_dragon) { 67 second_dragon = dragon[pos].origin; 68 /* A second dragon found, no need to continue looping. */ 69 break; 70 if (!experimental_connections) { 71 /* Look for distinct dragons. */ 72 if (first_dragon == NO_MOVE) 73 first_dragon = dragon[pos].origin; 74 else if (second_dragon == NO_MOVE 75 && dragon[pos].origin != first_dragon) { 76 second_dragon = dragon[pos].origin; 77 /* A second dragon found, no need to continue looping. */ 78 break; 79 } 80 } 81 else { 82 int origin = find_origin(pos); 83 int l; 84 for (l = 0; l < o_nstrings; l++) { 85 if (o_strings[l] == origin) 86 break; 87 } 88 if (l == o_nstrings) { 89 for (l = 0; l < o_nstrings; l++) 90 register_potential_worm_connection(o_strings[l], origin); 91 o_strings[l] = origin; 92 o_nstrings++; 93 } 70 94 } 71 95 } 72 96 } 73 if ( second_dragon == NO_MOVE)97 if (!experimental_connections && second_dragon == NO_MOVE) 74 98 return; /* Nothing to amalgamate. */ 75 99 } 76 100 … … 144 168 * can be attacked. 145 169 */ 146 170 if ((pattern->class & CLASS_C) 171 && !experimental_connections 147 172 && board[pos] == color 148 173 && pattern->patn[k].att == ATT_O 149 174 && ((pattern->class & CLASS_s) || attack(pos, NULL) == 0)) { -
patterns/helpers.c
RCS file: /cvsroot/gnugo/gnugo/patterns/helpers.c,v retrieving revision 1.72 diff -u -r1.72 helpers.c
428 428 void 429 429 amalgamate_most_valuable_helper(int apos, int bpos, int cpos) 430 430 { 431 if (experimental_connections) 432 return; 431 433 if (!is_same_dragon(apos, bpos) && !is_same_dragon(bpos, cpos)) { 432 434 if (dragon[apos].effective_size >= dragon[cpos].effective_size) 433 435 join_dragons(apos, bpos); -
patterns/owl_defendpats.db
RCS file: /cvsroot/gnugo/gnugo/patterns/owl_defendpats.db,v retrieving revision 1.133 diff -u -r1.133 owl_defendpats.db
7074 7074 ;&& oplay_disconnect(*,a,b) != WIN 7075 7075 7076 7076 7077 Pattern D1396 7078 # gf New pattern. (3.7.5) 7079 # See gifu03:404 7080 7081 O...O 7082 .*.O. 7083 ----- 7084 7085 :8,b,value(80) 7086 7087 B...A 7088 .*.O. 7089 ----- 7090 7091 ;attack(A) && owl_strong_dragon(B) && !oplay_disconnect(*,A,B) 7092 7093 7077 7094 ######################################################### 7078 7095 # # 7079 7096 # Ko # -
patterns/patterns2.db
RCS file: /cvsroot/gnugo/gnugo/patterns/patterns2.db,v retrieving revision 1.82 diff -u -r1.82 patterns2.db
852 852 ;oplay_attack_either(*,a,B,a) && !oplay_attack(*,c) && !oplay_attack(*,d) 853 853 854 854 855 Pattern Conn612 856 857 O*O. 858 XOXO 859 860 :8,C 861 862 855 863 ############################################## 856 864 # 857 865 # Connection of two space jump from two stones
