/** * @brief Recursive function used to traverse the game tree. * * @param [in] result a reference to the exact solution data structure * @param [in] gp the game position to traverse * @return a pointer to a new serch node structure */ static SearchNode * game_position_solve_impl ( ExactSolution * const result, const GamePosition * const gp_old) { SearchNode *node; SearchNode *node2; node = NULL; node2 = NULL; result->node_count++; NodeInfo * const node_info = &stack->nodes[++stack->fill_point]; //NodeInfo * const next_node_info = &stack->nodes[stack->fill_point]; LegalMoveList * const moves = &node_info->moves; const SquareSet move_set = game_position_legal_moves(gp_old); legal_move_list_from_set(move_set, moves); //GamePositionX * const gp = &node_info->gp; //GamePositionX * const next_gp = &next_node_info->gp; /* GamePosition gp; uint64 hash; */ if (move_set == empty_square_set) { GamePosition *flipped_players = game_position_pass(gp_old); const int previous_move_count = stack->nodes[stack->fill_point - 1].moves.move_count; const SquareSet empties = board_empties(gp_old->board); if (empties != empty_square_set && previous_move_count != 0) { node = search_node_negated(game_position_solve_impl(result, flipped_players)); } else { result->leaf_count++; node = search_node_new((Square) -1, game_position_final_value(gp_old)); } flipped_players = game_position_free(flipped_players); } else { node = search_node_new((Square) -1, -65); for (int i = 0; i < moves->move_count; i++) { const Square move = moves->squares[i]; GamePosition *gp2 = game_position_make_move(gp_old, move); node2 = search_node_negated(game_position_solve_impl(result, gp2)); gp2 = game_position_free(gp2); if (node2->value > node->value) { search_node_free(node); node = node2; node->move = move; node2 = NULL; } else { node2 = search_node_free(node2); } } } stack->fill_point--; return node; }
int exomizer(unsigned char *srcbuf, int len, int load, int start, unsigned char *destbuf) { int destlen; int max_offset = 65536; int max_passes = 65536; static match_ctx ctx; encode_match_data emd; encode_match_priv optimal_priv; search_nodep snp; match_ctx_init(ctx, srcbuf, len, max_offset); emd->out = NULL; emd->priv = optimal_priv; optimal_init(emd); snp = do_compress(ctx, emd, max_passes); destlen = generate_output(ctx, snp, sfx_c64ne, optimal_encode, emd, load, len, start, destbuf); optimal_free(emd); #if 0 /* RH */ search_node_free(snp); #endif /* RH */ match_ctx_free(ctx); return destlen; }
void crunch_backwards(struct membuf *inbuf, struct membuf *outbuf, struct crunch_options *options, /* IN */ struct crunch_info *info) /* OUT */ { static match_ctx ctx; encode_match_data emd; search_nodep snp; int outlen; int safety; int copy_used; if(options == NULL) { options = default_options; } outlen = membuf_memlen(outbuf); emd->out = NULL; optimal_init(emd); LOG(LOG_NORMAL, ("\nPhase 1: Instrumenting file" "\n-----------------------------\n")); LOG(LOG_NORMAL, (" Length of indata: %d bytes.\n", membuf_memlen(inbuf))); match_ctx_init(ctx, inbuf, options->max_len, options->max_offset, options->use_imprecise_rle); LOG(LOG_NORMAL, (" Instrumenting file, done.\n")); emd->out = NULL; optimal_init(emd); LOG(LOG_NORMAL, ("\nPhase 2: Calculating encoding" "\n-----------------------------\n")); snp = do_compress(ctx, emd, options->exported_encoding, options->max_passes, options->use_literal_sequences); LOG(LOG_NORMAL, (" Calculating encoding, done.\n")); LOG(LOG_NORMAL, ("\nPhase 3: Generating output file" "\n------------------------------\n")); LOG(LOG_NORMAL, (" Encoding: %s\n", optimal_encoding_export(emd))); safety = do_output(ctx, snp, emd, optimal_encode, outbuf, ©_used); LOG(LOG_NORMAL, (" Length of crunched data: %d bytes.\n", membuf_memlen(outbuf) - outlen)); optimal_free(emd); search_node_free(snp); match_ctx_free(ctx); if(info != NULL) { info->literal_sequences_used = copy_used; info->needed_safety_offset = safety; } }
/** * @brief Solves the game position returning a new exact solution pointer. * * @param [in] root the starting game position to be solved * @return a pointer to a new exact solution structure */ ExactSolution * game_position_rab_solve (const GamePosition * const root) { ExactSolution *result; SearchNode *sn; game_tree_stack_init(); result = exact_solution_new(); result->solved_game_position = game_position_clone(root); sn = game_position_solve_impl(result, result->solved_game_position); result->principal_variation[0] = sn->move; result->outcome = sn->value; sn = search_node_free(sn); return result; }
/* * Main recursive search function. */ static SearchNode * game_position_solve_impl (ExactSolution *const result, const GamePosition *const gp, const int achievable, const int cutoff, PVCell ***pve_parent_line_p) { result->node_count++; SearchNode *node = NULL; SearchNode *node2 = NULL; PVCell **pve_line = NULL; if (log_env->log_is_on) { call_count++; gp_hash_stack_fill_point++; LogDataH log_data; log_data.sub_run_id = 0; log_data.call_id = call_count; log_data.hash = game_position_hash(gp); gp_hash_stack[gp_hash_stack_fill_point] = log_data.hash; log_data.parent_hash = gp_hash_stack[gp_hash_stack_fill_point - 1]; log_data.blacks = (gp->board)->blacks; log_data.whites = (gp->board)->whites; log_data.player = gp->player; gchar *json_doc = game_tree_log_data_h_json_doc(gp_hash_stack_fill_point, gp); log_data.json_doc = json_doc; log_data.json_doc_len = strlen(json_doc); game_tree_log_write_h(log_env, &log_data); g_free(json_doc); } const SquareSet moves = game_position_legal_moves(gp); if (0ULL == moves) { pve_line = pve_line_create(pve); GamePosition *flipped_players = game_position_pass(gp); if (game_position_has_any_legal_move(flipped_players)) { node = search_node_negated(game_position_solve_impl(result, flipped_players, -cutoff, -achievable, &pve_line)); } else { result->leaf_count++; node = search_node_new(pass_move, game_position_final_value(gp)); } pve_line_add_move(pve, pve_line, pass_move, flipped_players); pve_line_delete(pve, *pve_parent_line_p); *pve_parent_line_p = pve_line; game_position_free(flipped_players); } else { MoveList move_list; bool branch_is_active = false; move_list_init(&move_list); sort_moves_by_mobility_count(&move_list, gp); for (MoveListElement *element = move_list.head.succ; element != &move_list.tail; element = element->succ) { const Square move = element->sq; if (!node) node = search_node_new(move, (pv_full_recording) ? achievable - 1 : achievable); GamePosition *gp2 = game_position_make_move(gp, move); pve_line = pve_line_create(pve); node2 = search_node_negated(game_position_solve_impl(result, gp2, -cutoff, -node->value, &pve_line)); if (node2->value > node->value || (!branch_is_active && node2->value == node->value)) { branch_is_active = true; search_node_free(node); node = node2; node->move = move; node2 = NULL; pve_line_add_move(pve, pve_line, move, gp2); game_position_free(gp2); pve_line_delete(pve, *pve_parent_line_p); *pve_parent_line_p = pve_line; if (node->value > cutoff) goto out; if (!pv_full_recording && node->value == cutoff) goto out; } else { if (pv_full_recording && node2->value == node->value) { pve_line_add_move(pve, pve_line, move, gp2); pve_line_add_variant(pve, *pve_parent_line_p, pve_line); } else { pve_line_delete(pve, pve_line); } search_node_free(node2); game_position_free(gp2); } } } out: if (log_env->log_is_on) { gp_hash_stack_fill_point--; } return node; }
/** * @brief Solves the game position returning a new exact solution pointer. * * @invariant Parameters `root` and `env` must be not `NULL`. * The invariants are guarded by assertions. * * @param [in] root the starting game position to be solved * @param [in] env parameter envelope * @return a pointer to a new exact solution structure */ ExactSolution * game_position_es_solve (const GamePositionX *const root, const endgame_solver_env_t *const env) { g_assert(root); g_assert(env); ExactSolution *result; SearchNode *sn; int alpha; int beta; pv_full_recording = env->pv_full_recording; log_env = game_tree_log_init(env->log_file); //GamePositionX *rootx = game_position_x_gp_to_gpx(root); pve = pve_new(root); //game_position_x_free(rootx); if (log_env->log_is_on) { gp_hash_stack[0] = 0; game_tree_log_open_h(log_env); } if (pv_full_recording) { alpha = out_of_range_defeat_score; beta = out_of_range_win_score; } else { alpha = worst_score; beta = best_score; } result = exact_solution_new(); result->solved_game_position = game_position_clone(game_position_x_gpx_to_gp(root)); sn = game_position_solve_impl(result, result->solved_game_position, alpha, beta, &(pve->root_line)); if (sn) { result->pv[0] = sn->move; result->outcome = sn->value; pve_line_copy_to_exact_solution(pve, (const PVCell **const) pve->root_line, result); exact_solution_compute_final_board(result); } if (pv_full_recording && !env->pv_no_print) { printf("\n --- --- pve_line_with_variants_to_string() START --- ---\n"); pve_line_with_variants_to_stream(pve, stdout); printf("\n --- --- pve_line_with_variants_to_string() COMPLETED --- ---\n"); } if (pv_internals_to_stream) { printf("\nThe constant \"pv_internals_to_stream\", in source file \"exact_solver.c\", is TRUE. Printing PVE internals:\n"); printf(" --- --- pve_is_invariant_satisfied() START --- ---\n"); pve_error_code_t error_code = 0; pve_is_invariant_satisfied(pve, &error_code, 0xFF); if (error_code) { printf("error_code=%d\n", error_code); abort(); } printf(" --- --- pve_is_invariant_satisfied() COMPLETED --- ---\n"); printf("\n --- --- pve_internals_to_stream() START --- ---\n"); switches_t shown_sections = 0x0000; shown_sections |= pve_internals_header_section; shown_sections |= pve_internals_index_section; shown_sections |= pve_internals_properties_section; shown_sections |= pve_internals_structure_section; shown_sections |= pve_internals_computed_properties_section; //shown_sections |= pve_internals_active_lines_section; shown_sections |= pve_internals_cells_segments_section; shown_sections |= pve_internals_sorted_cells_segments_section; shown_sections |= pve_internals_cells_section; shown_sections |= pve_internals_cells_stack_section; shown_sections |= pve_internals_lines_segments_section; shown_sections |= pve_internals_sorted_lines_segments_section; shown_sections |= pve_internals_lines_section; shown_sections |= pve_internals_lines_stack_section; pve_internals_to_stream(pve, stdout, shown_sections); printf("\n --- --- pve_internals_to_stream() COMPLETED --- ---\n"); } if (env->pve_dump_file) { printf("\n --- --- pve_dump_to_binary_file() START --- ---\n"); pve_dump_to_binary_file(pve, env->pve_dump_file); printf(" --- --- pve_dump_to_binary_file() COMPLETED --- ---\n"); } search_node_free(sn); pve_free(pve); game_tree_log_close(log_env); return result; }
search_nodep do_compress(match_ctx ctx, encode_match_data emd, const char *exported_encoding, int max_passes, int use_literal_sequences) { matchp_cache_enum mpce; matchp_snp_enum snpe; search_nodep snp; search_nodep best_snp; int pass; float size; float old_size; char prev_enc[100]; const char *curr_enc; pass = 1; prev_enc[0] = '\0'; LOG(LOG_NORMAL, (" pass %d: ", pass)); if(exported_encoding != NULL) { LOG(LOG_NORMAL, ("importing %s\n", exported_encoding)); optimal_encoding_import(emd, exported_encoding); } else { LOG(LOG_NORMAL, ("optimizing ..\n")); matchp_cache_get_enum(ctx, mpce); optimal_optimize(emd, matchp_cache_enum_get_next, mpce); } best_snp = NULL; old_size = 100000000.0; for (;;) { snp = search_buffer(ctx, optimal_encode, emd, use_literal_sequences); if (snp == NULL) { LOG(LOG_ERROR, ("error: search_buffer() returned NULL\n")); exit(-1); } size = snp->total_score; LOG(LOG_NORMAL, (" size %0.1f bits ~%d bytes\n", size, (((int) size) + 7) >> 3)); if (size >= old_size) { search_node_free(snp); break; } if (best_snp != NULL) { search_node_free(best_snp); } best_snp = snp; old_size = size; ++pass; if(pass > max_passes) { break; } optimal_free(emd); optimal_init(emd); LOG(LOG_NORMAL, (" pass %d: optimizing ..\n", pass)); matchp_snp_get_enum(snp, snpe); optimal_optimize(emd, matchp_snp_enum_get_next, snpe); curr_enc = optimal_encoding_export(emd); if (strcmp(curr_enc, prev_enc) == 0) { break; } strcpy(prev_enc, curr_enc); } return best_snp; }
static search_nodep do_compress(match_ctx ctx, encode_match_data emd, int max_passes) { matchp_cache_enum mpce; matchp_snp_enum snpe; search_nodep snp; search_nodep best_snp; int pass; float old_size; pass = 1; matchp_cache_get_enum(ctx, mpce); optimal_optimize(emd, matchp_cache_enum_get_next, mpce); best_snp = NULL; old_size = 1000000.0; for (;;) { snp = search_buffer(ctx, optimal_encode, emd); if (snp == NULL) { fprintf(stderr, "error: search_buffer() returned NULL\n"); exit(-1); } float size = snp->total_score; if (size >= old_size) { #if 0 /* RH */ search_node_free(snp); #endif /* RH */ break; } #if 0 /* RH */ if (best_snp != NULL) { search_node_free(best_snp); } #endif /* RH */ best_snp = snp; old_size = size; ++pass; if (pass > max_passes) { break; } optimal_free(emd); optimal_init(emd); matchp_snp_get_enum(snp, snpe); optimal_optimize(emd, matchp_snp_enum_get_next, snpe); } return best_snp; }