diff options
Diffstat (limited to 'kpat/freecell-solver/lib.c')
-rw-r--r-- | kpat/freecell-solver/lib.c | 1244 |
1 files changed, 1244 insertions, 0 deletions
diff --git a/kpat/freecell-solver/lib.c b/kpat/freecell-solver/lib.c new file mode 100644 index 00000000..1839614b --- /dev/null +++ b/kpat/freecell-solver/lib.c @@ -0,0 +1,1244 @@ +/* + * lib.c - library interface functions of Freecell Solver. + * + * Written by Shlomi Fish (shlomif@vipe.technion.ac.il), 2000 + * + * This file is in the public domain (it's uncopyrighted). + */ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "card.h" +#include "fcs.h" +#include "preset.h" +#include "fcs_user.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +struct fcs_instance_item_struct +{ + freecell_solver_instance_t * instance; + int ret; + int limit; +}; + +typedef struct fcs_instance_item_struct fcs_instance_item_t; + +struct fcs_user_struct +{ + /* + * This is a list of several consecutive instances that are run + * one after the other in case the previous ones could not solve + * the board + * */ + fcs_instance_item_t * instances_list; + int num_instances; + int max_num_instances; + + int current_instance_idx; + /* + * The global (sequence-wide) limit of the iterations. Used + * by limit_iterations() and friends + * */ + int current_iterations_limit; + /* + * The number of iterations this board started at. + * */ + int iterations_board_started_at; + /* + * The number of iterations that the current instance started solving from. + * */ + int init_num_times; + /* + * A pointer to the currently active instance out of the sequence + * */ + freecell_solver_instance_t * instance; + fcs_state_with_locations_t state; + fcs_state_with_locations_t running_state; + int ret; + int state_validity_ret; + fcs_card_t state_validity_card; + freecell_solver_user_iter_handler_t iter_handler; + void * iter_handler_context; + + freecell_solver_soft_thread_t * soft_thread; + +#ifdef INDIRECT_STACK_STATES + fcs_card_t indirect_stacks_buffer[MAX_NUM_STACKS << 7]; +#endif + char * state_string_copy; + + fcs_preset_t common_preset; +}; + +typedef struct fcs_user_struct fcs_user_t; + +static void user_initialize( + fcs_user_t * ret + ) +{ + const fcs_preset_t * freecell_preset; + + freecell_solver_get_preset_by_name( + "freecell", + &freecell_preset + ); + + fcs_duplicate_preset(ret->common_preset, *freecell_preset); + + ret->max_num_instances = 10; + ret->instances_list = malloc(sizeof(ret->instances_list[0]) * ret->max_num_instances); + ret->num_instances = 1; + ret->current_instance_idx = 0; + ret->instance = freecell_solver_alloc_instance(); + freecell_solver_apply_preset_by_ptr(ret->instance, &(ret->common_preset)); + ret->instances_list[ret->current_instance_idx].instance = ret->instance; + ret->instances_list[ret->current_instance_idx].ret = ret->ret = FCS_STATE_NOT_BEGAN_YET; + ret->instances_list[ret->current_instance_idx].limit = -1; + ret->current_iterations_limit = -1; + + ret->soft_thread = + freecell_solver_instance_get_soft_thread( + ret->instance, 0,0 + ); + + ret->state_string_copy = NULL; + ret->iterations_board_started_at = 0; +} + +void * freecell_solver_user_alloc(void) +{ + fcs_user_t * ret; + + ret = (fcs_user_t *)malloc(sizeof(fcs_user_t)); + + user_initialize(ret); + + return (void*)ret; +} + +int freecell_solver_user_apply_preset( + void * user_instance, + const char * preset_name) +{ + const fcs_preset_t * new_preset_ptr; + fcs_user_t * user; + int status; + int i; + + user = (fcs_user_t*)user_instance; + + status = + freecell_solver_get_preset_by_name( + preset_name, + &new_preset_ptr + ); + + if (status != FCS_PRESET_CODE_OK) + { + return status; + } + + for(i = 0 ; i < user->num_instances ; i++) + { + status = freecell_solver_apply_preset_by_ptr( + user->instances_list[i].instance, + new_preset_ptr + ); + + if (status != FCS_PRESET_CODE_OK) + { + return status; + } + } + + fcs_duplicate_preset(user->common_preset, *new_preset_ptr); + + return FCS_PRESET_CODE_OK; +} + +void freecell_solver_user_limit_iterations( + void * user_instance, + int max_iters + ) +{ + fcs_user_t * user; + + user = (fcs_user_t*)user_instance; + + user->current_iterations_limit = max_iters; +} + +void freecell_solver_user_limit_current_instance_iterations( + void * user_instance, + int max_iters + ) +{ + fcs_user_t * user; + + user = (fcs_user_t*)user_instance; + + user->instances_list[user->current_instance_idx].limit = max_iters; +} + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +int freecell_solver_user_set_tests_order( + void * user_instance, + const char * tests_order, + char * * error_string + ) +{ + fcs_user_t * user; + + user = (fcs_user_t*)user_instance; + + return + freecell_solver_apply_tests_order( + &(user->soft_thread->tests_order), + tests_order, + error_string + ); +} + +int freecell_solver_user_solve_board( + void * user_instance, + const char * state_as_string + ) +{ + fcs_user_t * user; + + user = (fcs_user_t*)user_instance; + + user->state_string_copy = strdup(state_as_string); + + user->current_instance_idx = 0; + + return freecell_solver_user_resume_solution(user_instance); +} + +static void recycle_instance( + fcs_user_t * user, + int i + ) +{ + if (user->instances_list[i].ret == FCS_STATE_WAS_SOLVED) + { + fcs_move_stack_destroy(user->instance->solution_moves); + user->instance->solution_moves = NULL; + } + else if (user->instances_list[i].ret == FCS_STATE_SUSPEND_PROCESS) + { + freecell_solver_unresume_instance(user->instances_list[i].instance); + } + + if (user->instances_list[i].ret != FCS_STATE_NOT_BEGAN_YET) + { + freecell_solver_recycle_instance(user->instances_list[i].instance); + /* + * We have to initialize init_num_times to 0 here, because it may not + * get initialized again, and now the num_times of the instance + * is equal to 0. + * */ + user->init_num_times = 0; + } + + user->instances_list[i].ret = FCS_STATE_NOT_BEGAN_YET; +} + +int freecell_solver_user_resume_solution( + void * user_instance + ) +{ + int init_num_times; + int run_for_first_iteration = 1; + int ret; + fcs_user_t * user; + + user = (fcs_user_t*)user_instance; + + /* + * I expect user->current_instance_idx to be initialized at some value. + * */ + for( ; + run_for_first_iteration || ((user->current_instance_idx < user->num_instances) && (ret == FCS_STATE_IS_NOT_SOLVEABLE)) ; + recycle_instance(user, user->current_instance_idx), user->current_instance_idx++ + ) + { + run_for_first_iteration = 0; + + user->instance = user->instances_list[user->current_instance_idx].instance; + + if (user->instances_list[user->current_instance_idx].ret == FCS_STATE_NOT_BEGAN_YET) + { + int status; + status = freecell_solver_initial_user_state_to_c( + user->state_string_copy, + &(user->state), + user->instance->freecells_num, + user->instance->stacks_num, + user->instance->decks_num +#ifdef FCS_WITH_TALONS + ,user->instance->talon_type +#endif +#ifdef INDIRECT_STACK_STATES + ,user->indirect_stacks_buffer +#endif + ); + + if (status != FCS_USER_STATE_TO_C__SUCCESS) + { + user->ret = FCS_STATE_INVALID_STATE; + user->state_validity_ret = FCS_STATE_VALIDITY__PREMATURE_END_OF_INPUT; + return user->ret; + } + + user->state_validity_ret = freecell_solver_check_state_validity( + &user->state, + user->instance->freecells_num, + user->instance->stacks_num, + user->instance->decks_num, +#ifdef FCS_WITH_TALONS + FCS_TALON_NONE, +#endif + &(user->state_validity_card)); + + if (user->state_validity_ret != 0) + { + user->ret = FCS_STATE_INVALID_STATE; + return user->ret; + } + + + /* running_state is a normalized state. So I'm duplicating + * state to it before state is canonized + * */ + fcs_duplicate_state(user->running_state, user->state); + + fcs_canonize_state( + &user->state, + user->instance->freecells_num, + user->instance->stacks_num + ); + + freecell_solver_init_instance(user->instance); + +#define global_limit() \ + (user->instance->num_times + user->current_iterations_limit - user->iterations_board_started_at) +#define local_limit() \ + (user->instances_list[user->current_instance_idx].limit) +#define min(a,b) (((a)<(b))?(a):(b)) +#define calc_max_iters() \ + { \ + if (user->instances_list[user->current_instance_idx].limit < 0) \ + {\ + if (user->current_iterations_limit < 0)\ + {\ + user->instance->max_num_times = -1;\ + }\ + else\ + {\ + user->instance->max_num_times = global_limit();\ + }\ + }\ + else\ + {\ + if (user->current_iterations_limit < 0)\ + {\ + user->instance->max_num_times = local_limit();\ + }\ + else\ + {\ + int a, b;\ + \ + a = global_limit();\ + b = local_limit();\ + \ + user->instance->max_num_times = min(a,b);\ + }\ + }\ + } + + + calc_max_iters(); + + user->init_num_times = init_num_times = user->instance->num_times; + + ret = user->ret = + user->instances_list[user->current_instance_idx].ret = + freecell_solver_solve_instance(user->instance, &user->state); + } + else + { + + calc_max_iters(); + + user->init_num_times = init_num_times = user->instance->num_times; + + ret = user->ret = + user->instances_list[user->current_instance_idx].ret = + freecell_solver_resume_instance(user->instance); + } + + user->iterations_board_started_at += user->instance->num_times - init_num_times; + user->init_num_times = user->instance->num_times; + + if (user->ret == FCS_STATE_WAS_SOLVED) + { + freecell_solver_move_stack_normalize( + user->instance->solution_moves, + &(user->state), + user->instance->freecells_num, + user->instance->stacks_num, + user->instance->decks_num + ); + + break; + } + else if (user->ret == FCS_STATE_SUSPEND_PROCESS) + { + /* + * First - check if we exceeded our limit. If so - we must terminate + * and return now. + * */ + if ((user->current_iterations_limit >= 0) && + (user->iterations_board_started_at >= user->current_iterations_limit)) + { + break; + } + + /* + * Determine if we exceeded the instance-specific quota and if + * so, designate it as unsolvable. + * */ + if ((local_limit() >= 0) && + (user->instance->num_times >= local_limit()) + ) + { + ret = FCS_STATE_IS_NOT_SOLVEABLE; + } + } + } + + return ret; +} + +int freecell_solver_user_get_next_move( + void * user_instance, + fcs_move_t * move + ) +{ + fcs_user_t * user; + + user = (fcs_user_t*)user_instance; + if (user->ret == FCS_STATE_WAS_SOLVED) + { + int ret; + + ret = fcs_move_stack_pop( + user->instance->solution_moves, + move + ); + + if (ret == 0) + { + freecell_solver_apply_move( + &(user->running_state), + *move, + user->instance->freecells_num, + user->instance->stacks_num, + user->instance->decks_num + ); + } + return ret; + } + else + { + return 1; + } +} + +char * freecell_solver_user_current_state_as_string( + void * user_instance, + int parseable_output, + int canonized_order_output, + int display_10_as_t + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + return + freecell_solver_state_as_string( + &(user->running_state), + user->instance->freecells_num, + user->instance->stacks_num, + user->instance->decks_num, + parseable_output, + canonized_order_output, + display_10_as_t + ); +} + +static void user_free_resources( + fcs_user_t * user + ) +{ + int i; + + for(i=0;i<user->num_instances;i++) + { + int ret_code = user->instances_list[i].ret; + + if (ret_code == FCS_STATE_WAS_SOLVED) + { + fcs_move_stack_destroy(user->instance->solution_moves); + user->instance->solution_moves = NULL; + } + else if (ret_code == FCS_STATE_SUSPEND_PROCESS) + { + freecell_solver_unresume_instance(user->instances_list[i].instance); + } + + if (ret_code != FCS_STATE_NOT_BEGAN_YET) + { + if (ret_code != FCS_STATE_INVALID_STATE) + { + freecell_solver_finish_instance(user->instances_list[i].instance); + } + } + + freecell_solver_free_instance(user->instances_list[i].instance); + } + + free(user->instances_list); + + if (user->state_string_copy != NULL) + { + free(user->state_string_copy); + user->state_string_copy = NULL; + } +} + +void freecell_solver_user_free( + void * user_instance + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user_free_resources(user); + + free(user); +} + +int freecell_solver_user_get_current_depth( + void * user_instance + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + return (user->soft_thread->num_solution_states - 1); +} + +void freecell_solver_user_set_solving_method( + void * user_instance, + int method + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->soft_thread->method = method; +} + +#define set_for_all_instances(what) \ + { \ + for(i = 0 ; i < user->num_instances ; i++) \ + { \ + user->instances_list[i].instance->what = what; \ + } \ + user->common_preset.what = what; \ + } + +int freecell_solver_user_set_num_freecells( + void * user_instance, + int freecells_num + ) +{ + fcs_user_t * user; + int i; + + user = (fcs_user_t *)user_instance; + + if ((freecells_num < 0) || (freecells_num > MAX_NUM_FREECELLS)) + { + return 1; + } + + set_for_all_instances(freecells_num); + + return 0; +} + +int freecell_solver_user_set_num_stacks( + void * user_instance, + int stacks_num + ) +{ + fcs_user_t * user; + int i; + + user = (fcs_user_t *)user_instance; + + if ((stacks_num < 0) || (stacks_num > MAX_NUM_STACKS)) + { + return 1; + } + set_for_all_instances(stacks_num); + + return 0; +} + +int freecell_solver_user_set_num_decks( + void * user_instance, + int decks_num + ) +{ + fcs_user_t * user; + int i; + + user = (fcs_user_t *)user_instance; + + if ((decks_num < 0) || (decks_num > MAX_NUM_DECKS)) + { + return 1; + } + set_for_all_instances(decks_num); + + return 0; +} + + +int freecell_solver_user_set_game( + void * user_instance, + int freecells_num, + int stacks_num, + int decks_num, + int sequences_are_built_by, + int unlimited_sequence_move, + int empty_stacks_fill + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + if (freecell_solver_user_set_num_freecells(user_instance, freecells_num)) + { + return 1; + } + if (freecell_solver_user_set_num_stacks(user_instance, stacks_num)) + { + return 2; + } + if (freecell_solver_user_set_num_decks(user_instance, decks_num)) + { + return 3; + } + if (freecell_solver_user_set_sequences_are_built_by_type(user_instance, sequences_are_built_by)) + { + return 4; + } + if (freecell_solver_user_set_sequence_move(user_instance, unlimited_sequence_move)) + { + return 5; + } + if (freecell_solver_user_set_empty_stacks_filled_by(user_instance, empty_stacks_fill)) + { + return 6; + } + + return 0; +} + +int freecell_solver_user_get_num_times(void * user_instance) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + return user->iterations_board_started_at + user->instance->num_times - user->init_num_times; +} + +int freecell_solver_user_get_limit_iterations(void * user_instance) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + return user->instance->max_num_times; +} + +int freecell_solver_user_get_moves_left(void * user_instance) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + if (user->ret == FCS_STATE_WAS_SOLVED) + return user->instance->solution_moves->num_moves; + else + return 0; +} + +void freecell_solver_user_set_solution_optimization( + void * user_instance, + int optimize +) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->instance->optimize_solution_path = optimize; +} + +char * freecell_solver_user_move_to_string( + fcs_move_t move, + int standard_notation + ) +{ + return freecell_solver_move_to_string(move, standard_notation); +} + +char * freecell_solver_user_move_to_string_w_state( + void * user_instance, + fcs_move_t move, + int standard_notation + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + return + freecell_solver_move_to_string_w_state( + &(user->running_state), + user->instance->freecells_num, + user->instance->stacks_num, + user->instance->decks_num, + move, + standard_notation + ); +} + +void freecell_solver_user_limit_depth( + void * user_instance, + int max_depth +) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->instance->max_depth = max_depth; +} + +int freecell_solver_user_get_max_num_freecells(void) +{ + return MAX_NUM_FREECELLS; +} + +int freecell_solver_user_get_max_num_stacks(void) +{ + return MAX_NUM_STACKS; +} + +int freecell_solver_user_get_max_num_decks(void) +{ + return MAX_NUM_DECKS; +} + + +char * freecell_solver_user_get_invalid_state_error_string( + void * user_instance, + int print_ts + ) +{ + fcs_user_t * user; + char string[80], card_str[10]; + + user = (fcs_user_t *)user_instance; + + if (user->state_validity_ret == FCS_STATE_VALIDITY__OK) + { + return strdup(""); + } + fcs_card_perl2user(user->state_validity_card, card_str, print_ts); + + if (user->state_validity_ret == FCS_STATE_VALIDITY__EMPTY_SLOT) + { + sprintf(string, "%s", + "There's an empty slot in one of the stacks." + ); + } + else if ((user->state_validity_ret == FCS_STATE_VALIDITY__EXTRA_CARD) || + (user->state_validity_ret == FCS_STATE_VALIDITY__MISSING_CARD) + ) + { + sprintf(string, "%s%s.", + ((user->state_validity_ret == FCS_STATE_VALIDITY__EXTRA_CARD)? "There's an extra card: " : "There's a missing card: "), + card_str + ); + } + else if (user->state_validity_ret == FCS_STATE_VALIDITY__PREMATURE_END_OF_INPUT) + { + sprintf(string, "%s.", "Not enough input"); + } + return strdup(string); +} + +int freecell_solver_user_set_sequences_are_built_by_type( + void * user_instance, + int sequences_are_built_by + ) +{ + fcs_user_t * user; + int i; + + user = (fcs_user_t *)user_instance; + + if ((sequences_are_built_by < 0) || (sequences_are_built_by > 2)) + { + return 1; + } + set_for_all_instances(sequences_are_built_by) + + return 0; +} + +int freecell_solver_user_set_sequence_move( + void * user_instance, + int unlimited_sequence_move + ) +{ + fcs_user_t * user; + int i; + + user = (fcs_user_t *)user_instance; + + set_for_all_instances(unlimited_sequence_move); + + return 0; +} + +int freecell_solver_user_set_empty_stacks_filled_by( + void * user_instance, + int empty_stacks_fill + ) +{ + fcs_user_t * user; + int i; + + user = (fcs_user_t *)user_instance; + + if ((empty_stacks_fill < 0) || (empty_stacks_fill > 2)) + { + return 1; + } + set_for_all_instances(empty_stacks_fill); + + return 0; +} + +int freecell_solver_user_set_a_star_weight( + void * user_instance, + int index, + double weight + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + if ((index < 0) || (index >= (int)(sizeof(user->soft_thread->a_star_weights)/sizeof(user->soft_thread->a_star_weights[0])))) + { + return 1; + } + if (weight < 0) + { + return 2; + } + + user->soft_thread->a_star_weights[index] = weight; + + return 0; + +} + +static void freecell_solver_user_iter_handler_wrapper( + void * user_instance, + int iter_num, + int depth, + void * lp_instance, + fcs_state_with_locations_t * ptr_state_with_locations, + int parent_iter_num + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->iter_handler( + user_instance, + iter_num, + depth, + (void *)ptr_state_with_locations, + parent_iter_num, + user->iter_handler_context + ); + + (void)lp_instance; + return; +} + +void freecell_solver_user_set_iter_handler( +void * user_instance, +freecell_solver_user_iter_handler_t iter_handler, +void * iter_handler_context +) +{ +fcs_user_t * user; + +user = (fcs_user_t *)user_instance; + +if (iter_handler == NULL) +{ + user->instance->debug_iter_output = 0; +} +else +{ + /* Disable it temporarily while we change the settings */ + user->instance->debug_iter_output = 0; + user->iter_handler = iter_handler; + user->iter_handler_context = iter_handler_context; + user->instance->debug_iter_output_context = user; + user->instance->debug_iter_output_func = freecell_solver_user_iter_handler_wrapper; + user->instance->debug_iter_output = 1; +} +} + +char * freecell_solver_user_iter_state_as_string( +void * user_instance, +void * ptr_state, +int parseable_output, +int canonized_order_output, +int display_10_as_t +) +{ +fcs_user_t * user; + +user = (fcs_user_t *)user_instance; + +return + freecell_solver_state_as_string( + ptr_state, + user->instance->freecells_num, + user->instance->stacks_num, + user->instance->decks_num, + parseable_output, + canonized_order_output, + display_10_as_t + ); +} + +void freecell_solver_user_set_random_seed( +void * user_instance, +int seed +) +{ +fcs_user_t * user; + +user = (fcs_user_t *)user_instance; + +freecell_solver_rand_srand(user->soft_thread->rand_gen, (user->soft_thread->rand_seed = seed)); +} + +int freecell_solver_user_get_num_states_in_collection(void * user_instance) +{ +fcs_user_t * user; + +user = (fcs_user_t *)user_instance; + +return user->instance->num_states_in_collection; +} + +void freecell_solver_user_limit_num_states_in_collection( +void * user_instance, +int max_num_states + ) +{ + fcs_user_t * user; + + user = (fcs_user_t*)user_instance; + + user->instance->max_num_states_in_collection = max_num_states; +} + +int freecell_solver_user_next_soft_thread( + void * user_instance + ) +{ + fcs_user_t * user; + freecell_solver_soft_thread_t * soft_thread; + + user = (fcs_user_t *)user_instance; + + soft_thread = freecell_solver_new_soft_thread(user->soft_thread); + + if (soft_thread == NULL) + { + return 1; + } + + user->soft_thread = soft_thread; + + return 0; +} + +extern void freecell_solver_user_set_soft_thread_step( + void * user_instance, + int num_times_step + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->soft_thread->num_times_step = num_times_step; +} + +int freecell_solver_user_next_hard_thread( + void * user_instance + ) +{ + fcs_user_t * user; + freecell_solver_soft_thread_t * soft_thread; + + user = (fcs_user_t *)user_instance; + + soft_thread = freecell_solver_new_hard_thread(user->instance); + + if (soft_thread == NULL) + { + return 1; + } + + user->soft_thread = soft_thread; + + return 0; +} + +int freecell_solver_user_get_num_soft_threads_in_instance( + void * user_instance + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + return user->instance->next_soft_thread_id; +} + +void freecell_solver_user_set_calc_real_depth( + void * user_instance, + int calc_real_depth +) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->instance->calc_real_depth = calc_real_depth; +} + +void freecell_solver_user_set_soft_thread_name( + void * user_instance, + char * name + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + if (user->soft_thread->name != NULL) + { + free(user->soft_thread->name); + } + user->soft_thread->name = strdup(name); +} + +int freecell_solver_user_set_hard_thread_prelude( + void * user_instance, + char * prelude + ) +{ + fcs_user_t * user; + freecell_solver_hard_thread_t * hard_thread; + + user = (fcs_user_t *)user_instance; + + hard_thread = user->soft_thread->hard_thread; + + if (hard_thread->prelude_as_string != NULL) + { + free(hard_thread->prelude_as_string); + hard_thread->prelude_as_string = NULL; + } + hard_thread->prelude_as_string = strdup(prelude); + + return 0; +} + +void freecell_solver_user_recycle( + void * user_instance + ) +{ + fcs_user_t * user; + int i; + + user = (fcs_user_t *)user_instance; + + for(i=0;i<user->num_instances;i++) + { + recycle_instance(user, i); + } + user->current_iterations_limit = -1; + user->iterations_board_started_at = 0; + if (user->state_string_copy != NULL) + { + free(user->state_string_copy); + user->state_string_copy = NULL; + } +} + +int freecell_solver_user_set_optimization_scan_tests_order( + void * user_instance, + const char * tests_order, + char * * error_string + ) +{ + fcs_user_t * user; + int ret; + + user = (fcs_user_t*)user_instance; + + if (user->instance->opt_tests_order.tests) + { + free(user->instance->opt_tests_order.tests); + user->instance->opt_tests_order.tests = NULL; + } + + user->instance->opt_tests_order_set = 0; + + ret = + freecell_solver_apply_tests_order( + &(user->instance->opt_tests_order), + tests_order, + error_string + ); + + if (!ret) + { + user->instance->opt_tests_order_set = 1; + } + + return ret; +} + +void freecell_solver_user_set_reparent_states( + void * user_instance, + int to_reparent_states + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->instance->to_reparent_states = to_reparent_states; +} + +void freecell_solver_user_set_scans_synergy( + void * user_instance, + int synergy + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->instance->scans_synergy = synergy; +} + +int freecell_solver_user_next_instance( + void * user_instance + ) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user->num_instances++; + if (user->num_instances == user->max_num_instances) + { + user->max_num_instances += 10; + user->instances_list = + realloc( + user->instances_list, + sizeof(user->instances_list[0])*user->max_num_instances + ); + } + user->current_instance_idx = user->num_instances-1; + user->instance = freecell_solver_alloc_instance(); + + freecell_solver_apply_preset_by_ptr(user->instance, &(user->common_preset)); + + /* + * Switch the soft_thread variable so it won't refer to the old + * instance + * */ + user->soft_thread = + freecell_solver_instance_get_soft_thread( + user->instance, 0, 0 + ); + + user->instances_list[user->current_instance_idx].instance = user->instance; + user->instances_list[user->current_instance_idx].ret = user->ret = FCS_STATE_NOT_BEGAN_YET; + user->instances_list[user->current_instance_idx].limit = -1; + + return 0; +} + +int freecell_solver_user_reset(void * user_instance) +{ + fcs_user_t * user; + + user = (fcs_user_t *)user_instance; + + user_free_resources(user); + + user_initialize(user); + + return 0; +} + |