RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.247
diff -u -r1.247 owl.c
|
|
|
|
| 118 | 118 | |
| 119 | 119 | #define MAX_CUTS 5 |
| 120 | 120 | |
| | 121 | enum same_dragon_value { |
| | 122 | SAME_DRAGON_NOT_CONNECTED, |
| | 123 | SAME_DRAGON_MAYBE_CONNECTED, |
| | 124 | SAME_DRAGON_CONNECTED, |
| | 125 | SAME_DRAGON_ALL_CONNECTED |
| | 126 | }; |
| | 127 | |
| | 128 | struct matched_pattern_data; |
| | 129 | |
| 121 | 130 | struct owl_move_data { |
| 122 | 131 | int pos; /* move coordinate */ |
| 123 | 132 | int value; /* value */ |
| 124 | 133 | const char *name; /* name of the pattern suggesting the move */ |
| 125 | | int same_dragon; /* whether the move extends the dragon or not */ |
| | 134 | /* whether the move extends the dragon or not */ |
| | 135 | enum same_dragon_value same_dragon; |
| 126 | 136 | int lunch; /* Position of a lunch, if applicable.*/ |
| 127 | 137 | int escape; /* true if an escape pattern is matched */ |
| 128 | 138 | int defense_pos; /* defense coordinate for vital owl attack patterns. */ |
| 129 | 139 | int cuts[MAX_CUTS]; /* strings of the goal that might get cut off */ |
| | 140 | /* pointer to pattern data, used for SAME_DRAGON_ALL_CONNECTED */ |
| | 141 | struct matched_pattern_data *pattern_data; |
| 130 | 142 | }; |
| 131 | 143 | |
| 132 | 144 | #define USE_BDIST 1 |
| … |
… |
|
| 187 | 199 | struct pattern *pattern_db, |
| 188 | 200 | int ll, void *data); |
| 189 | 201 | static void owl_add_move(struct owl_move_data *moves, int move, int value, |
| 190 | | const char *reason, int same_dragon, int lunch, |
| 191 | | int escape, int defense_pos, int max_moves); |
| | 202 | const char *reason, |
| | 203 | enum same_dragon_value same_dragon, int lunch, |
| | 204 | int escape, int defense_pos, int max_moves, |
| | 205 | struct matched_pattern_data *pattern_data); |
| 192 | 206 | static void owl_determine_life(struct local_owl_data *owl, |
| 193 | 207 | struct local_owl_data *second_owl, |
| 194 | 208 | int does_attack, |
| … |
… |
|
| 216 | 230 | static void owl_mark_worm(int apos, int bpos, |
| 217 | 231 | struct local_owl_data *owl); |
| 218 | 232 | static void owl_mark_boundary(struct local_owl_data *owl); |
| 219 | | static void owl_update_goal(int pos, int same_dragon, int lunch, |
| 220 | | struct local_owl_data *owl, int semeai_call); |
| | 233 | static void owl_update_goal(int pos, enum same_dragon_value same_dragon, |
| | 234 | int lunch, struct local_owl_data *owl, |
| | 235 | int semeai_call, |
| | 236 | struct matched_pattern_data *pattern_data); |
| 221 | 237 | static void owl_test_cuts(signed char goal[BOARDMAX], int color, |
| 222 | 238 | int cuts[MAX_CUTS]); |
| 223 | 239 | static void componentdump(const signed char component[BOARDMAX]); |
| … |
… |
|
| 246 | 262 | int owl_phase, |
| 247 | 263 | int move, int color, int ko_allowed, |
| 248 | 264 | int move_value, const char *move_name, |
| 249 | | int same_dragon, int lunch, |
| 250 | | int *semeai_move, |
| | 265 | enum same_dragon_value same_dragon, |
| | 266 | struct matched_pattern_data *pattern_data, |
| | 267 | int lunch, int *semeai_move, |
| 251 | 268 | int *this_resulta, int *this_resultb); |
| 252 | 269 | static void semeai_add_sgf_comment(int value, int owl_phase); |
| 253 | 270 | static int semeai_trust_tactical_attack(int str); |
| … |
… |
|
| 556 | 573 | resulta, resultb, semeai_move, 0, owl); |
| 557 | 574 | else { |
| 558 | 575 | semeai_trymove_and_recurse(bpos, apos, owlb, owla, owl, |
| 559 | | move, color, 1, 0, "mandatory move", 1, NO_MOVE, |
| | 576 | move, color, 1, 0, "mandatory move", |
| | 577 | SAME_DRAGON_MAYBE_CONNECTED, NULL, NO_MOVE, |
| 560 | 578 | semeai_move, resultb, resulta); |
| 561 | 579 | *resulta = REVERSE_RESULT(*resulta); |
| 562 | 580 | *resultb = REVERSE_RESULT(*resultb); |
| … |
… |
|
| 703 | 721 | moves[k].pos = 0; |
| 704 | 722 | moves[k].value = -1; |
| 705 | 723 | moves[k].name = NULL; |
| 706 | | moves[k].same_dragon = 2; |
| | 724 | moves[k].same_dragon = SAME_DRAGON_CONNECTED; |
| 707 | 725 | moves[k].lunch = NO_MOVE; |
| 708 | 726 | clear_cut_list(moves[k].cuts); |
| 709 | 727 | } |
| … |
… |
|
| 742 | 760 | else if (acode != 0 |
| 743 | 761 | && find_defense(semeai_worms[sworm], NULL)) { |
| 744 | 762 | critical_semeai_worms[sworm] = 1; |
| 745 | | owl_add_move(moves, upos, 105, "attack semeai worm", 1, |
| 746 | | NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES); |
| | 763 | owl_add_move(moves, upos, 105, "attack semeai worm", |
| | 764 | SAME_DRAGON_MAYBE_CONNECTED, |
| | 765 | NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 747 | 766 | TRACE("Added %1m %d (-1)\n", upos, 105); |
| 748 | 767 | } |
| 749 | 768 | else if (acode == WIN |
| 750 | 769 | && important_semeai_worms[sworm]) { |
| 751 | | owl_add_move(moves, upos, 100, "attack semeai worm", 1, |
| 752 | | NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES); |
| | 770 | owl_add_move(moves, upos, 100, "attack semeai worm", |
| | 771 | SAME_DRAGON_MAYBE_CONNECTED, |
| | 772 | NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 753 | 773 | TRACE("Added %1m %d (-1)\n", upos, 100); |
| 754 | 774 | } |
| 755 | 775 | } |
| … |
… |
|
| 767 | 787 | if (attack(semeai_worms[sworm], NULL) |
| 768 | 788 | && find_defense(semeai_worms[sworm], &upos)) { |
| 769 | 789 | critical_semeai_worms[sworm] = 1; |
| 770 | | owl_add_move(moves, upos, 85, "defend semeai worm", 1, NO_MOVE, |
| 771 | | 0, NO_MOVE, MAX_SEMEAI_MOVES); |
| | 790 | owl_add_move(moves, upos, 85, "defend semeai worm", |
| | 791 | SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE, |
| | 792 | 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 772 | 793 | TRACE("Added %1m %d (0)\n", upos, 85); |
| 773 | 794 | } |
| 774 | 795 | } |
| … |
… |
|
| 1006 | 1027 | owla, owlb, 50, |
| 1007 | 1028 | critical_semeai_worms); |
| 1008 | 1029 | owl_add_move(moves, outside_liberty.pos, move_value, |
| 1009 | | "safe outside liberty", 0, NO_MOVE, 0, NO_MOVE, |
| 1010 | | MAX_SEMEAI_MOVES); |
| | 1030 | "safe outside liberty", SAME_DRAGON_NOT_CONNECTED, |
| | 1031 | NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 1011 | 1032 | riskless_move_found = 1; |
| 1012 | 1033 | TRACE("Added %1m %d (5)\n", outside_liberty.pos, move_value); |
| 1013 | 1034 | } |
| … |
… |
|
| 1016 | 1037 | owla, owlb, 50, |
| 1017 | 1038 | critical_semeai_worms); |
| 1018 | 1039 | owl_add_move(moves, backfill_outside_liberty.pos, move_value, |
| 1019 | | "backfilling move", 0, NO_MOVE, 0, |
| 1020 | | NO_MOVE, MAX_SEMEAI_MOVES); |
| | 1040 | "backfilling move", SAME_DRAGON_NOT_CONNECTED, NO_MOVE, 0, |
| | 1041 | NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 1021 | 1042 | riskless_move_found = 1; |
| 1022 | 1043 | TRACE("Added %1m %d (6)\n", backfill_outside_liberty.pos, move_value); |
| 1023 | 1044 | } |
| … |
… |
|
| 1027 | 1048 | owla, owlb, 10, |
| 1028 | 1049 | critical_semeai_worms); |
| 1029 | 1050 | owl_add_move(moves, common_liberty.pos, move_value, |
| 1030 | | "safe common liberty", 1, NO_MOVE, 0, |
| 1031 | | NO_MOVE, MAX_SEMEAI_MOVES); |
| | 1051 | "safe common liberty", SAME_DRAGON_MAYBE_CONNECTED, |
| | 1052 | NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 1032 | 1053 | if (semeai_is_riskless_move(common_liberty.pos, owla)) |
| 1033 | 1054 | riskless_move_found = 1; |
| 1034 | 1055 | TRACE("Added %1m %d (7)\n", common_liberty.pos, move_value); |
| … |
… |
|
| 1038 | 1059 | owla, owlb, 10, |
| 1039 | 1060 | critical_semeai_worms); |
| 1040 | 1061 | owl_add_move(moves, backfill_common_liberty.pos, move_value, |
| 1041 | | "backfilling move", 0, NO_MOVE, 0, |
| 1042 | | NO_MOVE, MAX_SEMEAI_MOVES); |
| | 1062 | "backfilling move", SAME_DRAGON_NOT_CONNECTED, NO_MOVE, 0, |
| | 1063 | NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 1043 | 1064 | if (semeai_is_riskless_move(backfill_common_liberty.pos, owla)) |
| 1044 | 1065 | riskless_move_found = 1; |
| 1045 | 1066 | TRACE("Added %1m %d (6)\n", backfill_common_liberty.pos, move_value); |
| … |
… |
|
| 1054 | 1075 | int move = semeai_propose_eyespace_filling_move(owla, owlb); |
| 1055 | 1076 | |
| 1056 | 1077 | if (move) { |
| 1057 | | owl_add_move(moves, move, 70, "eyespace filling", 0, NO_MOVE, |
| 1058 | | 0, NO_MOVE, MAX_SEMEAI_MOVES); |
| | 1078 | owl_add_move(moves, move, 70, "eyespace filling", |
| | 1079 | SAME_DRAGON_NOT_CONNECTED, NO_MOVE, |
| | 1080 | 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL); |
| 1059 | 1081 | } |
| 1060 | 1082 | } |
| 1061 | 1083 | |
| … |
… |
|
| 1097 | 1119 | owl_phase, mpos, color, |
| 1098 | 1120 | best_resulta == 0 || best_resultb == 0, |
| 1099 | 1121 | moves[k].value, moves[k].name, |
| 1100 | | moves[k].same_dragon, moves[k].lunch, |
| 1101 | | NULL, &this_resulta, &this_resultb)) { |
| | 1122 | moves[k].same_dragon, moves[k].pattern_data, |
| | 1123 | moves[k].lunch, NULL, |
| | 1124 | &this_resulta, &this_resultb)) { |
| 1102 | 1125 | tested_moves++; |
| 1103 | 1126 | if (this_resultb == WIN && this_resulta == WIN) { |
| 1104 | 1127 | /* Ideal result, no need to try any more moves. */ |
| … |
… |
|
| 1249 | 1272 | int owl_phase, |
| 1250 | 1273 | int move, int color, int ko_allowed, |
| 1251 | 1274 | int move_value, const char *move_name, |
| 1252 | | int same_dragon, int lunch, int *semeai_move, |
| | 1275 | enum same_dragon_value same_dragon, |
| | 1276 | struct matched_pattern_data *pattern_data, |
| | 1277 | int lunch, int *semeai_move, |
| 1253 | 1278 | int *this_resulta, int *this_resultb) |
| 1254 | 1279 | { |
| 1255 | 1280 | int ko_move = 0; |
| … |
… |
|
| 1275 | 1300 | push_owl(&owlb); |
| 1276 | 1301 | |
| 1277 | 1302 | if (owla->color == color) { |
| 1278 | | owl_update_goal(move, same_dragon, lunch, owla, 1); |
| | 1303 | owl_update_goal(move, same_dragon, lunch, owla, 1, pattern_data); |
| 1279 | 1304 | owl_update_boundary_marks(move, owlb); |
| 1280 | 1305 | } |
| 1281 | 1306 | else { |
| 1282 | | owl_update_goal(move, same_dragon, lunch, owlb, 1); |
| | 1307 | owl_update_goal(move, same_dragon, lunch, owlb, 1, pattern_data); |
| 1283 | 1308 | owl_update_boundary_marks(move, owla); |
| 1284 | 1309 | } |
| 1285 | 1310 | mark_goal_in_sgf(owla->goal); |
| … |
… |
|
| 1418 | 1443 | { |
| 1419 | 1444 | int move; |
| 1420 | 1445 | int move_value; |
| 1421 | | int same_dragon; |
| | 1446 | enum same_dragon_value same_dragon; |
| | 1447 | struct matched_pattern_data *pattern_data = NULL; |
| 1422 | 1448 | int k; |
| 1423 | 1449 | |
| 1424 | 1450 | for (k = 0; k < MAX_MOVES-1; k++) { |
| … |
… |
|
| 1444 | 1470 | if (guess_same_dragon) { |
| 1445 | 1471 | if (liberty_of_goal(move, owla) |
| 1446 | 1472 | || second_liberty_of_goal(move, owla)) |
| 1447 | | same_dragon = 1; |
| | 1473 | same_dragon = SAME_DRAGON_MAYBE_CONNECTED; |
| 1448 | 1474 | else |
| 1449 | | same_dragon = 0; |
| | 1475 | same_dragon = SAME_DRAGON_NOT_CONNECTED; |
| 1450 | 1476 | } |
| 1451 | | else |
| | 1477 | else { |
| 1452 | 1478 | same_dragon = owl_moves[k].same_dragon; |
| | 1479 | pattern_data = owl_moves[k].pattern_data; |
| | 1480 | } |
| 1453 | 1481 | |
| 1454 | 1482 | mw[move] = 1; |
| 1455 | 1483 | move_value = (semeai_move_value(move, owla, owlb, owl_moves[k].value, |
| … |
… |
|
| 1457 | 1485 | + value_bonus); |
| 1458 | 1486 | owl_add_move(semeai_moves, move, move_value, owl_moves[k].name, |
| 1459 | 1487 | same_dragon, NO_MOVE, owl_moves[k].escape, |
| 1460 | | NO_MOVE, MAX_SEMEAI_MOVES); |
| | 1488 | NO_MOVE, MAX_SEMEAI_MOVES, pattern_data); |
| 1461 | 1489 | TRACE("Added %1m %d\n", move, move_value); |
| 1462 | 1490 | } |
| 1463 | 1491 | } |
| … |
… |
|
| 1703 | 1731 | moves[k].pos = NO_MOVE; |
| 1704 | 1732 | moves[k].value = -1; |
| 1705 | 1733 | moves[k].name = NULL; |
| 1706 | | moves[k].same_dragon = 2; |
| | 1734 | moves[k].same_dragon = SAME_DRAGON_CONNECTED; |
| 1707 | 1735 | moves[k].escape = 0; |
| 1708 | 1736 | moves[k].lunch = NO_MOVE; |
| | 1737 | moves[k].pattern_data = NULL; |
| 1709 | 1738 | clear_cut_list(moves[k].cuts); |
| 1710 | 1739 | } |
| 1711 | 1740 | } |
| … |
… |
|
| 1714 | 1743 | set_single_owl_move(struct owl_move_data moves[MAX_MOVES], |
| 1715 | 1744 | int pos, const char *name) |
| 1716 | 1745 | { |
| 1717 | | moves[0].pos = pos; |
| 1718 | | moves[0].value = 25; |
| 1719 | | moves[0].name = name; |
| 1720 | | moves[0].same_dragon = 1; |
| 1721 | | moves[0].escape = 0; |
| 1722 | | moves[0].lunch = NO_MOVE; |
| | 1746 | moves[0].pos = pos; |
| | 1747 | moves[0].value = 25; |
| | 1748 | moves[0].name = name; |
| | 1749 | moves[0].same_dragon = SAME_DRAGON_MAYBE_CONNECTED; |
| | 1750 | moves[0].escape = 0; |
| | 1751 | moves[0].lunch = NO_MOVE; |
| | 1752 | moves[0].pattern_data = NULL; |
| 1723 | 1753 | clear_cut_list(moves[0].cuts); |
| 1724 | | moves[1].value = 0; |
| | 1754 | moves[1].value = 0; |
| 1725 | 1755 | } |
| 1726 | 1756 | |
| 1727 | 1757 | |
| … |
… |
|
| 2716 | 2746 | /* Add the stone just played to the goal dragon, unless the |
| 2717 | 2747 | * pattern explicitly asked for not doing this. |
| 2718 | 2748 | */ |
| 2719 | | owl_update_goal(mpos, moves[k].same_dragon, moves[k].lunch, owl, 0); |
| | 2749 | owl_update_goal(mpos, moves[k].same_dragon, moves[k].lunch, owl, 0, |
| | 2750 | moves[k].pattern_data); |
| 2720 | 2751 | mark_goal_in_sgf(owl->goal); |
| 2721 | 2752 | |
| 2722 | 2753 | if (!ko_move) { |
| … |
… |
|
| 2832 | 2863 | if (trymove(moves[k].pos, color, moves[k].name, target)) { |
| 2833 | 2864 | owl->lunches_are_current = 0; |
| 2834 | 2865 | owl_update_goal(moves[k].pos, moves[k].same_dragon, |
| 2835 | | moves[k].lunch, owl, 0); |
| | 2866 | moves[k].lunch, owl, 0, moves[k].pattern_data); |
| 2836 | 2867 | if (do_owl_defend(target, &move2, NULL, owl, 0) == WIN) { |
| 2837 | 2868 | move = moves[k].pos; |
| 2838 | 2869 | popgo(); |
| … |
… |
|
| 2947 | 2978 | * Let's try to defend against it. |
| 2948 | 2979 | */ |
| 2949 | 2980 | owl_add_move(vital_moves, dummy_moves[0].defense_pos, |
| 2950 | | dummy_moves[0].value, dummy_moves[0].name, 2, NO_MOVE, |
| 2951 | | 0, NO_MOVE, MAX_MOVES); |
| | 2981 | dummy_moves[0].value, dummy_moves[0].name, |
| | 2982 | SAME_DRAGON_CONNECTED, NO_MOVE, 0, NO_MOVE, MAX_MOVES, NULL); |
| 2952 | 2983 | } |
| 2953 | 2984 | |
| 2954 | 2985 | return 0; |
| … |
… |
|
| 3161 | 3192 | attack_point); |
| 3162 | 3193 | |
| 3163 | 3194 | if (attack_point != NO_MOVE) { |
| 3164 | | owl_add_move(moves, attack_point, value, reason, 1, NO_MOVE, |
| 3165 | | 0, NO_MOVE, MAX_MOVES); |
| | 3195 | owl_add_move(moves, attack_point, value, reason, |
| | 3196 | SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE, |
| | 3197 | 0, NO_MOVE, MAX_MOVES, NULL); |
| 3166 | 3198 | vital_values[attack_point] = value; |
| 3167 | 3199 | eyes_attack_points[num_eyes] = attack_point; |
| 3168 | 3200 | } |
| … |
… |
|
| 3216 | 3248 | defense_point); |
| 3217 | 3249 | |
| 3218 | 3250 | if (defense_point != NO_MOVE) { |
| 3219 | | owl_add_move(moves, defense_point, value, reason, 1, NO_MOVE, |
| 3220 | | 0, NO_MOVE, MAX_MOVES); |
| | 3251 | owl_add_move(moves, defense_point, value, reason, |
| | 3252 | SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE, |
| | 3253 | 0, NO_MOVE, MAX_MOVES, NULL); |
| 3221 | 3254 | vital_values[defense_point] = value; |
| 3222 | 3255 | } |
| 3223 | 3256 | } |
| … |
… |
|
| 3291 | 3324 | owl->lunch[lunch], defense_point, value, |
| 3292 | 3325 | lunch_probable, lunch_max); |
| 3293 | 3326 | owl_add_move(moves, defense_point, value, |
| 3294 | | "save lunch", 1, NO_MOVE, 0, NO_MOVE, MAX_MOVES); |
| | 3327 | "save lunch", SAME_DRAGON_MAYBE_CONNECTED, |
| | 3328 | NO_MOVE, 0, NO_MOVE, MAX_MOVES, NULL); |
| 3295 | 3329 | } |
| 3296 | 3330 | else { |
| 3297 | 3331 | attack_point = improve_lunch_attack(owl->lunch[lunch], |
| … |
… |
|
| 3307 | 3341 | if (owl->lunch_attack_code[lunch] == WIN |
| 3308 | 3342 | || is_illegal_ko_capture(attack_point, owl->color)) |
| 3309 | 3343 | owl_add_move(moves, attack_point, value, "eat lunch", |
| 3310 | | 1, owl->lunch[lunch], 0, NO_MOVE, MAX_MOVES); |
| | 3344 | SAME_DRAGON_MAYBE_CONNECTED, owl->lunch[lunch], |
| | 3345 | 0, NO_MOVE, MAX_MOVES, NULL); |
| 3311 | 3346 | else |
| 3312 | 3347 | owl_add_move(moves, attack_point, value, "eat lunch", |
| 3313 | | 1, NO_MOVE, 0, NO_MOVE, MAX_MOVES); |
| | 3348 | SAME_DRAGON_MAYBE_CONNECTED, NO_MOVE, 0, NO_MOVE, |
| | 3349 | MAX_MOVES, NULL); |
| 3314 | 3350 | num_lunches++; |
| 3315 | 3351 | eyevalue_list[num_eyes++] = e; |
| 3316 | 3352 | } |
| … |
… |
|
| 4162 | 4198 | |
| 4163 | 4199 | while (list->heap_num_patterns > 0) { |
| 4164 | 4200 | int k; |
| | 4201 | struct matched_pattern_data *pattern_data; |
| 4165 | 4202 | struct pattern *pattern; |
| 4166 | 4203 | int move; |
| 4167 | 4204 | int value; |
| … |
… |
|
| 4173 | 4210 | if (list->pattern_heap[0]->value < cutoff) |
| 4174 | 4211 | break; |
| 4175 | 4212 | |
| | 4213 | pattern_data = list->pattern_heap[0]; |
| 4176 | 4214 | pattern = list->pattern_heap[0]->pattern; |
| 4177 | 4215 | move = list->pattern_heap[0]->move; |
| 4178 | 4216 | value = list->pattern_heap[0]->value; |
| … |
… |
|
| 4240 | 4278 | } |
| 4241 | 4279 | |
| 4242 | 4280 | if (pattern->class & CLASS_B) |
| 4243 | | moves[k].same_dragon = 0; |
| 4244 | | else if (pattern->class & CLASS_b) { |
| | 4281 | moves[k].same_dragon = SAME_DRAGON_NOT_CONNECTED; |
| | 4282 | else if (pattern->class & CLASS_a) { |
| | 4283 | moves[k].same_dragon = SAME_DRAGON_ALL_CONNECTED; |
| | 4284 | moves[k].pattern_data = pattern_data; |
| | 4285 | } |
| | 4286 | else if (!(pattern->class & CLASS_b)) |
| | 4287 | moves[k].same_dragon = SAME_DRAGON_CONNECTED; |
| | 4288 | else { |
| 4245 | 4289 | int i; |
| 4246 | | int same_dragon = 1; |
| | 4290 | enum same_dragon_value same_dragon = SAME_DRAGON_MAYBE_CONNECTED; |
| 4247 | 4291 | |
| 4248 | 4292 | /* If we do not yet know whether the move belongs to the |
| 4249 | 4293 | * same dragon, we see whether another pattern can clarify. |
| 4250 | 4294 | */ |
| 4251 | 4295 | for (i = 0; i < list->heap_num_patterns; i++) { |
| 4252 | | struct matched_pattern_data *pattern_data = list->pattern_heap[i]; |
| | 4296 | pattern_data = list->pattern_heap[i]; |
| 4253 | 4297 | |
| 4254 | 4298 | if (pattern_data->pattern |
| 4255 | 4299 | && pattern_data->move == move |
| … |
… |
|
| 4260 | 4304 | TRACE("Additionally pattern %s found at %1m\n", |
| 4261 | 4305 | pattern_data->pattern->name, move); |
| 4262 | 4306 | if (pattern_data->pattern->class & CLASS_B) |
| 4263 | | same_dragon = 0; |
| | 4307 | same_dragon = SAME_DRAGON_NOT_CONNECTED; |
| | 4308 | else if (pattern_data->pattern->class & CLASS_a) { |
| | 4309 | same_dragon = SAME_DRAGON_ALL_CONNECTED; |
| | 4310 | moves[k].pattern_data = pattern_data; |
| | 4311 | } |
| 4264 | 4312 | else |
| 4265 | | same_dragon = 2; |
| | 4313 | same_dragon = SAME_DRAGON_CONNECTED; |
| 4266 | 4314 | |
| 4267 | 4315 | break; |
| 4268 | 4316 | } |
| … |
… |
|
| 4271 | 4319 | |
| 4272 | 4320 | moves[k].same_dragon = same_dragon; |
| 4273 | 4321 | } |
| 4274 | | else |
| 4275 | | moves[k].same_dragon = 2; |
| 4276 | 4322 | } |
| 4277 | 4323 | else { |
| 4278 | 4324 | moves[k].name = "Pattern combination"; |
| … |
… |
|
| 4287 | 4333 | * chain didn't match, this will not work at all. |
| 4288 | 4334 | */ |
| 4289 | 4335 | if (pattern && pattern->class & CLASS_B) |
| 4290 | | moves[k].same_dragon = 0; |
| | 4336 | moves[k].same_dragon = SAME_DRAGON_NOT_CONNECTED; |
| | 4337 | else if (pattern && pattern->class & CLASS_a) { |
| | 4338 | moves[k].same_dragon = SAME_DRAGON_ALL_CONNECTED; |
| | 4339 | moves[k].pattern_data = list->pattern_heap[0]; |
| | 4340 | } |
| 4291 | 4341 | else |
| 4292 | | moves[k].same_dragon = 2; |
| | 4342 | moves[k].same_dragon = SAME_DRAGON_CONNECTED; |
| 4293 | 4343 | } |
| 4294 | 4344 | |
| 4295 | 4345 | if (pattern && pattern->class & CLASS_E) |
| … |
… |
|
| 4338 | 4388 | int tval; /* trial move and its value */ |
| 4339 | 4389 | int move; |
| 4340 | 4390 | struct owl_move_data *moves = data; /* considered moves passed as data */ |
| 4341 | | int same_dragon = 1; |
| | 4391 | enum same_dragon_value same_dragon = SAME_DRAGON_MAYBE_CONNECTED; |
| 4342 | 4392 | int escape = 0; |
| 4343 | 4393 | int defense_pos; |
| 4344 | 4394 | |
| … |
… |
|
| 4395 | 4445 | TRACE("Pattern %s found at %1m with value %d\n", pattern->name, move, tval); |
| 4396 | 4446 | |
| 4397 | 4447 | if (pattern->class & CLASS_B) |
| 4398 | | same_dragon = 0; |
| | 4448 | same_dragon = SAME_DRAGON_NOT_CONNECTED; |
| 4399 | 4449 | else if (pattern->class & CLASS_b) |
| 4400 | | same_dragon = 1; |
| | 4450 | same_dragon = SAME_DRAGON_MAYBE_CONNECTED; |
| | 4451 | else if (pattern->class & CLASS_a) { |
| | 4452 | same_dragon = SAME_DRAGON_ALL_CONNECTED; |
| | 4453 | /* FIXME: Currently this code is only used with vital attack |
| | 4454 | * moves, so there is no use for the "a" classification. If it |
| | 4455 | * would be needed in the future it's necessary to set up a struct |
| | 4456 | * matched_pattern_data here to be passed to owl_add_move(). This |
| | 4457 | * is not all that simple with respect to memory management |
| | 4458 | * however. Notice that a local variable in this function would go |
| | 4459 | * out of scope too early. |
| | 4460 | */ |
| | 4461 | gg_assert(0); |
| | 4462 | } |
| 4401 | 4463 | else |
| 4402 | | same_dragon = 2; |
| | 4464 | same_dragon = SAME_DRAGON_CONNECTED; |
| 4403 | 4465 | |
| 4404 | 4466 | if (pattern->class & CLASS_E) |
| 4405 | 4467 | escape = 1; |
| … |
… |
|
| 4416 | 4478 | } |
| 4417 | 4479 | |
| 4418 | 4480 | owl_add_move(moves, move, tval, pattern->name, same_dragon, NO_MOVE, |
| 4419 | | escape, defense_pos, MAX_MOVES); |
| | 4481 | escape, defense_pos, MAX_MOVES, NULL); |
| 4420 | 4482 | } |
| 4421 | 4483 | |
| 4422 | 4484 | |
| … |
… |
|
| 4424 | 4486 | |
| 4425 | 4487 | static void |
| 4426 | 4488 | owl_add_move(struct owl_move_data *moves, int move, int value, |
| 4427 | | const char *reason, int same_dragon, int lunch, |
| 4428 | | int escape, int defense_pos, int max_moves) |
| | 4489 | const char *reason, enum same_dragon_value same_dragon, int lunch, |
| | 4490 | int escape, int defense_pos, int max_moves, |
| | 4491 | struct matched_pattern_data *pattern_data) |
| 4429 | 4492 | { |
| 4430 | 4493 | int k; |
| 4431 | 4494 | |
| … |
… |
|
| 4443 | 4506 | if (moves[k].value == -1) |
| 4444 | 4507 | break; |
| 4445 | 4508 | if (moves[k].pos == move) { |
| 4446 | | if (same_dragon > moves[k].same_dragon) |
| | 4509 | if (same_dragon > moves[k].same_dragon) { |
| 4447 | 4510 | moves[k].same_dragon = same_dragon; |
| | 4511 | moves[k].pattern_data = pattern_data; |
| | 4512 | } |
| 4448 | 4513 | if (!moves[k].escape) |
| 4449 | 4514 | escape = 0; |
| 4450 | 4515 | break; |
| … |
… |
|
| 4471 | 4536 | * dragon under consideration. |
| 4472 | 4537 | */ |
| 4473 | 4538 | moves[k].same_dragon = same_dragon; |
| | 4539 | moves[k].pattern_data = pattern_data; |
| 4474 | 4540 | moves[k].lunch = lunch; |
| 4475 | 4541 | moves[k].escape = escape; |
| 4476 | 4542 | moves[k].defense_pos = defense_pos; |
| … |
… |
|
| 4661 | 4727 | } |
| 4662 | 4728 | |
| 4663 | 4729 | /* Add the stone just played to the goal dragon if same_dragon is |
| 4664 | | * 2. We also add all stones belonging to the same generalized string |
| 4665 | | * to the goal. If same_dragon is 1, we only add the stones if at |
| 4666 | | * least one stone of the generalized string already was part of the |
| 4667 | | * goal. If same_dragon is 0, we don't add any stones at all. |
| | 4730 | * SAME_DRAGON_CONNECTED. We also add all stones belonging to the same |
| | 4731 | * generalized string to the goal. If same_dragon is |
| | 4732 | * SAME_DRAGON_MAYBE_CONNECTED, we only add the stones if at least one |
| | 4733 | * stone of the generalized string already was part of the goal. If |
| | 4734 | * same_dragon is SAME_DRAGON_NOT_CONNECTED, we don't add any stones |
| | 4735 | * at all. |
| | 4736 | * |
| | 4737 | * The SAME_DRAGON_ALL_CONNECTED case is like SAME_DRAGON_CONNECTED |
| | 4738 | * but additionally all other own stones in the pattern suggesting the |
| | 4739 | * move are also added to the goal. |
| 4668 | 4740 | */ |
| 4669 | 4741 | static void |
| 4670 | | owl_update_goal(int pos, int same_dragon, int lunch, |
| 4671 | | struct local_owl_data *owl, int semeai_call) |
| | 4742 | owl_update_goal(int pos, enum same_dragon_value same_dragon, int lunch, |
| | 4743 | struct local_owl_data *owl, int semeai_call, |
| | 4744 | struct matched_pattern_data *pattern_data) |
| 4672 | 4745 | { |
| 4673 | 4746 | int stones[MAX_BOARD * MAX_BOARD]; |
| 4674 | 4747 | int num_stones; |
| … |
… |
|
| 4682 | 4755 | sgf_dumptree = NULL; |
| 4683 | 4756 | count_variations = 0; |
| 4684 | 4757 | |
| 4685 | | if (same_dragon == 0) |
| | 4758 | if (same_dragon == SAME_DRAGON_NOT_CONNECTED) |
| 4686 | 4759 | num_stones = findstones(pos, MAX_BOARD*MAX_BOARD, stones); |
| 4687 | 4760 | else if (semeai_call) |
| 4688 | 4761 | find_superstring_conservative(pos, &num_stones, stones); |
| … |
… |
|
| 4696 | 4769 | /* If same_dragon field is 1, only add if the played stone |
| 4697 | 4770 | * clearly is in contact with the goal dragon. |
| 4698 | 4771 | */ |
| 4699 | | if (same_dragon <= 1) { |
| | 4772 | if (same_dragon <= SAME_DRAGON_MAYBE_CONNECTED) { |
| 4700 | 4773 | do_add = 0; |
| 4701 | 4774 | for (k = 0; k < num_stones; k++) |
| 4702 | 4775 | if (owl->goal[stones[k]] != 0) { |
| … |
… |
|
| 4729 | 4802 | } |
| 4730 | 4803 | } |
| 4731 | 4804 | |
| | 4805 | /* Now we handle the SAME_DRAGON_ALL_CONNECTED case. The move has |
| | 4806 | * already been added to the goal above, so it remains to find all |
| | 4807 | * other friendly stones in the pattern and add them too. We do that |
| | 4808 | * by a recursive call to this function in SAME_DRAGON_CONNECTED mode. |
| | 4809 | * This is maybe not the most elegant technique, however. |
| | 4810 | */ |
| | 4811 | if (same_dragon == SAME_DRAGON_ALL_CONNECTED) { |
| | 4812 | gg_assert(pattern_data != NULL); |
| | 4813 | for (k = 0; k < pattern_data->pattern->patlen; k++) { |
| | 4814 | int pos2; |
| | 4815 | |
| | 4816 | /* all the following stuff (currently) applies only at occupied cells */ |
| | 4817 | if (pattern_data->pattern->patn[k].att != ATT_O) |
| | 4818 | continue; |
| | 4819 | |
| | 4820 | /* transform pattern real coordinate */ |
| | 4821 | pos2 = AFFINE_TRANSFORM(pattern_data->pattern->patn[k].offset, |
| | 4822 | pattern_data->ll, pattern_data->anchor); |
| | 4823 | |
| | 4824 | if (!owl->goal[pos2]) |
| | 4825 | owl_update_goal(pos2, SAME_DRAGON_CONNECTED, NO_MOVE, owl, semeai_call, |
| | 4826 | pattern_data); |
| | 4827 | } |
| | 4828 | } |
| | 4829 | |
| 4732 | 4830 | if (1 && verbose) |
| 4733 | 4831 | goaldump(owl->goal); |
| 4734 | 4832 | } |
| … |
… |
|
| 5501 | 5599 | init_owl(&owl, target1, target2, NO_MOVE, 1, NULL); |
| 5502 | 5600 | |
| 5503 | 5601 | if (trymove( |