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; }
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; }
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; } }
/* * 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; } }
/* * 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 }