static void fc_solve_state_string_to_enc(
    enum fcs_dbm_variant_type_t local_variant,
    fc_solve_delta_stater_t * delta,
    const char * const state_s_proto,
    fcs_encoded_state_buffer_t * enc_state
)
{
    fcs_state_keyval_pair_t state;
    DECLARE_IND_BUF_T(state_indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(
        state_s_proto,
        &state,
        FREECELLS_NUM,
        STACKS_NUM,
        DECKS_NUM,
        state_indirect_stacks_buffer
        );

    fcs_init_and_encode_state(
        delta,
        local_variant,
        &(state),
        enc_state
    );
}
コード例 #2
0
ファイル: delta_states.c プロジェクト: shlomif/fc-solve
// The char * returned is malloc()ed and should be free()ed.
DLLEXPORT char *fc_solve_user_INTERNAL_delta_states_enc_and_dec(
    const fcs_dbm_variant_type local_variant GCC_UNUSED,
    const char *const init_state_s, const char *const derived_state_s)
{
    fcs_state_keyval_pair init_state, derived_state, new_derived_state;
    fcs_uchar enc_state[24];
    fcs_bit_reader bit_r;
    fcs_state_locs_struct locs;
    fc_solve_init_locs(&locs);

    DECLARE_IND_BUF_T(indirect_stacks_buffer)
    DECLARE_IND_BUF_T(derived_stacks_buffer)
    DECLARE_IND_BUF_T(new_derived_indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(init_state_s, &init_state, FREECELLS_NUM,
        STACKS_NUM, DECKS_NUM, indirect_stacks_buffer);

    fc_solve_initial_user_state_to_c(derived_state_s, &derived_state,
        FREECELLS_NUM, STACKS_NUM, DECKS_NUM, derived_stacks_buffer);

    fcs_delta_stater delta;
    fc_solve_delta_stater_init(&delta, local_variant, &(init_state.s),
        STACKS_NUM,
        FREECELLS_NUM PASS_ON_NOT_FC_ONLY(FCS_SEQ_BUILT_BY_ALTERNATE_COLOR));

    fc_solve_delta_stater_set_derived(&delta, &(derived_state.s));

    fc_solve_state_init(
        &new_derived_state, STACKS_NUM, new_derived_indirect_stacks_buffer);

    fc_solve_bit_writer bit_w;
    fc_solve_bit_writer_init(&bit_w, enc_state);
    fc_solve_delta_stater_encode_composite(&delta, &bit_w);

    fc_solve_bit_reader_init(&bit_r, enc_state);
    fc_solve_delta_stater_decode(&delta, &bit_r, &(new_derived_state.s));

    char *new_derived_as_str = SMALLOC(new_derived_as_str, 1000);
    FCS__RENDER_STATE(new_derived_as_str, &(new_derived_state.s), &locs);

    fc_solve_delta_stater_release(&delta);
    return new_derived_as_str;
}
/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_perform_horne_prune(
        enum fcs_dbm_variant_type_t local_variant,
        const char * init_state_str_proto,
        char * * ret_state_s
        )
{
    fcs_state_keyval_pair_t init_state;
    fcs_state_locs_struct_t locs;
    int prune_ret;

    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_init_locs(&locs);

    fc_solve_initial_user_state_to_c(
            init_state_str_proto,
            &init_state,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            indirect_stacks_buffer
            );

    {
        fcs_which_moves_bitmask_t which_no_use = {{'\0'}};
        prune_ret = horne_prune(local_variant, &init_state, &which_no_use, NULL, NULL);
    }
    *ret_state_s =
        fc_solve_state_as_string(
            &(init_state.s),
            &locs,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            1,
            0,
            1
            );

    return prune_ret;
}
/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_calc_derived_states_wrapper(
        enum fcs_dbm_variant_type_t local_variant,
        const char * init_state_str_proto,
        int * const num_out_derived_states,
        fcs_derived_state_debug_t * * out_derived_states,
        const fcs_bool_t perform_horne_prune
        )
{
    fcs_state_keyval_pair_t init_state;
    fc_solve_delta_stater_t * delta;
    fcs_encoded_state_buffer_t enc_state;
    fcs_state_locs_struct_t locs;
    fcs_derived_state_t * derived_list = NULL;
    fcs_derived_state_t * derived_list_recycle_bin = NULL;
    fcs_compact_allocator_t allocator;
    fcs_meta_compact_allocator_t meta_alloc;
    int states_count = 0;
    fcs_derived_state_t * iter;
    fcs_derived_state_debug_t * debug_ret;
    int idx = 0;

    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(
            init_state_str_proto,
            &init_state,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            indirect_stacks_buffer
            );

    delta = fc_solve_delta_stater_alloc(
            &(init_state.s),
            STACKS_NUM,
            FREECELLS_NUM
#ifndef FCS_FREECELL_ONLY
            , FCS_SEQ_BUILT_BY_ALTERNATE_COLOR
#endif
            );

    fcs_init_and_encode_state(
        delta,
        local_variant,
        &(init_state),
        &enc_state
        );

    fc_solve_meta_compact_allocator_init (&meta_alloc);
    fc_solve_compact_allocator_init( &allocator, &meta_alloc);

    instance_solver_thread_calc_derived_states(
        local_variant,
        &init_state,
        NULL,
        &derived_list,
        &derived_list_recycle_bin,
        &allocator,
        perform_horne_prune
    );


    iter = derived_list;

    while (iter)
    {
        states_count++;
        iter = iter->next;
    }

    *(num_out_derived_states) = states_count;


    debug_ret = SMALLOC(debug_ret, states_count);

    *(out_derived_states) = debug_ret;

    fc_solve_init_locs(&locs);

    iter = derived_list;
    while (iter)
    {
        debug_ret[idx].state_string =
        fc_solve_state_as_string(
            &(iter->state.s),
            &locs,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            1,
            0,
            1
            );
        debug_ret[idx].move = iter->move;
        debug_ret[idx].core_irreversible_moves_count
            = iter->core_irreversible_moves_count;
        debug_ret[idx].num_non_reversible_moves_including_prune
            = iter->num_non_reversible_moves_including_prune;
        /* TODO : Put something meaningful there by passing it to the function. */
        debug_ret[idx].which_irreversible_moves_bitmask =
            iter->which_irreversible_moves_bitmask;
        idx++;
        iter = iter->next;
    }

    assert(idx == states_count);

    fc_solve_compact_allocator_finish(&allocator);
    fc_solve_meta_compact_allocator_finish( &meta_alloc );

    fc_solve_delta_stater_free (delta);

    return 0;
}
コード例 #5
0
ファイル: lib.c プロジェクト: BackupTheBerlios/fc-solve-svn
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;

    ret = FCS_STATE_IS_NOT_SOLVEABLE;

    /*
     * 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;
#if (!(defined(HARD_CODED_NUM_FREECELLS) && defined(HARD_CODED_NUM_STACKS) && defined(HARD_CODED_NUM_DECKS)))
            fc_solve_instance_t * instance = user->instance;
#endif

            status = fc_solve_initial_user_state_to_c(
                user->state_string_copy,
                &(user->state.s),
                &(user->state.info),
                INSTANCE_FREECELLS_NUM,
                INSTANCE_STACKS_NUM,
                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 = fc_solve_check_state_validity(
                &(user->state.info),
                INSTANCE_FREECELLS_NUM,
                INSTANCE_STACKS_NUM,
                INSTANCE_DECKS_NUM,
#ifdef FCS_WITH_TALONS
                FCS_TALON_NONE,
#endif
                &(user->state_validity_card));

            if (user->state_validity_ret != FCS_STATE_VALIDITY__OK)
            {
                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.s),
                &(user->running_state.info),
                &(user->state.s),
                &(user->state.info)
                );

            fc_solve_canonize_state(
                &user->state.info,
                INSTANCE_FREECELLS_NUM,
                INSTANCE_STACKS_NUM
                );

            fc_solve_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 =
                fc_solve_solve_instance(user->instance, &user->state.info);
        }
        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 =
                fc_solve_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)
        {
#if (!(defined(HARD_CODED_NUM_FREECELLS) && defined(HARD_CODED_NUM_STACKS) && defined(HARD_CODED_NUM_DECKS)))
            fc_solve_instance_t * instance = user->instance;
#endif
            fc_solve_move_stack_normalize(
                user->instance->solution_moves,
                &(user->state.info),
                INSTANCE_FREECELLS_NUM,
                INSTANCE_STACKS_NUM,
                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;
}
コード例 #6
0
int main(int argc, char *argv[])
{
    fcs_dbm_variant_type_t local_variant = FCS_DBM_VARIANT_2FC_FREECELL;
    const long delta_limit = 100000;
    const int max_num_elements_in_cache = 8000000;
    const char *filename = argv[1];
    FILE *const fh = fopen(filename, "r");
    if (fh == NULL)
    {
        fc_solve_err("Could not open file '%s' for input.\n", filename);
    }
    const fcs_user_state_str_t user_state = read_state(fh);
    fcs_state_keyval_pair_t init_state_pair;
    fc_solve_initial_user_state_to_c(
        user_state.s, &init_state_pair, FREECELLS_NUM, STACKS_NUM, 1, NULL);

    fcs_dbm_solver_instance_t instance;

    instance_init(
        &instance, local_variant, &init_state_pair, max_num_elements_in_cache);

#define LOG_FILENAME "fc-solve-pseudo-dfs.log.txt"

    {
        FILE *const last_line_fh = popen(("tail -1 " LOG_FILENAME), "r");

        if (last_line_fh)
        {
            long count_num_processed;
            if (fscanf(last_line_fh, "At %ld iterations Coords=[",
                    &count_num_processed) == 1)
            {
                instance__load_coords_from_fh(&instance, last_line_fh);
                /*
                 * instance__inspect_new_state increments count_num_processed
                 * so let's set it after loading the coordinates.
                 * */
                instance.count_num_processed = count_num_processed;
            }
        }
        pclose(last_line_fh);
    }

    instance.max_count_num_processed =
        instance.count_num_processed + delta_limit;

    while (instance.max_count_num_processed % delta_limit != 0)
    {
        instance.max_count_num_processed +=
            delta_limit - (instance.max_count_num_processed % delta_limit);
    }

    while (instance.should_terminate == DONT_TERMINATE)
    {
        instance_run(&instance);

        FILE *const log_fh = fopen(LOG_FILENAME, "at");
        instance__print_coords_to_log(&instance, log_fh);
        fclose(log_fh);

        instance.max_count_num_processed =
            instance.count_num_processed + delta_limit;
    }

    if (instance.should_terminate == SOLUTION_FOUND_TERMINATE)
    {
        printf("%s\n", "Solution was found.");
    }
    else
    {
        printf("%s\n", "I could not solve it.");
    }

    instance_free(&instance);

    return 0;
}
コード例 #7
0
/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_calc_derived_states_wrapper(
    fcs_dbm_variant_type_t local_variant, const char *init_state_str_proto,
    int *const num_out_derived_states,
    fcs_derived_state_debug_t **out_derived_states,
    const fcs_bool_t perform_horne_prune)
{
    fcs_state_keyval_pair_t init_state;
    fcs_encoded_state_buffer_t enc_state;
    fcs_state_locs_struct_t locs;
    fcs_derived_state_t *derived_list = NULL;
    fcs_derived_state_t *derived_list_recycle_bin = NULL;
    fcs_compact_allocator_t allocator;
    fcs_meta_compact_allocator_t meta_alloc;
    size_t states_count = 0;
    fcs_derived_state_t *iter;
    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(init_state_str_proto, &init_state,
        FREECELLS_NUM, STACKS_NUM, DECKS_NUM, indirect_stacks_buffer);

    fc_solve_delta_stater_t delta;
    fc_solve_delta_stater_init(
        &delta, &(init_state.s), STACKS_NUM, FREECELLS_NUM
#ifndef FCS_FREECELL_ONLY
        ,
        FCS_SEQ_BUILT_BY_ALTERNATE_COLOR
#endif
        );

    fcs_init_and_encode_state(&delta, local_variant, &(init_state), &enc_state);

    fc_solve_meta_compact_allocator_init(&meta_alloc);
    fc_solve_compact_allocator_init(&allocator, &meta_alloc);

    instance_solver_thread_calc_derived_states(local_variant, &init_state, NULL,
        &derived_list, &derived_list_recycle_bin, &allocator,
        perform_horne_prune);

    iter = derived_list;

    while (iter)
    {
        states_count++;
        iter = iter->next;
    }

    *(num_out_derived_states) = states_count;

    fcs_derived_state_debug_t *const debug_ret =
        SMALLOC(debug_ret, states_count);
    *(out_derived_states) = debug_ret;

    fc_solve_init_locs(&locs);

    iter = derived_list;
    size_t idx = 0;
    while (iter)
    {
        debug_ret[idx] = (typeof(debug_ret[idx])){
            .state_string = SMALLOC(debug_ret[idx].state_string, 1000),
            .move = iter->move,
            .core_irreversible_moves_count =
                iter->core_irreversible_moves_count,
            .num_non_reversible_moves_including_prune =
                iter->num_non_reversible_moves_including_prune,
            .which_irreversible_moves_bitmask =
                iter->which_irreversible_moves_bitmask};
        FCS__RENDER_STATE(debug_ret[idx].state_string, &(iter->state.s), &locs);
        /* TODO : Put something meaningful there by passing it to the function.
         */
        idx++;
        iter = iter->next;
    }

    assert(idx == states_count);

    fc_solve_compact_allocator_finish(&allocator);
    fc_solve_meta_compact_allocator_finish(&meta_alloc);

    fc_solve_delta_stater_release(&delta);

    return 0;
}

/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_perform_horne_prune(
    fcs_dbm_variant_type_t local_variant, const char *init_state_str_proto,
    char **ret_state_s)
{
    fcs_state_keyval_pair_t init_state;
    fcs_state_locs_struct_t locs;
    int prune_ret;

    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_init_locs(&locs);

    fc_solve_initial_user_state_to_c(init_state_str_proto, &init_state,
        FREECELLS_NUM, STACKS_NUM, DECKS_NUM, indirect_stacks_buffer);

    prune_ret = horne_prune__simple(local_variant, &init_state);
    *ret_state_s = SMALLOC(*ret_state_s, 1000);
    FCS__RENDER_STATE(*ret_state_s, &(init_state.s), &locs);

    return prune_ret;
}
/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_find_fcc_start_points(
        enum fcs_dbm_variant_type_t local_variant,
        const char * init_state_str_proto,
        const int start_state_moves_count,
        const fcs_fcc_move_t * const start_state_moves,
        fcs_FCC_start_point_result_t * * out_fcc_start_points,
        long * out_num_new_positions
        )
{
    fcs_state_keyval_pair_t init_state;
    fc_solve_delta_stater_t * delta;
    fcs_encoded_state_buffer_t enc_state;
    fcs_state_locs_struct_t locs;
    int i;
    fcs_meta_compact_allocator_t meta_alloc;
    fcs_FCC_start_points_list_t start_points_list;
    dict_t * do_next_fcc_start_points_exist;
    dict_t * does_min_by_sorting_exist;
    fcs_lru_cache_t does_state_exist_in_any_FCC_cache;
    const int max_num_elements_in_cache = 1000;
    fcs_bool_t is_min_by_sorting_new;
    fcs_encoded_state_buffer_t min_by_sorting;
    fcs_fcc_moves_seq_allocator_t moves_list_allocator;
    fcs_fcc_moves_seq_t start_state_moves_seq;
    int states_count = 0;
    fcs_FCC_start_point_t * iter;
    fcs_FCC_start_point_result_t * ret;
    add_start_point_context_t add_start_point_context;
    void * tree_recycle_bin = NULL;

    fcs_compact_allocator_t moves_list_compact_alloc;

    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(
            init_state_str_proto,
            &init_state,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            indirect_stacks_buffer
            );

    delta = fc_solve_delta_stater_alloc(
            &(init_state.s),
            STACKS_NUM,
            FREECELLS_NUM
#ifndef FCS_FREECELL_ONLY
            , FCS_SEQ_BUILT_BY_ALTERNATE_COLOR
#endif
            );

    fcs_init_and_encode_state(
        delta,
        local_variant,
        &(init_state),
        &enc_state
    );

    start_points_list.list = NULL;
    start_points_list.recycle_bin = NULL;
    fc_solve_meta_compact_allocator_init( &meta_alloc );
    fc_solve_compact_allocator_init(&(start_points_list.allocator), &meta_alloc);

    do_next_fcc_start_points_exist =
        fc_solve_kaz_tree_create(fc_solve_compare_encoded_states, NULL, &meta_alloc, &tree_recycle_bin);

    does_min_by_sorting_exist =
        fc_solve_kaz_tree_create(fc_solve_compare_encoded_states, NULL, &meta_alloc, &tree_recycle_bin);

    cache_init(&does_state_exist_in_any_FCC_cache, max_num_elements_in_cache, &meta_alloc);

    fc_solve_compact_allocator_init(&(moves_list_compact_alloc), &(meta_alloc));

    moves_list_allocator.recycle_bin = NULL;
    moves_list_allocator.allocator = &(moves_list_compact_alloc);

    start_state_moves_seq.count = start_state_moves_count;
    start_state_moves_seq.moves_list = NULL;
    {
        fcs_fcc_moves_list_item_t * * moves_iter = &(start_state_moves_seq.moves_list);
        for ( i=0 ; i < start_state_moves_count ; )
        {
            if (i % FCS_FCC_NUM_MOVES_IN_ITEM == 0)
            {
                *(moves_iter) = fc_solve_fcc_alloc_moves_list_item(&moves_list_allocator);
            }
            (*moves_iter)->data.s[i % FCS_FCC_NUM_MOVES_IN_ITEM] = start_state_moves[i];
            if ((++i) % FCS_FCC_NUM_MOVES_IN_ITEM == 0)
            {
                moves_iter = &((*moves_iter)->next);
            }
        }
    }

    add_start_point_context.do_next_fcc_start_points_exist = do_next_fcc_start_points_exist;
    add_start_point_context.next_start_points_list = &start_points_list;
    add_start_point_context.moves_list_allocator = &moves_list_allocator;

    perform_FCC_brfs(
        local_variant,
        &(init_state),
        enc_state,
        &start_state_moves_seq,
        fc_solve_add_start_point_in_mem,
        &add_start_point_context,
        &is_min_by_sorting_new,
        &min_by_sorting,
        does_min_by_sorting_exist,
        &does_state_exist_in_any_FCC_cache,
        out_num_new_positions,
        &moves_list_allocator,
        &meta_alloc
    );

    iter = start_points_list.list;

    while (iter)
    {
        states_count++;
        iter = iter->next;
    }

    *out_fcc_start_points = ret = SMALLOC(ret, states_count+1);

    ret[states_count].count = 0;

    fc_solve_init_locs(&locs);

    iter = start_points_list.list;
    for (i = 0; i < states_count ; i++)
    {
        fcs_state_keyval_pair_t state;
        DECLARE_IND_BUF_T(state_indirect_stacks_buffer)

        ret[i].count = iter->moves_seq.count;
        ret[i].moves = SMALLOC(ret[i].moves, ret[i].count);
        {
            int moves_idx;
            fcs_fcc_moves_list_item_t * moves_iter = iter->moves_seq.moves_list;
            for (moves_idx = 0 ; moves_idx < ret[i].count ; )
            {
                ret[i].moves[moves_idx] = moves_iter->data.s[moves_idx % FCS_FCC_NUM_MOVES_IN_ITEM];
                if ((++moves_idx) % FCS_FCC_NUM_MOVES_IN_ITEM == 0)
                {
                    moves_iter = moves_iter->next;
                }
            }
        }
        fc_solve_delta_stater_decode_into_state(delta, iter->enc_state.s, &(state), state_indirect_stacks_buffer);
        ret[i].state_as_string =
        fc_solve_state_as_string(
            &(state.s),
            &locs,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            1,
            0,
            1
            );

        iter = iter->next;
    }

    fc_solve_compact_allocator_finish(&(start_points_list.allocator));
    fc_solve_compact_allocator_finish(&(moves_list_compact_alloc));

    fc_solve_delta_stater_free (delta);
    fc_solve_kaz_tree_destroy(do_next_fcc_start_points_exist);
    fc_solve_kaz_tree_destroy(does_min_by_sorting_exist);
    cache_destroy(&does_state_exist_in_any_FCC_cache);
    fc_solve_meta_compact_allocator_finish( &meta_alloc );

    return 0;
}
DLLEXPORT int fc_solve_user_INTERNAL_is_fcc_new(
        enum fcs_dbm_variant_type_t local_variant,
        const char * init_state_str_proto,
        const char * start_state_str_proto,
        /* NULL-terminated */
        const char * * min_states,
        /* NULL-terminated */
        const char * * states_in_cache,
        fcs_bool_t * const out_is_fcc_new
        )
{
    fcs_state_keyval_pair_t init_state;
    fc_solve_delta_stater_t * delta;
    fcs_encoded_state_buffer_t enc_state;
    fcs_encoded_state_buffer_t start_enc_state;
    fcs_meta_compact_allocator_t meta_alloc;
    fcs_FCC_start_points_list_t start_points_list;
    dict_t * do_next_fcc_start_points_exist;
    dict_t * does_min_by_sorting_exist;
    fcs_compact_allocator_t temp_allocator;
    fcs_fcc_moves_seq_allocator_t moves_list_allocator;
    const int max_num_elements_in_cache = 1000000;
    fcs_lru_cache_t does_state_exist_in_any_FCC_cache;
    fcs_encoded_state_buffer_t min_by_sorting;
    fcs_fcc_moves_seq_t init_moves_seq;
    add_start_point_context_t add_start_point_context;
    void * tree_recycle_bin = NULL;

    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(
            init_state_str_proto,
            &init_state,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            indirect_stacks_buffer
            );

    delta = fc_solve_delta_stater_alloc(
            &(init_state.s),
            STACKS_NUM,
            FREECELLS_NUM
#ifndef FCS_FREECELL_ONLY
            , FCS_SEQ_BUILT_BY_ALTERNATE_COLOR
#endif
            );

    fcs_init_and_encode_state(
        delta,
        local_variant,
        &(init_state),
        &enc_state
    );

    fc_solve_state_string_to_enc(
        local_variant,
        delta,
        start_state_str_proto,
        &(start_enc_state)
    );


    fc_solve_meta_compact_allocator_init( &meta_alloc );

    start_points_list.list = NULL;
    start_points_list.recycle_bin = NULL;
    fc_solve_compact_allocator_init(&(start_points_list.allocator), &meta_alloc);

    do_next_fcc_start_points_exist =
        fc_solve_kaz_tree_create(fc_solve_compare_encoded_states, NULL, &meta_alloc, &tree_recycle_bin);

    does_min_by_sorting_exist =
        fc_solve_kaz_tree_create(fc_solve_compare_encoded_states, NULL, &meta_alloc, &tree_recycle_bin);

    fc_solve_compact_allocator_init(&(temp_allocator), &meta_alloc);

    moves_list_allocator.recycle_bin = NULL;
    moves_list_allocator.allocator = &(temp_allocator);

    /* Populate does_min_by_sorting_exist from min_states */
    {
        const char * * min_states_iter = min_states;

        for (; *(min_states_iter) ; min_states_iter++)
        {
            fcs_encoded_state_buffer_t * min_enc_state;
            min_enc_state = (fcs_encoded_state_buffer_t *)
                fcs_compact_alloc_ptr(
                    &(temp_allocator),
                    sizeof (*min_enc_state)
                    );

            fc_solve_state_string_to_enc(
                local_variant,
                delta,
                *(min_states_iter),
                min_enc_state
            );

            fc_solve_kaz_tree_alloc_insert(
                does_min_by_sorting_exist,
                min_enc_state
            );
        }
    }

    cache_init(&does_state_exist_in_any_FCC_cache, max_num_elements_in_cache, &meta_alloc);

    /* Populate does_state_exist_in_any_FCC_cache from states_in_cache */
    {
        const char * * min_states_iter = states_in_cache;

        for (; *(min_states_iter) ; min_states_iter++)
        {
            fcs_encoded_state_buffer_t * min_enc_state;
            min_enc_state = (fcs_encoded_state_buffer_t *)
                fcs_compact_alloc_ptr(
                    &(temp_allocator),
                    sizeof (*min_enc_state)
                    );

            fc_solve_state_string_to_enc(
                local_variant,
                delta,
                *(min_states_iter),
                min_enc_state
            );

            cache_insert (&does_state_exist_in_any_FCC_cache, min_enc_state, NULL, '\0');
        }
    }

    init_moves_seq.moves_list = NULL;
    init_moves_seq.count = 0;

    add_start_point_context.do_next_fcc_start_points_exist = do_next_fcc_start_points_exist;
    add_start_point_context.next_start_points_list = &start_points_list;
    add_start_point_context.moves_list_allocator = &moves_list_allocator;
    {
        long num_new_positions_temp;
        perform_FCC_brfs(
            local_variant,
            &(init_state),
            start_enc_state,
            &init_moves_seq,
            fc_solve_add_start_point_in_mem,
            &add_start_point_context,
            out_is_fcc_new,
            &min_by_sorting,
            does_min_by_sorting_exist,
            &does_state_exist_in_any_FCC_cache,
            &num_new_positions_temp,
            &moves_list_allocator,
            &meta_alloc
        );
    }

    fc_solve_compact_allocator_finish(&(start_points_list.allocator));
    fc_solve_compact_allocator_finish(&(temp_allocator));

    fc_solve_delta_stater_free (delta);
    fc_solve_kaz_tree_destroy(do_next_fcc_start_points_exist);
    fc_solve_kaz_tree_destroy(does_min_by_sorting_exist);
    cache_destroy(&does_state_exist_in_any_FCC_cache);
    fc_solve_meta_compact_allocator_finish( &meta_alloc );

    return 0;
}