/* * 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; }
/* * 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; }
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; }
static void *instance_run_solver_thread(void *const void_arg) { fcs_dbm_queue_item_t physical_item; fcs_dbm_record_t *token = NULL; fcs_dbm_queue_item_t *item, *prev_item; fcs_derived_state_t *derived_list, *derived_list_recycle_bin, *derived_iter; fcs_compact_allocator_t derived_list_allocator; fcs_state_keyval_pair_t state; char *base64_encoding_buffer = NULL; #if 0 size_t base64_encoding_buffer_max_len = 0; #endif #ifdef DEBUG_OUT fcs_state_locs_struct_t locs; fc_solve_init_locs(&locs); #endif DECLARE_IND_BUF_T(indirect_stacks_buffer) const_AUTO(thread, ((thread_arg_t *)void_arg)->thread); const_SLOT(instance, thread); const_AUTO(delta_stater, &(thread->delta_stater)); const_AUTO(local_variant, instance->common.variant); prev_item = item = NULL; int queue_num_extracted_and_processed = 0; fc_solve_compact_allocator_init( &(derived_list_allocator), &(thread->thread_meta_alloc)); derived_list_recycle_bin = NULL; derived_list = NULL; FILE *const out_fh = instance->common.out_fh; TRACE("%s\n", "instance_run_solver_thread start"); const_AUTO(coll, &(instance->coll)); #if 0 fcs_bool_t was_start_key_reachable = instance->was_start_key_reachable; #endif while (1) { /* First of all extract an item. */ fcs_lock_lock(&instance->global_lock); if (prev_item) { instance->common.queue_num_extracted_and_processed--; } if (instance->common.should_terminate == DONT_TERMINATE) { if (fcs_depth_multi_queue__extract(&(coll->depth_queue), &(thread->state_depth), (fcs_offloading_queue_item_t *)(&token))) { physical_item.key = token->key; item = &physical_item; instance_increment(instance); } else { item = NULL; } queue_num_extracted_and_processed = instance->common.queue_num_extracted_and_processed; } fcs_lock_unlock(&instance->global_lock); if ((instance->common.should_terminate != DONT_TERMINATE) || (!queue_num_extracted_and_processed)) { break; } if (!item) { /* Sleep until more items become available in the * queue. */ usleep(5000); } else { /* Handle item. */ fc_solve_delta_stater_decode_into_state( delta_stater, item->key.s, &state, indirect_stacks_buffer); /* A section for debugging. */ FCS__OUTPUT_STATE(out_fh, "", &(state.s), &locs); #if 0 { FccEntryPointNode key; key.kv.key.key = item->key; fcs_lock_lock(&instance->fcc_entry_points_lock); FccEntryPointNode * val_proto = RB_FIND( FccEntryPointList, &(instance->fcc_entry_points), &(key) ); fcs_bool_t to_prune = FALSE; fcs_bool_t to_output = FALSE; if (val_proto) { val_proto->kv.val.is_reachable = TRUE; const int moves_count = instance->start_key_moves_count + item->moves_seq.count; if (was_start_key_reachable) { if (val_proto->kv.val.depth <= moves_count) { /* We can prune based on here. */ to_prune = TRUE; } else { /* We can set it to the more pessimstic move count * for future trimming. */ to_output = !(val_proto->kv.val.was_consumed); val_proto->kv.val.depth = moves_count; val_proto->kv.val.was_consumed = TRUE; } } else { if (! val_proto->kv.val.was_consumed) { to_output = TRUE; if (val_proto->kv.val.depth >= moves_count) { val_proto->kv.val.depth = moves_count; val_proto->kv.val.was_consumed = TRUE; } } } } fcs_lock_unlock(&instance->fcc_entry_points_lock); if (to_output) { const size_t needed_len = ( (sizeof(key.kv.key.key)+2) << 2 ) / 3 + 20; if (base64_encoding_buffer_max_len < needed_len) { base64_encoding_buffer = SREALLOC(base64_encoding_buffer, needed_len); base64_encoding_buffer_max_len = needed_len; } size_t unused_output_len; base64_encode( (unsigned char *)&(key.kv.key.key), sizeof(key.kv.key.key), base64_encoding_buffer, &unused_output_len ); fcs_lock_lock(&instance->output_lock); fprintf( instance->consumed_states_fh, "%s\n", base64_encoding_buffer ); fflush(instance->consumed_states_fh); fcs_lock_unlock(&instance->output_lock); } if (to_prune) { continue; } } #endif if (instance_solver_thread_calc_derived_states(local_variant, &state, token, &derived_list, &derived_list_recycle_bin, &derived_list_allocator, TRUE)) { fcs_lock_lock(&instance->global_lock); fcs_dbm__found_solution(&(instance->common), token, item); fcs_lock_unlock(&instance->global_lock); break; } /* Encode all the states. */ for (derived_iter = derived_list; derived_iter; derived_iter = derived_iter->next) { fcs_init_and_encode_state(delta_stater, local_variant, &(derived_iter->state), &(derived_iter->key)); } instance_check_multiple_keys(thread, instance, &(coll->cache_store), &(coll->queue_meta_alloc), &derived_list, 1 #ifdef FCS_DBM_CACHE_ONLY , item->moves_to_key #endif ); /* Now recycle the derived_list */ while (derived_list) { #define derived_list_next derived_iter derived_list_next = derived_list->next; derived_list->next = derived_list_recycle_bin; derived_list_recycle_bin = derived_list; derived_list = derived_list_next; #undef derived_list_next } /* End handle item. */ } /* End of main thread loop */ prev_item = item; } free(base64_encoding_buffer); fc_solve_compact_allocator_finish(&(derived_list_allocator)); TRACE("%s\n", "instance_run_solver_thread end"); return NULL; }