UInt64 virtual_size() const { return sizeof(Header) + (sizeof(Entry) * num_keys()) + (sizeof(Block) * num_blocks()) + (sizeof(Node) * num_nodes()) + total_key_length(); }
int main() { Hash_map hash_map; Data data= (Data) 123; Key key= (Key) 456; mcheck_pedantic(NULL); hash_map= create_example_hash_map(); /* calling some of the functions with an empty Hash_map */ if (!get(&hash_map, (Key) (long) 1, &data) && !get_smallest(hash_map, &key, &data) && num_keys(hash_map, 0) == 0 && index_of(hash_map, (Key) (long) 5) == -1 && data == (Data) 123 && key == (Key) 456) printf("Your functions can handle an empty hash_map correctly!\n"); else printf("Oops! Error in handling anempty hash_map.\n"); clear(&hash_map); if (mallinfo().uordblks != 0) printf("Memory leak of %d bytes. :(\n", mallinfo().uordblks); else printf("No memory leak detected. :)\n"); return 0; }
void iterate(solution *sol, char *filename) { size_t num_states = num_keys(sol->d); int changed = 1; while (changed) { changed = 0; for (size_t j = 0; j < sol->num_layers; j++) { size_t key; size_t i; int tid; int num_threads; #pragma omp parallel private(i, key, tid, num_threads) { num_threads = omp_get_num_threads(); state s_; state *s = &s_; tid = omp_get_thread_num(); key = sol->d->min_key; for (i = 0; i < num_states; i++) { if (i % num_threads == tid) { assert(from_key_s(sol, s, key, j)); node_value new_v = negamax_node(sol, s, key, j, 1); assert(new_v.low >= sol->base_nodes[j][i].low); assert(new_v.high <= sol->base_nodes[j][i].high); changed = changed || !equal(sol->base_nodes[j][i], new_v); sol->base_nodes[j][i] = new_v; } key = next_key(sol->d, key); } #pragma omp for for (i = 0; i < sol->ko_ld->num_keys; i++) { key = sol->ko_ld->keys[i]; assert(from_key_ko(sol, s, key, j)); node_value new_v = negamax_node(sol, s, key, j, 1); assert(new_v.low >= sol->ko_nodes[j][i].low); assert(new_v.high <= sol->ko_nodes[j][i].high); changed = changed || !equal(sol->ko_nodes[j][i], new_v); sol->ko_nodes[j][i] = new_v; } } } size_t base_layer; size_t base_key = to_key_s(sol, sol->base_state, &base_layer); printf("Saving...\n"); // TODO: Prevent data corruption by catching Ctrl+C. FILE *f = fopen(filename, "wb"); save_solution(sol, f); fclose(f); print_node(negamax_node(sol, sol->base_state, base_key, base_layer, 0)); // Verify solution integrity. For debugging only. Leaks memory. // char *buffer = file_to_buffer(filename); // buffer = load_solution(sol, buffer, 0); } }
void upgrade(int argc, char *argv[]) { parse_args(argc - 1, argv + 1); solution sol_; solution *sol = &sol_; char *buffer = file_to_buffer(tsumego_name); // Not really a tsumego name. Needs extension too. buffer = load_solution(sol, buffer, 1); if (sol->si->color_symmetry) { num_layers = 2 * abs(ko_threats) + 1; } else if (num_layers <= 0) { num_layers = abs(ko_threats) + 1; } sol->base_nodes = (node_value**) realloc(sol->base_nodes, sol->num_layers * sizeof(node_value*)); sol->ko_nodes = (node_value**) realloc(sol->ko_nodes, sol->num_layers * sizeof(node_value*)); size_t zero_layer = abs(sol->base_state->ko_threats); size_t new_zero_layer = abs(ko_threats); sol->base_nodes[new_zero_layer] = sol->base_nodes[zero_layer]; sol->ko_nodes[new_zero_layer] = sol->ko_nodes[zero_layer]; sol->base_state->ko_threats = ko_threats; sol->num_layers = num_layers; size_t num_states = num_keys(sol->d); for (size_t k = 0; k < sol->num_layers; k++) { if (k == new_zero_layer) { continue; } sol->base_nodes[k] = (node_value*) malloc(num_states * sizeof(node_value)); for (size_t i = 0; i < num_states; i++) { (sol->base_nodes[k])[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } } for (size_t k = 0; k < sol->num_layers; k++) { if (k == new_zero_layer) { continue; } sol->ko_nodes[k] = (node_value*) malloc(sol->ko_ld->num_keys * sizeof(node_value)); for (size_t i = 0; i < sol->ko_ld->num_keys; i++) { sol->ko_nodes[k][i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } } FILE *f = fopen(tsumego_name, "wb"); save_solution(sol, f); fclose(f); printf("Done!\n"); }
int main(int argc, char *argv[]) { num_solutions = argc - 2; solution_names = argv + 2; sols = (solution**) malloc(num_solutions * sizeof(solution*)); for (int i = 0; i < num_solutions; i++) { sols[i] = mmap_solution(solution_names[i]); #ifdef DEBUG printf("%s\n", solution_names[i]); printf("Number of unique positions: %zu\n", num_keys(sols[i]->d)); printf("Number of positions with ko: %zu\n", sols[i]->ko_ld->num_keys); #endif repr_state(sols[i]->base_state); printf("%zu\n", sols[i]->num_layers); } printf("Solutions loaded.\n"); serve(argv[1]); // TODO: Cleanup. return 0; }
/// Return iterator to the ending+1 value with key == id inline const_iterator end(size_t id) const { return (id+1) < num_keys() ? value_ptrs[id+1] : values.end(); }
/// Return iterator to the begining value with key == id inline const_iterator begin(size_t id) const { //logstream(LOG_INFO) << "disk debug. vid in mem=" << id << std::endl; return id < num_keys() ? value_ptrs[id] : values.end(); }
/// Return iterator to the ending+1 value with key == id inline iterator end(size_t id) { //logstream(LOG_INFO) << "disk debug. id=" << id << std::endl; return (id+1) < num_keys() ? value_ptrs[id+1] : values.end(); }
/// Return iterator to the begining value with key == id inline iterator begin(size_t id) { return id < num_keys() ? value_ptrs[id] : values.end(); }
int main(int argc, char *argv[]) { if (argc != 3) { printf("Usage: %s width height\n", argv[0]); return 0; } int width = atoi(argv[1]); int height = atoi(argv[2]); if (width <= 0) { printf("Width must be larger than 0.\n"); return 0; } if (width >= 7) { printf("Width must be less than 7.\n"); return 0; } if (height <= 0) { printf("Height must be larger than 0.\n"); return 0; } if (height >= 6) { printf("Height must be less than 6.\n"); return 0; } state s_ = (state) {rectangle(width, height), 0, 0, 0, 0}; state *s = &s_; dict d_; dict *d = &d_; size_t max_k = max_key(s); init_dict(d, max_k); size_t key_min = ~0; size_t key_max = 0; size_t total_legal = 0; for (size_t k = 0; k < max_k; k++) { if (!from_key(s, k)){ continue; } total_legal++; canonize(s); size_t key = to_key(s); add_key(d, key); if (key < key_min) { key_min = key; } if (key > key_max) { key_max = key; } } resize_dict(d, key_max); finalize_dict(d); size_t num_states = num_keys(d); printf("Total legal positions %zu\n", total_legal); printf("Total unique positions %zu\n", num_states); node_value *base_nodes = (node_value*) malloc(num_states * sizeof(node_value)); node_value *pass_nodes = (node_value*) malloc(num_states * sizeof(node_value)); value_t *leaf_nodes = (value_t*) malloc(num_states * sizeof(value_t)); lin_dict ko_ld_ = (lin_dict) {0, 0, 0, NULL}; lin_dict *ko_ld = &ko_ld_; state child_; state *child = &child_; size_t child_key; size_t key = key_min; for (size_t i = 0; i < num_states; i++) { assert(from_key(s, key)); value_t score = liberty_score(s); leaf_nodes[i] = score; pass_nodes[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; base_nodes[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; for (int j = 0; j < STATE_SIZE; j++) { *child = *s; if (make_move(child, 1UL << j)) { if (child->ko) { canonize(child); child_key = to_key(child) * STATE_SIZE + bitscan(child->ko); add_lin_key(ko_ld, child_key); } } } key = next_key(d, key); } finalize_lin_dict(ko_ld); node_value *ko_nodes = (node_value*) malloc(ko_ld->num_keys * sizeof(node_value)); printf("Unique positions with ko %zu\n", ko_ld->num_keys); for (size_t i = 0; i < ko_ld->num_keys; i++) { ko_nodes[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } #ifndef PRELOAD printf("Negamax with Chinese rules.\n"); iterate( d, ko_ld, base_nodes, pass_nodes, ko_nodes, leaf_nodes, s, key_min, 0 ); #endif char dir_name[16]; sprintf(dir_name, "%dx%d", width, height); struct stat sb; if (stat(dir_name, &sb) == -1) { mkdir(dir_name, 0700); } assert(chdir(dir_name) == 0); FILE *f; #ifndef PRELOAD f = fopen("d_slots.dat", "wb"); fwrite((void*) d->slots, sizeof(slot_t), d->num_slots, f); fclose(f); f = fopen("d_checkpoints.dat", "wb"); fwrite((void*) d->checkpoints, sizeof(size_t), (d->num_slots >> 4) + 1, f); fclose(f); f = fopen("ko_ld_keys.dat", "wb"); fwrite((void*) ko_ld->keys, sizeof(size_t), ko_ld->num_keys, f); fclose(f); f = fopen("base_nodes.dat", "wb"); fwrite((void*) base_nodes, sizeof(node_value), num_states, f); fclose(f); f = fopen("pass_nodes.dat", "wb"); fwrite((void*) pass_nodes, sizeof(node_value), num_states, f); fclose(f); f = fopen("leaf_nodes.dat", "wb"); fwrite((void*) leaf_nodes, sizeof(value_t), num_states, f); fclose(f); f = fopen("ko_nodes.dat", "wb"); fwrite((void*) ko_nodes, sizeof(node_value), ko_ld->num_keys, f); fclose(f); #endif #ifdef PRELOAD f = fopen("base_nodes.dat", "rb"); fread((void*) base_nodes, sizeof(node_value), num_states, f); fclose(f); f = fopen("pass_nodes.dat", "rb"); fread((void*) pass_nodes, sizeof(node_value), num_states, f); fclose(f); f = fopen("leaf_nodes.dat", "rb"); fread((void*) leaf_nodes, sizeof(value_t), num_states, f); fclose(f); f = fopen("ko_nodes.dat", "rb"); fread((void*) ko_nodes, sizeof(node_value), ko_ld->num_keys, f); fclose(f); #endif // Japanese leaf state calculation. state new_s_; state *new_s = &new_s_; key = key_min; for (size_t i = 0; i < num_states; i++) { assert(from_key(s, key)); stones_t empty = s->playing_area & ~(s->player | s->opponent); *new_s = *s; endstate( d, ko_ld, base_nodes, pass_nodes, ko_nodes, new_s, base_nodes[i], 0, 1 ); stones_t player_controlled = new_s->player | liberties(new_s->player, new_s->playing_area & ~new_s->opponent); stones_t opponent_controlled = new_s->opponent | liberties(new_s->opponent, new_s->playing_area & ~new_s->player); value_t score = popcount(player_controlled & empty) - popcount(opponent_controlled & empty); score += 2 * (popcount(player_controlled & s->opponent) - popcount(opponent_controlled & s->player)); leaf_nodes[i] = score; *new_s = *s; endstate( d, ko_ld, base_nodes, pass_nodes, ko_nodes, new_s, base_nodes[i], 0, 0 ); player_controlled = new_s->player | liberties(new_s->player, new_s->playing_area & ~new_s->opponent); opponent_controlled = new_s->opponent | liberties(new_s->opponent, new_s->playing_area & ~new_s->player); score = popcount(player_controlled & empty) - popcount(opponent_controlled & empty); score += 2 * (popcount(player_controlled & s->opponent) - popcount(opponent_controlled & s->player)); leaf_nodes[i] += score; key = next_key(d, key); } // Clear the rest of the tree. for (size_t i = 0; i < num_states; i++) { pass_nodes[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; base_nodes[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } for (size_t i = 0; i < ko_ld->num_keys; i++) { ko_nodes[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } printf("Negamax with Japanese rules.\n"); iterate( d, ko_ld, base_nodes, pass_nodes, ko_nodes, leaf_nodes, s, key_min, 1 ); f = fopen("base_nodes_j.dat", "wb"); fwrite((void*) base_nodes, sizeof(node_value), num_states, f); fclose(f); f = fopen("pass_nodes_j.dat", "wb"); fwrite((void*) pass_nodes, sizeof(node_value), num_states, f); fclose(f); f = fopen("leaf_nodes_j.dat", "wb"); fwrite((void*) leaf_nodes, sizeof(value_t), num_states, f); fclose(f); f = fopen("ko_nodes_j.dat", "wb"); fwrite((void*) ko_nodes, sizeof(node_value), ko_ld->num_keys, f); fclose(f); return 0; }
void iterate( dict *d, lin_dict *ko_ld, node_value *base_nodes, node_value *pass_nodes, node_value *ko_nodes, value_t *leaf_nodes, state *s, size_t key_min, int japanese_rules ) { state child_; state *child = &child_; size_t num_states = num_keys(d); int changed = 1; while (changed) { changed = 0; size_t key = key_min; for (size_t i = 0; i < 2 * num_states + ko_ld->num_keys; i++) { if (i < 2 * num_states) { assert(from_key(s, key)); if (i % 2 == 1) { s->passes = 1; } } else { key = ko_ld->keys[i - 2 * num_states]; size_t ko_pos = key % STATE_SIZE; key /= STATE_SIZE; assert(from_key(s, key)); s->ko = 1UL << ko_pos; } node_value new_v = (node_value) {VALUE_MIN, VALUE_MIN, DISTANCE_MAX, 0}; for (int j = -1; j < STATE_SIZE; j++) { size_t child_key; node_value child_v; *child = *s; stones_t move; if (j == -1){ move = 0; } else { move = 1UL << j; } if (make_move(child, move)) { canonize(child); child_key = to_key(child); if (child->passes == 2){ value_t score = leaf_nodes[key_index(d, child_key)]; child_v = (node_value) {score, score, 0, 0}; } else if (child->passes == 1) { child_v = pass_nodes[key_index(d, child_key)]; } else if (child->ko) { child_key = child_key * STATE_SIZE + bitscan(child->ko); child_v = ko_nodes[lin_key_index(ko_ld, child_key)]; } else { child_v = base_nodes[key_index(d, child_key)]; } if (japanese_rules) { int prisoners = (popcount(s->opponent) - popcount(child->player)) * PRISONER_VALUE; if (child_v.low > VALUE_MIN) { child_v.low = child_v.low - prisoners; } if (child_v.high < VALUE_MAX) { child_v.high = child_v.high - prisoners; } } new_v = negamax(new_v, child_v); } } assert(new_v.high_distance > 0); if (i < 2 * num_states) { if (i % 2 == 0) { assert(new_v.low_distance > 1); assert(new_v.high_distance > 1); assert(new_v.low >= base_nodes[i / 2].low); assert(new_v.high <= base_nodes[i / 2].high); changed = changed || !equal(base_nodes[i / 2], new_v); base_nodes[i / 2] = new_v; } else { changed = changed || !equal(pass_nodes[i / 2], new_v); pass_nodes[i / 2] = new_v; key = next_key(d, key); } } else { changed = changed || !equal(ko_nodes[i - 2 * num_states], new_v); ko_nodes[i - 2 * num_states] = new_v; } } print_node(base_nodes[0]); } for (size_t i = 0; i < ko_ld->num_keys; i++) { assert(ko_nodes[i].low_distance > 2); assert(ko_nodes[i].high_distance > 2); } for (size_t i = 0; i < num_states; i++) { assert(base_nodes[i].low_distance > 1); assert(base_nodes[i].high_distance > 1); assert(pass_nodes[i].low_distance > 0); assert(pass_nodes[i].high_distance > 0); } }
int main(int argc, char **argv) { char *list_in; char *file_out; double ratio; if (argc != 3 && argc != 4) { printf("Usage: %s <list.txt> <outfile> [window_radius]\n", argv[0]); return EXIT_FAILURE; } list_in = argv[1]; ratio = 0.6; file_out = argv[2]; int window_radius = -1; if (argc == 4) { window_radius = atoi(argv[3]); } clock_t start = clock(); /* Read the list of files */ std::vector<std::string> key_files; if (ReadFileList(list_in, key_files) != 0) return EXIT_FAILURE; FILE *f; if ((f = fopen(file_out, "w")) == NULL) { printf("Could not open %s for writing.\n", file_out); return EXIT_FAILURE; } int num_images = (int) key_files.size(); std::vector<unsigned char*> keys(num_images); std::vector<int> num_keys(num_images); /* Read all keys */ for (int i = 0; i < num_images; i++) { keys[i] = NULL; num_keys[i] = ReadKeyFile(key_files[i].c_str(), &keys[i]); } clock_t end = clock(); printf("[KeyMatchFull] Reading keys took %0.3fs\n", (end - start) / ((double) CLOCKS_PER_SEC)); for (int i = 0; i < num_images; i++) { if (num_keys[i] == 0) continue; printf("[KeyMatchFull] Matching to image %d\n", i); start = clock(); /* Create a tree from the keys */ ANNkd_tree *tree = CreateSearchTree(num_keys[i], keys[i]); /* Compute the start index */ int start_idx = 0; if (window_radius > 0) start_idx = std::max(i - window_radius, 0); for (int j = start_idx; j < i; j++) { if (num_keys[j] == 0) continue; /* Compute likely matches between two sets of keypoints */ std::vector<KeypointMatch> matches = MatchKeys(num_keys[j], keys[j], tree, ratio); int num_matches = (int) matches.size(); if (num_matches >= 16) { /* Write the pair */ fprintf(f, "%d %d\n", j, i); /* Write the number of matches */ fprintf(f, "%d\n", (int) matches.size()); for (int i = 0; i < num_matches; i++) { fprintf(f, "%d %d\n", matches[i].m_idx1, matches[i].m_idx2); } } } end = clock(); printf("[KeyMatchFull] Matching took %0.3fs\n", (end - start) / ((double) CLOCKS_PER_SEC)); fflush(stdout); delete tree; } /* Free keypoints */ for (int i = 0; i < num_images; i++) { if (keys[i] != NULL) delete [] keys[i]; } fclose(f); return EXIT_SUCCESS; }
UInt32 max_key_id() const { return num_keys(); }
int main(int argc, char *argv[]) { #ifdef TEST test(); return 0; #endif #ifdef REPAIR repair(argc, argv); return 0; #endif #ifdef UPGRADE upgrade(argc, argv); return 0; #endif int load_sol = 0; int resume_sol = 0; if (strcmp(argv[argc - 1], "load") == 0) { load_sol = 1; argc--; } if (strcmp(argv[argc - 1], "resume") == 0) { resume_sol = 1; argc--; } parse_args(argc - 1, argv + 1); int width = board_width; int height = board_height; if (board_width >= 10) { fprintf(stderr, "Width must be less than 10.\n"); exit(EXIT_FAILURE); } if (board_height >= 8) { fprintf(stderr, "Height must be less than 8.\n"); exit(EXIT_FAILURE); } #include "tsumego.c" state base_state_; state *base_state = &base_state_; char sol_name[64] = "unknown"; char temp_filename[128]; char filename[128]; if (board_width > 0) { *base_state = (state) {rectangle(width, height), 0, 0, 0, 0}; sprintf(sol_name, "%dx%d", width, height); } else { int i; int found = 0; for (i = 0; tsumego_infos[i].name; ++i) { if (!strcmp(tsumego_name, tsumego_infos[i].name)) { *base_state = *(tsumego_infos[i].state); strcpy(sol_name, tsumego_name); found = 1; break; } } if (!found) { fprintf(stderr, "unknown tsumego: `%s'\n", tsumego_name); exit(EXIT_FAILURE); } } base_state->ko_threats = ko_threats; sprintf(temp_filename, "%s_temp.dat", sol_name); state_info si_; state_info *si = &si_; init_state(base_state, si); if (si->color_symmetry) { num_layers = 2 * abs(base_state->ko_threats) + 1; } else if (num_layers <= 0) { num_layers = abs(base_state->ko_threats) + 1; } else { assert(num_layers >= abs(base_state->ko_threats) + 1); } print_state(base_state); for (int i = 0; i < si->num_external; i++) { print_stones(si->externals[i]); } printf( "width=%d height=%d c=%d v=%d h=%d d=%d\n", si->width, si->height, si->color_symmetry, si->mirror_v_symmetry, si->mirror_h_symmetry, si->mirror_d_symmetry ); state s_; state *s = &s_; dict d_; dict *d = &d_; solution sol_; solution *sol = &sol_; sol->base_state = base_state; sol->si = si; sol->d = d; sol->num_layers = num_layers; size_t num_states; // Re-used at frontend. TODO: Allocate a different pointer. state child_; state *child = &child_; if (load_sol) { goto frontend; } if (resume_sol) { char *buffer = file_to_buffer(temp_filename); buffer = load_solution(sol, buffer, 1); num_states = num_keys(sol->d); if (sol->leaf_rule == japanese_double_liberty) { goto iterate_capture; } else { goto iterate_japanese; } } size_t k_size = key_size(sol->si); if (!sol->si->color_symmetry) { k_size *= 2; } init_dict(sol->d, k_size); size_t total_legal = 0; for (size_t k = 0; k < k_size; k++) { if (!from_key_s(sol, s, k, 0)){ continue; } total_legal++; size_t layer; size_t key = to_key_s(sol, s, &layer); assert(layer == 0); add_key(sol->d, key); } finalize_dict(sol->d); num_states = num_keys(sol->d); printf("Total positions %zu\n", total_legal); printf("Total unique positions %zu\n", num_states); node_value **base_nodes = (node_value**) malloc(sol->num_layers * sizeof(node_value*)); for (size_t i = 0; i < sol->num_layers; i++) { base_nodes[i] = (node_value*) malloc(num_states * sizeof(node_value)); } value_t *leaf_nodes = (value_t*) malloc(num_states * sizeof(value_t)); lin_dict ko_ld_ = (lin_dict) {0, 0, 0, NULL}; lin_dict *ko_ld = &ko_ld_; sol->base_nodes = base_nodes; sol->leaf_nodes = leaf_nodes; sol->ko_ld = ko_ld; size_t child_key; size_t key = sol->d->min_key; for (size_t i = 0; i < num_states; i++) { assert(from_key_s(sol, s, key, 0)); // size_t layer; // assert(to_key_s(sol, s, &layer) == key); sol->leaf_nodes[i] = 0; for (size_t k = 0; k < sol->num_layers; k++) { (sol->base_nodes[k])[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } for (int j = 0; j < STATE_SIZE; j++) { *child = *s; int prisoners; if (make_move(child, 1ULL << j, &prisoners)) { if (target_dead(child)) { continue; } if (child->ko) { size_t child_layer; child_key = to_key_s(sol, child, &child_layer); add_lin_key(sol->ko_ld, child_key); } } } key = next_key(sol->d, key); } finalize_lin_dict(sol->ko_ld); node_value **ko_nodes = (node_value**) malloc(sol->num_layers * sizeof(node_value*)); sol->ko_nodes = ko_nodes; for (size_t i = 0; i < sol->num_layers; i++) { sol->ko_nodes[i] = (node_value*) malloc(sol->ko_ld->num_keys * sizeof(node_value)); } printf("Unique positions with ko %zu\n", sol->ko_ld->num_keys); for (size_t i = 0; i < sol->ko_ld->num_keys; i++) { for (size_t k = 0; k < sol->num_layers; k++) { sol->ko_nodes[k][i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } } #ifdef CHINESE printf("Negamax with Chinese rules.\n"); sol->count_prisoners = 0; sol->leaf_rule = chinese_liberty; iterate(sol, temp_filename); #endif // NOTE: Capture rules may refuse to kill stones when the needed nakade sacrifices exceed triple the number of stones killed. printf("Negamax with capture rules.\n"); sol->count_prisoners = 1; sol->leaf_rule = japanese_double_liberty; iterate_capture: iterate(sol, temp_filename); sprintf(filename, "%s_capture.dat", sol_name); FILE *f = fopen(filename, "wb"); save_solution(sol, f); fclose(f); calculate_leaves(sol); // Clear the rest of the tree. for (size_t j = 0; j < sol->num_layers; j++) { for (size_t i = 0; i < num_states; i++) { sol->base_nodes[j][i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } for (size_t i = 0; i < sol->ko_ld->num_keys; i++) { sol->ko_nodes[j][i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX}; } } printf("Negamax with Japanese rules.\n"); sol->count_prisoners = 1; sol->leaf_rule = precalculated; iterate_japanese: iterate(sol, temp_filename); sprintf(filename, "%s_japanese.dat", sol_name); f = fopen(filename, "wb"); save_solution(sol, f); fclose(f); frontend: if (load_sol) { sprintf(filename, "%s_japanese.dat", sol_name); char *buffer = file_to_buffer(filename); buffer = load_solution(sol, buffer, 1); } *s = *sol->base_state; char coord1; int coord2; int total_prisoners = 0; int turn = 0; while (1) { size_t layer; size_t key = to_key_s(sol, s, &layer); node_value v = negamax_node(sol, s, key, layer, 0); print_state(s); if (turn) { print_node((node_value) {total_prisoners - v.high, total_prisoners - v.low, v.high_distance, v.low_distance}); } else { print_node((node_value) {total_prisoners + v.low, total_prisoners + v.high, v.low_distance, v.high_distance}); } if (target_dead(s) || s->passes >= 2) { break; } for (int j = -1; j < STATE_SIZE; j++) { *child = *s; stones_t move; if (j == -1){ move = 0; } else { move = 1ULL << j; } char c1 = 'A' + (j % WIDTH); char c2 = '0' + (j / WIDTH); int prisoners; if (make_move(child, move, &prisoners)) { size_t child_layer; size_t child_key = to_key_s(sol, child, &child_layer); node_value child_v = negamax_node(sol, child, child_key, child_layer, 0); if (sol->count_prisoners) { if (child_v.low > VALUE_MIN && child_v.low < VALUE_MAX) { child_v.low = child_v.low - prisoners; } if (child_v.high > VALUE_MIN && child_v.high < VALUE_MAX) { child_v.high = child_v.high - prisoners; } } if (move) { printf("%c%c", c1, c2); } else { printf("pass"); } if (-child_v.high == v.low) { printf("-"); if (child_v.high_distance + 1 == v.low_distance) { printf("L"); } else { printf("l"); } } if (-child_v.high == v.low) { printf("-"); if (child_v.low_distance + 1 == v.high_distance) { printf("H"); } else { printf("h"); } } printf(" "); } } printf("\n"); printf("Enter coordinates:\n"); assert(scanf("%c %d", &coord1, &coord2)); int c; while ((c = getchar()) != '\n' && c != EOF); coord1 = tolower(coord1) - 'a'; stones_t move; if (coord1 < 0 || coord1 >= WIDTH) { // printf("%d, %d\n", coord1, coord2); move = 0; } else { move = 1ULL << (coord1 + V_SHIFT * coord2); } int prisoners; if (make_move(s, move, &prisoners)) { if (turn) { total_prisoners -= prisoners; } else { total_prisoners += prisoners; } turn = !turn; } } return 0; }
// Japanese leaf state calculation from capture data. // We could store territory for the UI, it takes too much space. void calculate_leaves(solution *sol) { state s_; state *s = &s_; size_t key; size_t zero_layer = abs(sol->base_state->ko_threats); state new_s_; state *new_s = &new_s_; key = sol->d->min_key; size_t num_states = num_keys(sol->d); for (size_t i = 0; i < num_states; i++) { assert(from_key_s(sol, s, key, zero_layer)); *new_s = *s; node_value v = negamax_node(sol, s, key, zero_layer, 0); node_value v_b = sol->base_nodes[zero_layer][i]; assert(equal(v, v_b)); endstate(sol, new_s, v, 0, 1); // Use a flood of life so that partially dead nakade won't give extra points. // Note while this won't mark dead groups as alive, it can treat living nakade stones as dead. stones_t player_alive = flood(new_s->player, s->player); stones_t opponent_alive = flood(new_s->opponent, s->opponent); int score; // First check if a target is not alive. stones_t player_target = s->player & s->target; stones_t opponent_target = s->opponent & s->target; if (opponent_target & ~opponent_alive) { // Make sure that both aren't dead. assert(!(player_target & ~player_alive)); score = TARGET_SCORE; } else if (player_target & ~player_alive) { score = -TARGET_SCORE; } else { stones_t player_territory = 0; stones_t opponent_territory = 0; stones_t player_region_space = s->playing_area & ~player_alive; stones_t opponent_region_space = s->playing_area & ~opponent_alive; for (int j = 0; j < STATE_SIZE; j++) { stones_t p = 1ULL << j; stones_t region = flood(p, player_region_space); player_region_space ^= region; if (!(region & opponent_alive)) { player_territory |= region; } region = flood(p, opponent_region_space); opponent_region_space ^= region; if (!(region & player_alive)) { opponent_territory |= region; } } // Subtract friendly stones on the board from territory. player_territory &= ~s->player; opponent_territory &= ~s->opponent; score = popcount(player_territory) + popcount(player_territory & s->opponent) - popcount(opponent_territory) - popcount(opponent_territory & s->player); } sol->leaf_nodes[i] = score; key = next_key(sol->d, key); } }