diff -N -r -u -X .ignore gnugo-copy/engine/reading.c gnugo/engine/reading.c
|
old
|
new
|
|
| 484 | 484 | * is a frontend to the attack() and find_defense() functions, which |
| 485 | 485 | * guarantees a consistent result. If a string cannot be attacked, 0 |
| 486 | 486 | * is returned and acode is 0. If a string can be attacked and |
| 487 | | * defended, WIN is returned, acode and dcode are both non-zero, and |
| | 487 | * defended, 1 is returned, acode and dcode are both non-zero, and |
| 488 | 488 | * (attack_point), (defense_point) both point to vertices on the board. |
| 489 | 489 | * If a string can be attacked but not defended, 0 is again returned, |
| 490 | 490 | * acode is non-zero, dcode is 0, and (attack_point) points to a vertex |
| … |
… |
|
| 507 | 507 | int dpos = NO_MOVE; |
| 508 | 508 | |
| 509 | 509 | acode = attack(str, &apos); |
| 510 | | if (acode != 0) |
| | 510 | if (acode) |
| 511 | 511 | dcode = find_defense(str, &dpos); |
| 512 | 512 | |
| 513 | 513 | ASSERT1(!(acode != 0 && dcode == WIN && dpos == NO_MOVE), str); |
| … |
… |
|
| 521 | 521 | if (defense_point) |
| 522 | 522 | *defense_point = dpos; |
| 523 | 523 | |
| 524 | | return acode != 0 && dcode != 0; |
| | 524 | return acode && dcode; |
| 525 | 525 | } |
| 526 | 526 | |
| 527 | 527 | |
| … |
… |
|
| 1021 | 1021 | |
| 1022 | 1022 | |
| 1023 | 1023 | /* Return up to max_threats threats to capture the string at str. |
| 1024 | | * If the string is directly attackable the number of threats |
| 1025 | | * is reported to be 0. |
| | 1024 | * The function should be called only when the string is not directly |
| | 1025 | * attackable. |
| 1026 | 1026 | * |
| 1027 | 1027 | * NOTE: You can call attack_threats with moves[] and codes[] |
| 1028 | 1028 | * already partly filled in. So if you want to get the |
| 1029 | 1029 | * threats from scratch, you have to set them to 0 |
| 1030 | 1030 | * yourself. |
| 1031 | | * |
| 1032 | | * FIXME: Shall we report upgrades, like we can capture in ko but |
| 1033 | | * have a threat to capture unconditionally? |
| 1034 | 1031 | */ |
| 1035 | 1032 | |
| 1036 | 1033 | int |
| 1037 | 1034 | attack_threats(int str, int max_points, int moves[], int codes[]) |
| 1038 | 1035 | { |
| 1039 | 1036 | int other; |
| 1040 | | int num_threats; |
| 1041 | 1037 | int liberties; |
| 1042 | 1038 | int libs[MAXLIBS]; |
| 1043 | | int num_adj; |
| | 1039 | int *cur_lib, *last_lib; |
| 1044 | 1040 | int adjs[MAXCHAIN]; |
| 1045 | | int k; |
| 1046 | | int l; |
| | 1041 | int *cur_adj, *last_adj; |
| 1047 | 1042 | int r; |
| 1048 | 1043 | int discard; |
| | 1044 | int aa, bb; |
| | 1045 | int acode; |
| | 1046 | const int *cur_delta; |
| 1049 | 1047 | |
| 1050 | 1048 | ASSERT1(IS_STONE(board[str]), str); |
| | 1049 | ASSERT1(!attack(str, NULL), str); |
| 1051 | 1050 | |
| 1052 | | /* Only handle strings with no way to capture immediately. |
| 1053 | | * For now, we treat ko the same as unconditionally. */ |
| 1054 | | if (attack(str, NULL) != 0) |
| 1055 | | return 0; |
| | 1051 | other = OTHER_COLOR(board[str]); |
| | 1052 | liberties = findlib(str, MAXLIBS, libs); |
| 1056 | 1053 | |
| 1057 | 1054 | /* This test would seem to be unnecessary since we only threaten |
| 1058 | 1055 | * strings with attack_code == 0, but it turns out that single |
| … |
… |
|
| 1061 | 1058 | * |
| 1062 | 1059 | * The test against 6 liberties is just an optimization. |
| 1063 | 1060 | */ |
| 1064 | | other = OTHER_COLOR(board[str]); |
| 1065 | | liberties = findlib(str, MAXLIBS, libs); |
| 1066 | | if (liberties > 1 && liberties < 6) { |
| 1067 | | for (k = 0; k < liberties; k++) { |
| 1068 | | int aa = libs[k]; |
| | 1061 | if (liberties == 1) |
| | 1062 | change_tactical_point(str, libs[0], WIN, moves, codes, |
| | 1063 | worm[str].discarded_att_threats); |
| | 1064 | else if (liberties < 6) { |
| | 1065 | cur_lib = libs; |
| | 1066 | last_lib = cur_lib + liberties; |
| | 1067 | |
| | 1068 | for (; cur_lib < last_lib; cur_lib++) { |
| | 1069 | aa = *cur_lib; |
| 1069 | 1070 | |
| 1070 | 1071 | /* Try to threaten on the liberty. */ |
| 1071 | 1072 | if (trymove(aa, other, "attack_threats-A", str)) { |
| 1072 | | int acode = attack(str, NULL); |
| 1073 | | if (acode != 0) |
| | 1073 | acode = attack(str, NULL); |
| | 1074 | if (acode) |
| 1074 | 1075 | change_tactical_point(str, aa, acode, moves, codes, |
| 1075 | 1076 | worm[str].discarded_att_threats); |
| 1076 | 1077 | popgo(); |
| 1077 | 1078 | } |
| 1078 | 1079 | |
| 1079 | 1080 | /* Try to threaten on second order liberties. */ |
| 1080 | | for (l = 0; l < 4; l++) { |
| 1081 | | int bb = libs[k] + delta[l]; |
| | 1081 | for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { |
| | 1082 | bb = aa + *cur_delta; |
| 1082 | 1083 | |
| 1083 | | if (!ON_BOARD(bb) |
| 1084 | | || IS_STONE(board[bb]) |
| | 1084 | if (board[bb] |
| 1085 | 1085 | || attack_threat_move_known(bb, str) |
| 1086 | 1086 | || discarded_move_known(bb, MAX_TACTICAL_POINTS, |
| 1087 | 1087 | worm[str].discarded_att_threats) |
| … |
… |
|
| 1091 | 1091 | discard = 1; |
| 1092 | 1092 | |
| 1093 | 1093 | if (trymove(bb, other, "attack_threats-B", str)) { |
| 1094 | | int acode = attack(str, NULL); |
| 1095 | | if (acode != 0) { |
| | 1094 | acode = attack(str, NULL); |
| | 1095 | if (acode) { |
| 1096 | 1096 | change_tactical_point(str, bb, acode, moves, codes, |
| 1097 | 1097 | worm[str].discarded_att_threats); |
| 1098 | 1098 | discard = 0; |
| … |
… |
|
| 1108 | 1108 | } |
| 1109 | 1109 | |
| 1110 | 1110 | /* Threaten to attack by saving weak neighbors. */ |
| 1111 | | num_adj = chainlinks(str, adjs); |
| 1112 | | for (k = 0; k < num_adj; k++) { |
| 1113 | | int bb; |
| 1114 | | int acode; |
| | 1111 | cur_adj = adjs; |
| | 1112 | last_adj = cur_adj + chainlinks(str, adjs); |
| | 1113 | for (; cur_adj < last_adj; cur_adj++) { |
| 1115 | 1114 | int dcode; |
| 1116 | 1115 | |
| 1117 | | attack_and_defend(adjs[k], &acode, NULL, &dcode, NULL); |
| 1118 | | if (acode == 0 || dcode == 0) |
| | 1116 | if (!attack_and_defend(*cur_adj, &acode, NULL, &dcode, NULL)) |
| 1119 | 1117 | continue; |
| 1120 | 1118 | |
| 1121 | 1119 | /* Step through all defense points. */ |
| 1122 | 1120 | for (r = 0; r < max_points; r++) { |
| 1123 | | if (worm[adjs[k]].defense_codes[r] == 0) |
| | 1121 | if (!worm[*cur_adj].defense_codes[r]) |
| 1124 | 1122 | break; |
| 1125 | | bb = worm[adjs[k]].defense_points[r]; |
| | 1123 | bb = worm[*cur_adj].defense_points[r]; |
| | 1124 | |
| | 1125 | if (attack_threat_move_known(bb, str) |
| | 1126 | || discarded_move_known(bb, MAX_TACTICAL_POINTS, |
| | 1127 | worm[str].discarded_att_threats)) |
| | 1128 | continue; |
| | 1129 | |
| | 1130 | discard = 1; |
| 1126 | 1131 | |
| 1127 | 1132 | /* Test the move and see if it is a threat. */ |
| 1128 | 1133 | if (trymove(bb, other, "attack_threats-C", str)) { |
| 1129 | | if (board[str] == EMPTY) |
| | 1134 | if (!board[str]) |
| 1130 | 1135 | acode = WIN; |
| 1131 | 1136 | else |
| 1132 | 1137 | acode = attack(str, NULL); |
| 1133 | | if (acode != 0) |
| | 1138 | if (acode) { |
| 1134 | 1139 | change_tactical_point(str, bb, acode, moves, codes, |
| 1135 | 1140 | worm[str].discarded_att_threats); |
| | 1141 | discard = 0; |
| | 1142 | } |
| 1136 | 1143 | popgo(); |
| 1137 | 1144 | } |
| | 1145 | |
| | 1146 | if (discard) |
| | 1147 | movelist_change_discarded(bb, MAX_TACTICAL_POINTS, |
| | 1148 | worm[str].discarded_att_threats); |
| 1138 | 1149 | } |
| 1139 | 1150 | } |
| 1140 | 1151 | |
| 1141 | 1152 | /* Return actual number of threats found regardless of attack code. */ |
| 1142 | | for (num_threats = 0; num_threats < max_points; num_threats++) |
| 1143 | | if (codes[num_threats] == 0) |
| | 1153 | for (r = 0; r < max_points; r++) |
| | 1154 | if (!codes[r]) |
| 1144 | 1155 | break; |
| 1145 | | return num_threats; |
| | 1156 | return r; |
| 1146 | 1157 | } |
| 1147 | 1158 | |
| 1148 | 1159 | |
diff -N -r -u -X .ignore gnugo-copy/engine/worm.c gnugo/engine/worm.c
|
old
|
new
|
|
| 822 | 822 | */ |
| 823 | 823 | if (!send_two_return_one(pos, other) |
| 824 | 824 | && trymove(pos, other, "make_worms", str)) { |
| 825 | | if (board[str] == EMPTY || attack(str, NULL)) { |
| 826 | | if (board[str] == EMPTY) |
| | 825 | if (!board[str] || attack(str, NULL)) { |
| | 826 | if (!board[str]) |
| 827 | 827 | dcode = 0; |
| 828 | 828 | else |
| 829 | 829 | dcode = find_defense(str, NULL); |
| … |
… |
|
| 863 | 863 | { |
| 864 | 864 | int str; |
| 865 | 865 | static int libs[MAXLIBS]; |
| 866 | | int liberties; |
| 867 | | |
| 868 | | int k; |
| 869 | | int l; |
| | 866 | int *cur_lib, *last_lib; |
| | 867 | int aa, bb; |
| 870 | 868 | int color; |
| 871 | 869 | int discard; |
| | 870 | int dcode, worm_dcode; |
| | 871 | const int *cur_delta; |
| 872 | 872 | |
| 873 | 873 | for (str = BOARDMIN; str < BOARDMAX; str++) { |
| 874 | | color = board[str]; |
| 875 | | if (!IS_STONE(color) || !is_worm_origin(str, str)) |
| | 874 | if (!IS_STONE(board[str]) || !is_worm_origin(str, str)) |
| 876 | 875 | continue; |
| 877 | 876 | |
| | 877 | color = board[str]; |
| | 878 | |
| 878 | 879 | /* 1. Start with finding attack threats. */ |
| 879 | 880 | /* Only try those worms that have no attack. */ |
| 880 | | if (worm[str].attack_codes[0] == 0) { |
| | 881 | if (!worm[str].attack_codes[0]) { |
| 881 | 882 | attack_threats(str, MAX_TACTICAL_POINTS, |
| 882 | 883 | worm[str].attack_threat_points, |
| 883 | 884 | worm[str].attack_threat_codes); |
| 884 | | #if 0 |
| 885 | | /* Threaten to attack by saving weak neighbors. */ |
| 886 | | num_adj = chainlinks(str, adjs); |
| 887 | | for (k = 0; k < num_adj; k++) { |
| 888 | | if (worm[adjs[k]].attack_codes[0] != 0 |
| 889 | | && worm[adjs[k]].defense_codes[0] != 0) |
| 890 | | for (r = 0; r < MAX_TACTICAL_POINTS; r++) { |
| 891 | | int bb; |
| 892 | | |
| 893 | | if (worm[adjs[k]].defense_codes[r] == 0) |
| 894 | | break; |
| 895 | | bb = worm[adjs[k]].defense_points[r]; |
| 896 | | if (trymove(bb, other, "threaten attack", str, |
| 897 | | EMPTY, NO_MOVE)) { |
| 898 | | int acode; |
| 899 | | if (board[str] == EMPTY) |
| 900 | | acode = WIN; |
| 901 | | else |
| 902 | | acode = attack(str, NULL); |
| 903 | | if (acode != 0) |
| 904 | | change_attack_threat(str, bb, acode); |
| 905 | | popgo(); |
| 906 | | } |
| 907 | | } |
| 908 | | } |
| 909 | | #endif |
| | 885 | |
| 910 | 886 | /* FIXME: Try other moves also (patterns?). */ |
| 911 | 887 | } |
| 912 | 888 | |
| 913 | 889 | /* 2. Continue with finding defense threats. */ |
| 914 | 890 | /* Only try those worms that have an attack. */ |
| 915 | | if (worm[str].attack_codes[0] != 0 |
| 916 | | && worm[str].defense_codes[0] == 0) { |
| | 891 | else { |
| | 892 | worm_dcode = worm[str].defense_codes[0]; |
| 917 | 893 | |
| 918 | | liberties = findlib(str, MAXLIBS, libs); |
| | 894 | cur_lib = libs; |
| | 895 | last_lib = cur_lib + findlib(str, MAXLIBS, libs); |
| 919 | 896 | |
| 920 | | for (k = 0; k < liberties; k++) { |
| 921 | | int aa = libs[k]; |
| | 897 | for (; cur_lib < last_lib; cur_lib++) { |
| | 898 | aa = *cur_lib; |
| | 899 | |
| | 900 | discard = 1; |
| 922 | 901 | |
| 923 | 902 | /* Try to threaten on the liberty. */ |
| 924 | 903 | if (trymove(aa, color, "threaten defense", NO_MOVE)) { |
| 925 | | if (attack(str, NULL) == WIN) { |
| 926 | | int dcode = find_defense(str, NULL); |
| 927 | | if (dcode != 0) |
| 928 | | change_defense_threat(str, aa, dcode); |
| | 904 | dcode = find_defense(str, NULL); |
| | 905 | if (dcode > worm_dcode) { |
| | 906 | change_defense_threat(str, aa, dcode); |
| | 907 | discard = 0; |
| 929 | 908 | } |
| 930 | 909 | popgo(); |
| 931 | 910 | } |
| | 911 | |
| | 912 | if (discard) |
| | 913 | movelist_change_discarded(aa, MAX_TACTICAL_POINTS, |
| | 914 | worm[str].discarded_def_threats); |
| 932 | 915 | |
| 933 | 916 | /* Try to threaten on second order liberties. */ |
| 934 | | for (l = 0; l < 4; l++) { |
| 935 | | int bb = libs[k] + delta[l]; |
| | 917 | for (cur_delta = delta; cur_delta < last_delta_4; cur_delta++) { |
| | 918 | bb = aa + *cur_delta; |
| 936 | 919 | |
| 937 | | if (!ON_BOARD(bb) |
| 938 | | || IS_STONE(board[bb]) |
| | 920 | if (board[bb] |
| 939 | 921 | || defense_threat_move_known(bb, str) |
| 940 | 922 | || discarded_move_known(bb, MAX_TACTICAL_POINTS, |
| 941 | 923 | worm[str].discarded_def_threats) |
| … |
… |
|
| 945 | 927 | discard = 1; |
| 946 | 928 | |
| 947 | 929 | if (trymove(bb, color, "threaten defense", str)) { |
| 948 | | if (attack(str, NULL) == WIN) { |
| 949 | | int dcode = find_defense(str, NULL); |
| 950 | | if (dcode != 0) { |
| 951 | | change_defense_threat(str, bb, dcode); |
| 952 | | discard = 0; |
| 953 | | } |
| | 930 | dcode = find_defense(str, NULL); |
| | 931 | if (dcode > worm_dcode) { |
| | 932 | change_defense_threat(str, bb, dcode); |
| | 933 | discard = 0; |
| 954 | 934 | } |
| 955 | 935 | popgo(); |
| 956 | 936 | } |
| … |
… |
|
| 961 | 941 | } |
| 962 | 942 | } |
| 963 | 943 | |
| 964 | | /* It might be interesting to look for defense threats by |
| | 944 | /* FIXME: It might be interesting to look for defense threats by |
| 965 | 945 | * attacking weak neighbors, similar to threatening attack by |
| 966 | 946 | * defending a weak neighbor. However, in this case it seems |
| 967 | 947 | * probable that if there is such an attack, it's a real |
diff -N -r -u -X .ignore gnugo-copy/regression/nngs.tst gnugo/regression/nngs.tst
|
old
|
new
|
|
| 993 | 993 | #CATEGORY=OWL_TUNING |
| 994 | 994 | loadsgf games/nngs/LordOfPi-gnugo-3.1.20-200201202014.sgf 36 |
| 995 | 995 | 2060 reg_genmove black |
| 996 | | #? [C4|C1|F1] |
| | 996 | #? [C4] |