const string Guard::display() const { if (oneline.empty()) { string guards; if (_condition != nullptr) { guards += '['; guards += _condition->display(); guards += ']'; } guards.resize(max(guards.size(), (size_t)40), ' '); oneline += guards; string end = "nil"; if (endstate()) end = endstate()->name(); end.resize(max(end.size(), (size_t)10), ' '); oneline += end; string actions; actions += '{'; for (auto action : _actions) { actions += action->display(); } actions += '}'; oneline += actions; } return oneline; }
vector<int> DParray::sample_path() const { vector<int> path; const int I = size()-1; int i = I; int state2 = endstate(); vector<double> transition(nstates()); while(i >= 0) { path.push_back(state2); for(int state1=0; state1<nstates(); state1++) transition[state1] = (*this)(i,state1)*GQ(state1,state2); int state1 = choose_scratch(transition); if (di(state1)) i--; state2 = state1; } assert(i+di(state2)==0); std::reverse(path.begin(),path.end()); #ifndef NDEBUG_DP check_sampling_probability(path); #endif return path; }
void endstate(solution *sol, state *s, node_value parent_v, int turn, int low_player) { if (s->passes == 2 || target_dead(s)) { if (turn) { stones_t temp = s->player; s->player = s->opponent; s->opponent = temp; } return; } state child_; state *child = &child_; for (int j = 0; j < sol->si->num_moves; j++) { *child = *s; stones_t move = sol->si->moves[j]; 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); node_value child_v_p = add_prisoners(sol, child_v, prisoners); int is_best_child = (-child_v_p.high == parent_v.low && child_v_p.high_distance + 1 == parent_v.low_distance); is_best_child = low_player ? is_best_child : (-child_v_p.low == parent_v.high && child_v_p.low_distance + 1 == parent_v.high_distance); if (is_best_child) { *s = *child; endstate(sol, s, child_v, !turn, !low_player); return; } } } }
efloat_t DParray::Pr_sum_all_paths() const { const int I = size()-1; double total = 0.0; for(int state1=0; state1<nstates(); state1++) total += (*this)(I,state1) * GQ(state1,endstate()); return pow<efloat_t>(2.0,scale(I)) * total; }
void endstate( dict *d, lin_dict *ko_ld, node_value *base_nodes, node_value *pass_nodes, node_value *ko_nodes, state *s, node_value parent_v, int turn, int low_player ) { if (s->passes == 2) { if (turn) { stones_t temp = s->player; s->player = s->opponent; s->opponent = temp; } return; } state child_; state *child = &child_; for (int j = -1; j < STATE_SIZE; j++) { *child = *s; stones_t move; if (j == -1){ move = 0; } else { move = 1UL << j; } node_value child_v; if (make_move(child, move)) { canonize(child); size_t child_key = to_key(child); if (child->passes == 2){ value_t score = liberty_score(child); 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)]; } int is_best_child = (-child_v.high == parent_v.low && child_v.high_distance + 1 == parent_v.low_distance); is_best_child = low_player ? is_best_child : (-child_v.low == parent_v.high && child_v.low_distance + 1 == parent_v.high_distance); if (is_best_child) { *s = *child; endstate( d, ko_ld, base_nodes, pass_nodes, ko_nodes, s, child_v, !turn, !low_player ); } } } }
efloat_t DParrayConstrained::Pr_sum_all_paths() const { const int I = size()-1; double total = 0.0; for(int s1=0; s1<states(I).size(); s1++) { int state1 = states(I)[s1]; total += (*this)(I,state1) * GQ(state1,endstate()); } return pow<efloat_t>(2.0,scale(I)) * total; }
/* Matches the supplied string against the supplied pattern. Returns 0 for match * failure, 1 for match success, and -1 for out of memory. */ int match(const char *pat, const char *str) { struct states ss = { 0, NULL }; int i; if (startstates(&ss, (char *)pat)) return -1; while (*str) { if (step(&ss, *(str++))) return -1; if (!ss.n) return 0; } for (i = 0; i < ss.n; i++) { if (endstate(ss.p[i])) break; } free(ss.p); return i != ss.n; }
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 test() { solution sol_; solution *sol = &sol_; char *buffer = file_to_buffer("cho589_capture.dat"); buffer = load_solution(sol, buffer, 1); state s_; state *s = &s_; // sscanf_state("4337799298623 4335912108032 1879319553 0 1879048192 4335912108032 0 0 0", s); sscanf_state("4337799298623 4335918405632 1879319581 0 1879048192 4335912108032 0 0 0", s); print_state(s); size_t layer; size_t key = to_key_s(sol, s, &layer); // node_value v = negamax_node(sol, s, key, layer, 0); // print_node(v); // node_value v_b = sol->base_nodes[layer][key_index(sol->d, key)]; // print_node(v_b); // endstate(sol, s, v, 0, 1); // print_state(s); state new_s_; state *new_s = &new_s_; *new_s = *s; node_value v = negamax_node(sol, s, key, 0, 0); endstate(sol, new_s, v, 0, 1); print_state(new_s); // 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); print_stones(player_alive); print_stones(opponent_alive); 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) { assert(!(player_target & ~player_alive)); // Both shouldn't be dead. 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); } printf("%d\n", score); }
// 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); } }