Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
static inline void instance__inspect_new_state(
    fcs_dbm_solver_instance_t *const instance, fcs_cache_key_t *const state)
{
    instance->count_num_processed++;

    if (fcs_pdfs_cache_does_key_exist(&(instance->cache), &(state->s)))
    {
        instance->stack_depth--;
        return;
    }
    const fcs_dbm_variant_type_t local_variant = instance->local_variant;
    const int depth = (instance->stack_depth);
    const int max_depth = instance->max_stack_depth;
    if (depth == max_depth)
    {
        instance->stack =
            SREALLOC(instance->stack, ++(instance->max_stack_depth));
        pseduo_dfs_stack_item_t *const stack_item = instance->stack + max_depth;
        stack_item->next_states = NULL;
        stack_item->max_count_next_states = 0;
    }
    pseduo_dfs_stack_item_t *const stack_item = instance->stack + depth;
    stack_item->curr_state = state;

    fcs_derived_state_t *derived_list = NULL, *derived_iter = NULL;

    if (instance_solver_thread_calc_derived_states(instance->local_variant,
            state, NULL, &derived_list, &(instance->derived_list_recycle_bin),
            &(instance->derived_list_allocator), TRUE))
    {
        instance->should_terminate = SOLUTION_FOUND_TERMINATE;
        instance->solution_was_found = TRUE;
        return;
    }

    stack_item->count_next_states = 0;
    stack_item->next_state_idx = 0;
    fcs_kv_state_t kv;
    /* Now recycle the derived_list */
    while (derived_list)
    {
        kv.key = &(derived_list->state.s);
        kv.val = &(derived_list->state.info);
        fc_solve_canonize_state(kv.key, FREECELLS_NUM, STACKS_NUM);

        if (!lookup_state(
                &(instance->store), &(instance->cache), &(derived_list->state)))
        {
            int i = (stack_item->count_next_states)++;
            if (i >= stack_item->max_count_next_states)
            {
                stack_item->next_states = SREALLOC(stack_item->next_states,
                    ++(stack_item->max_count_next_states));
            }
            stack_item->next_states[i] = derived_list->state;
            insert_state(&(instance->store), &(stack_item->next_states[i]));
        }
#define derived_list_next derived_iter
        derived_list_next = derived_list->next;
        derived_list->next = instance->derived_list_recycle_bin;
        instance->derived_list_recycle_bin = derived_list;
        derived_list = derived_list_next;
#undef derived_list_next
    }

    return;
}
Ejemplo n.º 3
0
GCC_INLINE int fc_solve_check_and_add_state(
    fc_solve_soft_thread_t * soft_thread,
    fcs_state_extra_info_t * new_state_val,
    fcs_state_extra_info_t * * existing_state_val
    )
{
#if (FCS_STATE_STORAGE == FCS_STATE_STORAGE_INTERNAL_HASH)
#ifdef FCS_ENABLE_SECONDARY_HASH_VALUE
    SFO_hash_value_t hash_value_int;
#endif
#endif
#if (FCS_STATE_STORAGE == FCS_STATE_STORAGE_INDIRECT)
    fcs_standalone_state_ptrs_t * pos_ptr;
    int found;
#endif
    fc_solve_hard_thread_t * hard_thread = soft_thread->hard_thread;
    fc_solve_instance_t * instance = hard_thread->instance;
    fcs_state_t * new_state_key = new_state_val->key;

    int is_state_new;

    if (check_if_limits_exceeded())
    {
        return FCS_STATE_BEGIN_SUSPEND_PROCESS;
    }

    fc_solve_cache_stacks(hard_thread, new_state_key, new_state_val);

    fc_solve_canonize_state(new_state_val,
            INSTANCE_FREECELLS_NUM,
            INSTANCE_STACKS_NUM
            );

/*
    The objective of this part of the code is:
    1. To check if new_state_key / new_state_val is already in the prev_states
       collection.
    2. If not, to add it and to set check to true.
    3. If so, to set check to false.
  */

#if (FCS_STATE_STORAGE == FCS_STATE_STORAGE_INTERNAL_HASH)
#ifdef FCS_ENABLE_SECONDARY_HASH_VALUE
    {
        const char * s_ptr = (char*)new_state_key;
        const char * s_end = s_ptr+sizeof(*new_state_key);
        hash_value_int = 0;
        while (s_ptr < s_end)
        {
            hash_value_int += (hash_value_int << 5) + *(s_ptr++);
        }
        hash_value_int += (hash_value_int>>5);
    }
    if (hash_value_int < 0)
    {
        /*
         * This is a bit mask that nullifies the sign bit of the
         * number so it will always be positive
         * */
        hash_value_int &= (~(1<<((sizeof(hash_value_int)<<3)-1)));
    }
#endif
    {
        void * existing_key_void, * existing_val_void;
    is_state_new = (fc_solve_hash_insert(
        instance->hash,
        new_state_key,
        new_state_val,
        &existing_key_void,
        &existing_val_void,
        perl_hash_function(
            (ub1 *)new_state_key,
            sizeof(*new_state_key)
            )
#ifdef FCS_ENABLE_SECONDARY_HASH_VALUE
        , hash_value_int
#endif
        ) == 0);
        if (! is_state_new)
        {
            *existing_state_val = existing_val_void;
        }
    }
#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_INDIRECT)
    /* Try to see if the state is found in indirect_prev_states */
    if ((pos_ptr = (fcs_standalone_state_ptrs_t *)bsearch(&new_state_key,
                instance->indirect_prev_states,
                instance->num_indirect_prev_states,
                sizeof(instance->indirect_prev_states[0]),
                fc_solve_state_compare_indirect)) == NULL)
    {
        /* It isn't in prev_states, but maybe it's in the sort margin */
        pos_ptr = (fcs_standalone_state_ptrs_t *)fc_solve_bsearch(
            &new_state_key,
            instance->indirect_prev_states_margin,
            instance->num_prev_states_margin,
            sizeof(instance->indirect_prev_states_margin[0]),
            fc_solve_state_compare_indirect_with_context,
            NULL,
            &found);

        if (found)
        {
            is_state_new = 0;
            *existing_state_val = pos_ptr->val;
        }
        else
        {
            /* Insert the state into its corresponding place in the sort
             * margin */
            memmove((void*)(pos_ptr+1),
                    (void*)pos_ptr,
                    sizeof(*pos_ptr) *
                    (instance->num_prev_states_margin-
                      (pos_ptr-instance->indirect_prev_states_margin)
                    ));
            pos_ptr->key = new_state_key;
            pos_ptr->val = new_state_val;

            instance->num_prev_states_margin++;

            if (instance->num_prev_states_margin >= PREV_STATES_SORT_MARGIN)
            {
                /* The sort margin is full, let's combine it with the main array */

                instance->indirect_prev_states = 
                    realloc(
                        instance->indirect_prev_states,
                        sizeof(instance->indirect_prev_states[0])
                        * (instance->num_indirect_prev_states
                            + instance->num_prev_states_margin
                        )
                    );

                fc_solve_merge_large_and_small_sorted_arrays(
                    instance->indirect_prev_states,
                    instance->num_indirect_prev_states,
                    instance->indirect_prev_states_margin,
                    instance->num_prev_states_margin,
                    sizeof(instance->indirect_prev_states[0]),
                    fc_solve_state_compare_indirect_with_context,
                    NULL
                );

                instance->num_indirect_prev_states += instance->num_prev_states_margin;

                instance->num_prev_states_margin=0;
            }
            is_state_new = 1;
        }

    }
    else
    {
        *existing_state_val = pos_ptr->val;
        is_state_new = 0;
    }

#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_LIBREDBLACK_TREE)
    *existing_state_val = (fcs_state_extra_info_t *)rbsearch(new_state_val,
            instance->tree
            );
    is_state_new = ((*existing_state_val) == new_state_val);

#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_LIBAVL_AVL_TREE) || (FCS_STATE_STORAGE == FCS_STATE_STORAGE_LIBAVL_REDBLACK_TREE)

#if (FCS_STATE_STORAGE == FCS_STATE_STORAGE_LIBAVL_AVL_TREE)
#define fcs_libavl_states_tree_insert(a,b) avl_insert((a),(b))
#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_LIBAVL_REDBLACK_TREE)
#define fcs_libavl_states_tree_insert(a,b) rb_insert((a),(b))
#endif

    *existing_state = fcs_libavl_states_tree_insert(instance->tree, new_state);
    is_state_new = (*existing_state == NULL);

#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_GLIB_TREE)
    *existing_state = g_tree_lookup(instance->tree, (gpointer)new_state);
    if (*existing_state == NULL)
    {
        /* The new state was not found. Let's insert it.
         * The value must be the same as the key, so g_tree_lookup()
         * will return it. */
        g_tree_insert(
            instance->tree,
            (gpointer)new_state,
            (gpointer)new_state
            );
        is_state_new = 1;
    }
    else
    {
        is_state_new = 0;
    }



#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_GLIB_HASH)
    *existing_state = g_hash_table_lookup(instance->hash, (gpointer)new_state);
    if (*existing_state == NULL)
    {
        /* The new state was not found. Let's insert it.
         * The value must be the same as the key, so g_tree_lookup()
         * will return it. */
        g_hash_table_insert(
            instance->hash,
            (gpointer)new_state,
            (gpointer)new_state

            );
        is_state_new = 1;
    }
    else
    {
        is_state_new = 0;
    }

#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_DB_FILE)
    {
        DBT key, value;
        key.data = new_state;
        key.size = sizeof(*new_state);
        if (instance->db->get(
            instance->db,
            NULL,
            &key,
            &value,
            0
            ) == 0)
        {
            /* The new state was not found. Let's insert it.
             * The value must be the same as the key, so g_tree_lookup()
             * will return it. */

            value.data = key.data;
            value.size = key.size;
            instance->db->put(
                instance->db,
                NULL,
                &key,
                &value,
                0);
            is_state_new = 1;
        }
        else
        {
            is_state_new = 0;
            *existing_state = (fcs_state_with_locations_t *)(value.data);
        }
    }
#elif (FCS_STATE_STORAGE == FCS_STATE_STORAGE_JUDY)
    {
        PWord_t * PValue;

        JHSI(PValue, instance->judy_array, new_state_key, sizeof(*new_state_key));

        /* TODO : Handle out-of-memory. */
        if (*PValue == 0)
        {
            /* A new state. */
            is_state_new = 1;
            *PValue = (PWord_t)(*existing_state_val = new_state_val);
        }
        else
        {
            /* Already exists. */
            is_state_new = 0;
            *existing_state_val = (fcs_state_extra_info_t *)(*PValue);
        }
    }
#else
#error no define
#endif
    if (is_state_new)
    {
        /* The new state was not found in the cache, and it was already inserted */
        if (new_state_val->parent_val)
        {
            new_state_val->parent_val->num_active_children++;
        }
        instance->num_states_in_collection++;

        if (new_state_val->moves_to_parent != NULL)
        {
            new_state_val->moves_to_parent =
                fc_solve_move_stack_compact_allocate(
                    hard_thread,
                    new_state_val->moves_to_parent
                    );
        }

        return FCS_STATE_DOES_NOT_EXIST;
    }
    else
    {
        return FCS_STATE_ALREADY_EXISTS;
    }
}
Ejemplo n.º 4
0
/*
 * This function performs a given move on a state
 */
void fc_solve_apply_move(
        fcs_state_extra_info_t * state_val,
        fcs_internal_move_t move,
        int freecells_num,
        int stacks_num,
        int decks_num GCC_UNUSED
        )
{
    fcs_card_t card;
    fcs_cards_column_t col;

    fcs_state_t * state_key = state_val->key;

    switch(fcs_int_move_get_type(move))
    {
        case FCS_MOVE_TYPE_STACK_TO_STACK:
        {
            fcs_cards_column_t dest_col;
            int i;

            col = fcs_state_get_col(*state_key, fcs_int_move_get_src_stack(move));
            dest_col = fcs_state_get_col(*state_key, fcs_int_move_get_dest_stack(move));
            for(i=0 ; i<fcs_int_move_get_num_cards_in_seq(move) ; i++)
            {
                fcs_col_push_col_card(
                    dest_col,
                    col, 
                    fcs_col_len(col) - fcs_int_move_get_num_cards_in_seq(move)+i
                );
            }
            for(i=0 ; i<fcs_int_move_get_num_cards_in_seq(move) ; i++)
            {
                fcs_col_pop_top(col);
            }
        }
        break;
        case FCS_MOVE_TYPE_FREECELL_TO_STACK:
        {
            col = fcs_state_get_col(*state_key, fcs_int_move_get_dest_stack(move));
            fcs_col_push_card(col, fcs_freecell_card(*state_key, fcs_int_move_get_src_freecell(move)));
            fcs_empty_freecell(*state_key, fcs_int_move_get_src_freecell(move));
        }
        break;
        case FCS_MOVE_TYPE_FREECELL_TO_FREECELL:
        {
            card = fcs_freecell_card(*state_key, fcs_int_move_get_src_freecell(move));
            fcs_put_card_in_freecell(*state_key, fcs_int_move_get_dest_freecell(move), card);
            fcs_empty_freecell(*state_key, fcs_int_move_get_src_freecell(move));
        }
        break;

        case FCS_MOVE_TYPE_STACK_TO_FREECELL:
        {
            col = fcs_state_get_col(*state_key, fcs_int_move_get_src_stack(move));
            fcs_col_pop_card(col, card);
            fcs_put_card_in_freecell(*state_key, fcs_int_move_get_dest_freecell(move), card);
        }
        break;

        case FCS_MOVE_TYPE_STACK_TO_FOUNDATION:
        {
            col = fcs_state_get_col(
                *state_key, 
                fcs_int_move_get_src_stack(move)
                );
            fcs_col_pop_top(col);
            fcs_increment_foundation(*state_key, fcs_int_move_get_foundation(move));
        }
        break;

        case FCS_MOVE_TYPE_FREECELL_TO_FOUNDATION:
        {
            fcs_empty_freecell(*state_key, fcs_int_move_get_src_freecell(move));
            fcs_increment_foundation(*state_key, fcs_int_move_get_foundation(move));
        }
        break;

        case FCS_MOVE_TYPE_SEQ_TO_FOUNDATION:
        {
            int i;

            col = fcs_state_get_col(*state_key, fcs_int_move_get_src_stack(move));
            for (i=0 ; i<13 ; i++)
            {
                fcs_col_pop_top(col);
                fcs_increment_foundation(*state_key, fcs_int_move_get_foundation(move));
            }
        }
        break;

#ifndef FCS_WITHOUT_CARD_FLIPPING
        case FCS_MOVE_TYPE_FLIP_CARD:
        {
            col = fcs_state_get_col(*state_key, fcs_int_move_get_src_stack(move));
            fcs_col_flip_card(col, fcs_col_len(col)-1);
        }
        break;
#endif

        case FCS_MOVE_TYPE_CANONIZE:
        {
            fc_solve_canonize_state(
                state_val,
                freecells_num, stacks_num
            );
        }
        break;

    }
}
Ejemplo n.º 5
0
/*
 * This function performs a given move on a state
 */
void fc_solve_apply_move(fcs_state *const ptr_state_key,
    fcs_state_locs_struct *const locs,
    const fcs_internal_move move FREECELLS_AND_STACKS_ARGS())
{
    fcs_cards_column col;
    const stack_i src = fcs_int_move_get_src(move);
    const stack_i dest = fcs_int_move_get_dest(move);

#define state_key (ptr_state_key)
    switch (fcs_int_move_get_type(move))
    {
    case FCS_MOVE_TYPE_STACK_TO_STACK:
    {
        fcs_col_transfer_cards(fcs_state_get_col(*state_key, dest),
            fcs_state_get_col(*state_key, src),
            fcs_int_move_get_num_cards_in_seq(move));
    }
    break;
#if MAX_NUM_FREECELLS > 0
    case FCS_MOVE_TYPE_FREECELL_TO_STACK:
        fcs_state_push(state_key, dest, fcs_freecell_card(*state_key, src));
        fcs_empty_freecell(*state_key, src);
        break;
    case FCS_MOVE_TYPE_FREECELL_TO_FREECELL:
    {
        fcs_card card = fcs_freecell_card(*state_key, src);
        fcs_put_card_in_freecell(*state_key, dest, card);
        fcs_empty_freecell(*state_key, src);
    }
    break;

    case FCS_MOVE_TYPE_STACK_TO_FREECELL:
    {
        col = fcs_state_get_col(*state_key, src);
        fcs_card card;
        fcs_col_pop_card(col, card);
        fcs_put_card_in_freecell(*state_key, dest, card);
    }
    break;
#endif
    case FCS_MOVE_TYPE_STACK_TO_FOUNDATION:
        col = fcs_state_get_col(*state_key, src);
        fcs_col_pop_top(col);
        fcs_increment_foundation(*state_key, dest);
        break;

#if MAX_NUM_FREECELLS > 0
    case FCS_MOVE_TYPE_FREECELL_TO_FOUNDATION:
        fcs_empty_freecell(*state_key, src);
        fcs_increment_foundation(*state_key, dest);
        break;
#endif

#ifndef FCS_FREECELL_ONLY
    case FCS_MOVE_TYPE_SEQ_TO_FOUNDATION:
        col = fcs_state_get_col(*state_key, src);
        for (int i = 0; i < 13; i++)
        {
            fcs_col_pop_top(col);
            fcs_increment_foundation(*state_key, dest);
        }
        break;
#endif

    case FCS_MOVE_TYPE_CANONIZE:
        if (locs)
        {
            fc_solve_canonize_state_with_locs(state_key,
                locs PASS_FREECELLS(freecells_num) PASS_STACKS(stacks_num));
        }
        else
        {
            fc_solve_canonize_state(state_key PASS_FREECELLS(freecells_num)
                    PASS_STACKS(stacks_num));
        }
        break;
    }
#undef state_key
}