static char * get_the_positions_by_rank_data__ss_generator( fc_solve_soft_thread_t * const soft_thread, const fcs_state_t * const the_state ) { fc_solve_instance_t * const instance = HT_INSTANCE(soft_thread->hard_thread); SET_GAME_PARAMS(); #define FCS_SS_POS_BY_RANK_WIDTH (13+1) #define FCS_POS_BY_RANK_LEN ( FCS_SS_POS_BY_RANK_WIDTH * 4 ) #define FCS_POS_BY_RANK_SIZE (sizeof(positions_by_rank[0]) * FCS_POS_BY_RANK_LEN) #define FCS_POS_IDX(rank, suit) ( (suit)*FCS_SS_POS_BY_RANK_WIDTH + (rank) ) pos_by_rank_t * const positions_by_rank = SMALLOC(positions_by_rank, FCS_POS_BY_RANK_LEN); memset(positions_by_rank, -1, FCS_POS_BY_RANK_SIZE); for (int ds = 0 ; ds < LOCAL_STACKS_NUM ; ds++) { const fcs_const_cards_column_t dest_col = fcs_state_get_col(*the_state, ds); const int dest_cards_num = fcs_col_len(dest_col); for (int dc = 0 ; dc < dest_cards_num ; dc++) { const fcs_card_t card = fcs_col_get_card(dest_col, dc); const int suit = fcs_card_suit(card); const int rank = fcs_card_rank(card); const pos_by_rank_t pos = {.col = ds, .height = dc}; positions_by_rank[FCS_POS_IDX(rank, suit)] = pos; } } return (char *)positions_by_rank; }
static void initialize_a_star_rater( fc_solve_soft_thread_t * soft_thread, fcs_state_extra_info_t * ptr_state_val ) { #ifndef HARD_CODED_NUM_STACKS fc_solve_hard_thread_t * hard_thread = soft_thread->hard_thread; fc_solve_instance_t * instance = hard_thread->instance; #endif fcs_state_t * ptr_state_key = ptr_state_val->key; int a, c, cards_num; fcs_card_t this_card, prev_card; double cards_under_sequences; fcs_cards_column_t col; #ifndef FCS_FREECELL_ONLY int sequences_are_built_by = instance->sequences_are_built_by; #endif cards_under_sequences = 0; for(a=0;a<INSTANCE_STACKS_NUM;a++) { col = fcs_state_get_col(*ptr_state_key, a); cards_num = fcs_col_len(col); if (cards_num <= 1) { continue; } c = cards_num-2; this_card = fcs_col_get_card(col, c+1); prev_card = fcs_col_get_card(col, c); while (fcs_is_parent_card(this_card,prev_card) && (c >= 0)) { c--; this_card = prev_card; if (c>=0) { prev_card = fcs_col_get_card(col, c); } } cards_under_sequences += pow(c+1, FCS_A_STAR_CARDS_UNDER_SEQUENCES_EXPONENT); } soft_thread->a_star_initial_cards_under_sequences = cards_under_sequences; }
static GCC_INLINE void initialize_a_star_rater( fc_solve_soft_thread_t * soft_thread, fcs_state_extra_info_t * ptr_state_val ) { #ifndef HARD_CODED_NUM_STACKS fc_solve_hard_thread_t * hard_thread = soft_thread->hard_thread; fc_solve_instance_t * instance = hard_thread->instance; #endif fcs_state_t * ptr_state_key = ptr_state_val->key; int a; double cards_under_sequences; cards_under_sequences = 0; for(a=0;a<INSTANCE_STACKS_NUM;a++) { update_col_cards_under_sequences(soft_thread, fcs_state_get_col(*ptr_state_key, a), &cards_under_sequences); } soft_thread->method_specific.befs.meth.befs.a_star_initial_cards_under_sequences = cards_under_sequences; }
int fc_solve_a_star_or_bfs_do_solve( fc_solve_soft_thread_t * soft_thread ) { fc_solve_hard_thread_t * hard_thread = soft_thread->hard_thread; fc_solve_instance_t * instance = hard_thread->instance; fcs_state_t * ptr_state_key; fcs_state_extra_info_t * ptr_state_val, * ptr_new_state_val; int num_vacant_stacks, num_vacant_freecells; fcs_states_linked_list_item_t * save_item; int a; int check; fcs_derived_states_list_t derived; int derived_index; int method; #ifndef HARD_CODED_NUM_FREECELLS int freecells_num; #endif #ifndef HARD_CODED_NUM_STACKS int stacks_num; #endif int tests_order_num; int * tests_order_tests; int calc_real_depth = instance->calc_real_depth; int soft_thread_id = soft_thread->id; int is_a_complete_scan = soft_thread->is_a_complete_scan; int scans_synergy = instance->scans_synergy; fcs_states_linked_list_item_t * bfs_queue = soft_thread->bfs_queue; PQUEUE * a_star_pqueue = soft_thread->a_star_pqueue; fcs_states_linked_list_item_t * bfs_queue_last_item = soft_thread->bfs_queue_last_item; derived.num_states = 0; derived.states = NULL; tests_order_num = soft_thread->tests_order.num; tests_order_tests = soft_thread->tests_order.tests; ptr_state_val = soft_thread->first_state_to_check_val; method = soft_thread->method; #ifndef HARD_CODED_NUM_FREECELLS freecells_num = instance->freecells_num; #endif #ifndef HARD_CODED_NUM_STACKS stacks_num = instance->stacks_num; #endif /* Continue as long as there are states in the queue or priority queue. */ while ( ptr_state_val != NULL) { TRACE0("Start of loop"); /* * If this is an optimization scan and the state being checked is not * in the original solution path - move on to the next state * */ if ((method == FCS_METHOD_OPTIMIZE) && (!(ptr_state_val->visited & FCS_VISITED_IN_SOLUTION_PATH))) { goto label_next_state; } /* * It the state has already been visited - move on to the next * state. * */ if ((method == FCS_METHOD_OPTIMIZE) ? (ptr_state_val->visited & FCS_VISITED_IN_OPTIMIZED_PATH) : ((ptr_state_val->visited & FCS_VISITED_DEAD_END) || (is_scan_visited(ptr_state_val, soft_thread_id))) ) { goto label_next_state; } TRACE0("Counting cells"); ptr_state_key = ptr_state_val->key; /* Count the free-cells */ num_vacant_freecells = 0; for(a=0;a<LOCAL_FREECELLS_NUM;a++) { if (fcs_freecell_card_num((*ptr_state_key), a) == 0) { num_vacant_freecells++; } } /* Count the number of unoccupied stacks */ num_vacant_stacks = 0; for(a=0;a<LOCAL_STACKS_NUM;a++) { if (fcs_col_len(fcs_state_get_col(the_state, a)) == 0) { num_vacant_stacks++; } } if (check_if_limits_exceeded()) { soft_thread->first_state_to_check_val = ptr_state_val; TRACE0("myreturn - FCS_STATE_SUSPEND_PROCESS"); myreturn(FCS_STATE_SUSPEND_PROCESS); } TRACE0("debug_iter_output"); if (instance->debug_iter_output) { #ifdef DEBUG printf("ST Name: %s\n", soft_thread->name); #endif instance->debug_iter_output_func( (void*)instance->debug_iter_output_context, instance->num_times, ptr_state_val->depth, (void*)instance, ptr_state_val, ((ptr_state_val->parent_val == NULL) ? 0 : ptr_state_val->parent_val->visited_iter ) ); } if ((num_vacant_stacks == LOCAL_STACKS_NUM) && (num_vacant_freecells == LOCAL_FREECELLS_NUM)) { instance->final_state_val = ptr_state_val; myreturn(FCS_STATE_WAS_SOLVED); } calculate_real_depth( ptr_state_val ); soft_thread->num_vacant_freecells = num_vacant_freecells; soft_thread->num_vacant_stacks = num_vacant_stacks; if (soft_thread->a_star_positions_by_rank) { free(soft_thread->a_star_positions_by_rank); soft_thread->a_star_positions_by_rank = NULL; } TRACE0("perform_tests"); /* Do all the tests at one go, because that the way it should be done for BFS and A* */ derived.num_states = 0; for(a=0 ; a < tests_order_num; a++) { check = fc_solve_sfs_tests[tests_order_tests[a] & FCS_TEST_ORDER_NO_FLAGS_MASK] ( soft_thread, ptr_state_val, &derived ); if ((check == FCS_STATE_BEGIN_SUSPEND_PROCESS) || (check == FCS_STATE_EXCEEDS_MAX_NUM_TIMES) || (check == FCS_STATE_SUSPEND_PROCESS)) { /* Save the current position in the scan */ soft_thread->first_state_to_check_val = ptr_state_val; myreturn(FCS_STATE_SUSPEND_PROCESS); } } if (is_a_complete_scan) { ptr_state_val->visited |= FCS_VISITED_ALL_TESTS_DONE; } /* Increase the number of iterations by one . * */ { instance->num_times++; hard_thread->num_times++; } TRACE0("Insert all states"); /* Insert all the derived states into the PQ or Queue */ for(derived_index = 0 ; derived_index < derived.num_states ; derived_index++) { ptr_new_state_val = derived.states[derived_index].state_ptr; if (method == FCS_METHOD_A_STAR) { fc_solve_PQueuePush( a_star_pqueue, ptr_new_state_val, fc_solve_a_star_rate_state(soft_thread, ptr_new_state_val ) ); } else { fc_solve_bfs_enqueue_state( soft_thread, ptr_new_state_val ); } } if (method == FCS_METHOD_OPTIMIZE) { ptr_state_val->visited |= FCS_VISITED_IN_OPTIMIZED_PATH; } else { set_scan_visited( ptr_state_val, soft_thread_id ); if (derived.num_states == 0) { if (is_a_complete_scan) { mark_as_dead_end( ptr_state_val ); } } } ptr_state_val->visited_iter = instance->num_times-1; label_next_state: TRACE0("Label next state"); /* Extract the next item in the queue/priority queue. */ if ((method == FCS_METHOD_BFS) || (method == FCS_METHOD_OPTIMIZE)) { save_item = bfs_queue->next; if (save_item != bfs_queue_last_item) { ptr_state_val = save_item->s; bfs_queue->next = save_item->next; free(save_item); } else { ptr_state_val = NULL; } } else { /* It is an A* scan */ fc_solve_PQueuePop(a_star_pqueue, &ptr_state_val ); } } myreturn(FCS_STATE_IS_NOT_SOLVEABLE); }
static pq_rating_t fc_solve_a_star_rate_state( fc_solve_soft_thread_t * soft_thread, fcs_state_extra_info_t * ptr_state_val ) { fc_solve_hard_thread_t * hard_thread = soft_thread->hard_thread; fc_solve_instance_t * instance = hard_thread->instance; fcs_state_t * ptr_state_key = ptr_state_val->key; double ret=0; int a, c, cards_num, num_cards_in_founds; int num_vacant_stacks, num_vacant_freecells; fcs_card_t this_card, prev_card; double cards_under_sequences, temp; double seqs_over_renegade_cards; fcs_cards_column_t col; #ifndef FCS_FREECELL_ONLY int sequences_are_built_by = instance->sequences_are_built_by; #endif #ifndef HARD_CODED_NUM_FREECELLS int freecells_num = instance->freecells_num; #endif #ifndef HARD_CODED_NUM_STACKS int stacks_num = instance->stacks_num; #endif double * a_star_weights = soft_thread->a_star_weights; #ifndef FCS_FREECELL_ONLY int unlimited_sequence_move = instance->unlimited_sequence_move; #else #define unlimited_sequence_move 0 #endif #ifndef HARD_CODED_NUM_DECKS int decks_num = instance->decks_num; #endif cards_under_sequences = 0; num_vacant_stacks = 0; seqs_over_renegade_cards = 0; for(a=0;a<LOCAL_STACKS_NUM;a++) { col = fcs_state_get_col(*(ptr_state_key), a); cards_num = fcs_col_len(col); if (cards_num == 0) { num_vacant_stacks++; } if (cards_num <= 1) { continue; } c = cards_num-2; this_card = fcs_col_get_card(col, c+1); prev_card = fcs_col_get_card(col, c); while ((c >= 0) && fcs_is_parent_card(this_card,prev_card)) { c--; this_card = prev_card; if (c>=0) { prev_card = fcs_col_get_card(col, c); } } cards_under_sequences += pow(c+1, FCS_A_STAR_CARDS_UNDER_SEQUENCES_EXPONENT); if (c >= 0) { seqs_over_renegade_cards += ((unlimited_sequence_move) ? 1 : pow(cards_num-c-1, FCS_A_STAR_SEQS_OVER_RENEGADE_CARDS_EXPONENT) ); } } ret += ((soft_thread->a_star_initial_cards_under_sequences - cards_under_sequences) / soft_thread->a_star_initial_cards_under_sequences) * a_star_weights[FCS_A_STAR_WEIGHT_CARDS_UNDER_SEQUENCES]; ret += (seqs_over_renegade_cards / pow(LOCAL_DECKS_NUM*52, FCS_A_STAR_SEQS_OVER_RENEGADE_CARDS_EXPONENT) ) * a_star_weights[FCS_A_STAR_WEIGHT_SEQS_OVER_RENEGADE_CARDS]; num_cards_in_founds = 0; for(a=0;a<(LOCAL_DECKS_NUM<<2);a++) { num_cards_in_founds += fcs_foundation_value((*ptr_state_key), a); } ret += ((double)num_cards_in_founds/(LOCAL_DECKS_NUM*52)) * a_star_weights[FCS_A_STAR_WEIGHT_CARDS_OUT]; num_vacant_freecells = 0; for(a=0;a<LOCAL_FREECELLS_NUM;a++) { if (fcs_freecell_card_num((*ptr_state_key),a) == 0) { num_vacant_freecells++; } } if (instance->empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) { if (unlimited_sequence_move) { temp = (((double)num_vacant_freecells+num_vacant_stacks)/(LOCAL_FREECELLS_NUM+INSTANCE_STACKS_NUM)); } else { temp = (((double)((num_vacant_freecells+1)<<num_vacant_stacks)) / ((LOCAL_FREECELLS_NUM+1)<<(INSTANCE_STACKS_NUM))); } } else { if (unlimited_sequence_move) { temp = (((double)num_vacant_freecells)/LOCAL_FREECELLS_NUM); } else { temp = 0; } } ret += (temp * a_star_weights[FCS_A_STAR_WEIGHT_MAX_SEQUENCE_MOVE]); if (ptr_state_val->depth <= 20000) { ret += ((20000 - ptr_state_val->depth)/20000.0) * a_star_weights[FCS_A_STAR_WEIGHT_DEPTH]; } TRACE0("Before return"); return (int)(ret*INT_MAX); }
int fc_solve_soft_dfs_do_solve( fc_solve_soft_thread_t * soft_thread, int to_randomize ) { fc_solve_hard_thread_t * hard_thread = soft_thread->hard_thread; fc_solve_instance_t * instance = hard_thread->instance; fcs_state_t * ptr_state_key; fcs_state_extra_info_t * ptr_state_val; int check; int do_first_iteration; fcs_soft_dfs_stack_item_t * the_soft_dfs_info; #ifndef HARD_CODED_NUM_FREECELLS int freecells_num; #endif #ifndef HARD_CODED_NUM_STACKS int stacks_num; #endif int dfs_max_depth; int tests_order_num = soft_thread->tests_order.num; int * tests_order_tests = soft_thread->tests_order.tests; int calc_real_depth = instance->calc_real_depth; int is_a_complete_scan = soft_thread->is_a_complete_scan; int soft_thread_id = soft_thread->id; fcs_derived_states_list_t * derived_states_list; int scans_synergy; #ifndef HARD_CODED_NUM_FREECELLS freecells_num = instance->freecells_num; #endif #ifndef HARD_CODED_NUM_STACKS stacks_num = instance->stacks_num; #endif scans_synergy = instance->scans_synergy; the_soft_dfs_info = &(soft_thread->soft_dfs_info[soft_thread->depth]); dfs_max_depth = soft_thread->dfs_max_depth; ptr_state_val = the_soft_dfs_info->state_val; derived_states_list = &(the_soft_dfs_info->derived_states_list); calculate_real_depth( ptr_state_val ); TRACE0("Before depth loop"); /* The main loop. */ while (soft_thread->depth >= 0) { /* Increase the "maximal" depth if it is about to be exceeded. */ if (soft_thread->depth+1 >= dfs_max_depth) { fc_solve_increase_dfs_max_depth(soft_thread); /* Because the address of soft_thread->soft_dfs_info may * be changed * */ the_soft_dfs_info = &(soft_thread->soft_dfs_info[soft_thread->depth]); dfs_max_depth = soft_thread->dfs_max_depth; /* This too has to be re-synced */ derived_states_list = &(the_soft_dfs_info->derived_states_list); } TRACE0("Before current_state_index check"); /* All the resultant states in the last test conducted were covered */ if (the_soft_dfs_info->current_state_index == derived_states_list->num_states ) { if (the_soft_dfs_info->test_index >= tests_order_num) { /* Backtrack to the previous depth. */ if (is_a_complete_scan) { ptr_state_val->visited |= FCS_VISITED_ALL_TESTS_DONE; mark_as_dead_end( ptr_state_val ); } free(the_soft_dfs_info->positions_by_rank); if (--soft_thread->depth < 0) { break; } else { the_soft_dfs_info--; derived_states_list = &(the_soft_dfs_info->derived_states_list); ptr_state_val = the_soft_dfs_info->state_val; ptr_state_key = ptr_state_val->key; soft_thread->num_vacant_freecells = the_soft_dfs_info->num_vacant_freecells; soft_thread->num_vacant_stacks = the_soft_dfs_info->num_vacant_stacks; } continue; /* Just to make sure depth is not -1 now */ } derived_states_list->num_states = 0; TRACE0("Before iter_handler"); /* If this is the first test, then count the number of unoccupied freeceels and stacks and check if we are done. */ if (the_soft_dfs_info->test_index == 0) { int num_vacant_stacks, num_vacant_freecells; int i; TRACE0("In iter_handler"); if (instance->debug_iter_output) { #ifdef DEBUG printf("ST Name: %s\n", soft_thread->name); #endif instance->debug_iter_output_func( (void*)instance->debug_iter_output_context, instance->num_times, soft_thread->depth, (void*)instance, ptr_state_val, ((soft_thread->depth == 0) ? 0 : soft_thread->soft_dfs_info[soft_thread->depth-1].state_val->visited_iter ) ); } ptr_state_key = ptr_state_val->key; /* Count the free-cells */ num_vacant_freecells = 0; for(i=0;i<LOCAL_FREECELLS_NUM;i++) { if (fcs_freecell_card_num(the_state, i) == 0) { num_vacant_freecells++; } } /* Count the number of unoccupied stacks */ num_vacant_stacks = 0; for(i=0;i<LOCAL_STACKS_NUM;i++) { if (fcs_col_len(fcs_state_get_col(the_state, i)) == 0) { num_vacant_stacks++; } } /* Check if we have reached the empty state */ if ((num_vacant_stacks == LOCAL_STACKS_NUM) && (num_vacant_freecells == LOCAL_FREECELLS_NUM)) { instance->final_state_val = ptr_state_val; TRACE0("Returning FCS_STATE_WAS_SOLVED"); myreturn(FCS_STATE_WAS_SOLVED); } /* Cache num_vacant_freecells and num_vacant_stacks in their appropriate stacks, so they won't be calculated over and over again. */ soft_thread->num_vacant_freecells = the_soft_dfs_info->num_vacant_freecells = num_vacant_freecells; soft_thread->num_vacant_stacks = the_soft_dfs_info->num_vacant_stacks = num_vacant_stacks; } TRACE0("After iter_handler"); /* Always do the first test */ do_first_iteration = 1; while ( /* Make sure we do not exceed the number of tests */ (the_soft_dfs_info->test_index < tests_order_num) && ( /* Always do the first test */ do_first_iteration || ( /* This is a randomized scan. Else - quit after the first iteration */ to_randomize && /* We are still on a random group */ (tests_order_tests[ the_soft_dfs_info->test_index ] & FCS_TEST_ORDER_FLAG_RANDOM) && /* A new random group did not start */ (! (tests_order_tests[ the_soft_dfs_info->test_index ] & FCS_TEST_ORDER_FLAG_START_RANDOM_GROUP)) ) ) ) { do_first_iteration = 0; check = fc_solve_sfs_tests[tests_order_tests[ the_soft_dfs_info->test_index ] & FCS_TEST_ORDER_NO_FLAGS_MASK] ( soft_thread, ptr_state_val, derived_states_list ); if ((check == FCS_STATE_BEGIN_SUSPEND_PROCESS) || (check == FCS_STATE_EXCEEDS_MAX_NUM_TIMES) || (check == FCS_STATE_SUSPEND_PROCESS)) { /* Have this test be re-performed */ derived_states_list->num_states = 0; the_soft_dfs_info->current_state_index = 0; TRACE0("Returning FCS_STATE_SUSPEND_PROCESS (after sfs_tests)"); myreturn(FCS_STATE_SUSPEND_PROCESS); } /* Move the counter to the next test */ the_soft_dfs_info->test_index++; } { int a, j; int swap_save; int * rand_array, * ra_ptr; int num_states = derived_states_list->num_states; if (num_states > the_soft_dfs_info->derived_states_random_indexes_max_size) { the_soft_dfs_info->derived_states_random_indexes_max_size = num_states; the_soft_dfs_info->derived_states_random_indexes = realloc( the_soft_dfs_info->derived_states_random_indexes, sizeof(the_soft_dfs_info->derived_states_random_indexes[0]) * the_soft_dfs_info->derived_states_random_indexes_max_size ); } rand_array = the_soft_dfs_info->derived_states_random_indexes; for(a=0, ra_ptr = rand_array; a < num_states ; a++) { *(ra_ptr++) = a; } /* If we just conducted the tests for a random group - * randomize. Else - keep those indexes as the unity vector. * * Also, do not randomize if this is a pure soft-DFS scan. * */ if (to_randomize && tests_order_tests[ the_soft_dfs_info->test_index-1 ] & FCS_TEST_ORDER_FLAG_RANDOM) { a = num_states-1; while (a > 0) { j = ( fc_solve_rand_get_random_number( soft_thread->rand_gen ) % (a+1) ); swap_save = rand_array[a]; rand_array[a] = rand_array[j]; rand_array[j] = swap_save; a--; } } } /* We just performed a test, so the index of the first state that ought to be checked in this depth is 0. */ the_soft_dfs_info->current_state_index = 0; } { int num_states = derived_states_list->num_states; fcs_derived_states_list_item_t * derived_states = derived_states_list->states; int * rand_array = the_soft_dfs_info->derived_states_random_indexes; fcs_state_extra_info_t * single_derived_state; while (the_soft_dfs_info->current_state_index < num_states) { single_derived_state = derived_states[ rand_array[ the_soft_dfs_info->current_state_index++ ] ].state_ptr; if ( (! (single_derived_state->visited & FCS_VISITED_DEAD_END) ) && (! is_scan_visited( single_derived_state, soft_thread_id) ) ) { instance->num_times++; hard_thread->num_times++; set_scan_visited( single_derived_state, soft_thread_id ); single_derived_state->visited_iter = instance->num_times; /* I'm using current_state_indexes[depth]-1 because we already increased it by one, so now it refers to the next state. */ soft_thread->depth++; the_soft_dfs_info++; the_soft_dfs_info->state_val = ptr_state_val = single_derived_state; the_soft_dfs_info->test_index = 0; the_soft_dfs_info->current_state_index = 0; the_soft_dfs_info->positions_by_rank = NULL; derived_states_list = &(the_soft_dfs_info->derived_states_list); derived_states_list->num_states = 0; calculate_real_depth( ptr_state_val ); if (check_if_limits_exceeded()) { TRACE0("Returning FCS_STATE_SUSPEND_PROCESS (inside current_state_index)"); myreturn(FCS_STATE_SUSPEND_PROCESS); } break; } } } } /* * We need to bump the number of iterations so it will be ready with * a fresh iterations number for the next scan that takes place. * */ instance->num_times++; hard_thread->num_times++; soft_thread->depth = -1; return FCS_STATE_IS_NOT_SOLVEABLE; }
/* * Calculate, cache and return the positions_by_rank meta-data * about the currently-evaluated state. */ extern char * fc_solve_get_the_positions_by_rank_data( fc_solve_soft_thread_t * soft_thread, fcs_state_extra_info_t * ptr_state_val ) { char * * positions_by_rank_location; switch(soft_thread->method) { case FCS_METHOD_SOFT_DFS: case FCS_METHOD_RANDOM_DFS: { positions_by_rank_location = &( soft_thread->soft_dfs_info[ soft_thread->depth ].positions_by_rank ); } break; default: { positions_by_rank_location = &( soft_thread->a_star_positions_by_rank ); } break; } if (! *positions_by_rank_location) { char * positions_by_rank; #if (!(defined(HARD_CODED_NUM_FREECELLS) && defined(HARD_CODED_NUM_STACKS) && defined(HARD_CODED_NUM_DECKS))) fc_solve_instance_t * instance; #endif fcs_state_t * ptr_state_key; #ifndef HARD_CODED_NUM_DECKS int decks_num; #endif #ifndef HARD_CODED_NUM_STACKS int stacks_num; #endif #ifndef FCS_FREECELL_ONLY int sequences_are_built_by; #endif ptr_state_key = ptr_state_val->key; #if (!(defined(HARD_CODED_NUM_FREECELLS) && defined(HARD_CODED_NUM_STACKS) && defined(HARD_CODED_NUM_DECKS))) instance = soft_thread->hard_thread->instance; #endif #ifndef HARD_CODED_NUM_DECKS decks_num = instance->decks_num; #endif #ifndef HARD_CODED_NUM_STACKS stacks_num = instance->stacks_num; #endif #ifndef FCS_FREECELL_ONLY sequences_are_built_by = instance->sequences_are_built_by; #endif /* We don't keep track of kings (rank == 13). */ #define NUM_POS_BY_RANK_SLOTS 13 /* We need 2 chars per card - one for the column_idx and one * for the card_idx. * * We also need it times 13 for each of the ranks. * * We need (4*LOCAL_DECKS_NUM+1) slots to hold the cards plus a * (-1,-1) (= end) padding. * */ #define FCS_POS_BY_RANK_SIZE (sizeof(positions_by_rank[0]) * NUM_POS_BY_RANK_SLOTS * FCS_POS_BY_RANK_WIDTH) positions_by_rank = malloc(FCS_POS_BY_RANK_SIZE); memset(positions_by_rank, -1, FCS_POS_BY_RANK_SIZE); { char * positions_by_rank_slots[NUM_POS_BY_RANK_SLOTS]; { int c; /* Initialize the pointers to the first available slots */ for ( c=0 ; c < NUM_POS_BY_RANK_SLOTS ; c++ ) { positions_by_rank_slots[c] = &positions_by_rank[ (((LOCAL_DECKS_NUM << 2)+1) << 1) * c ]; } } /* Populate positions_by_rank by looping over the stacks and * indices looking for the cards and filling them. */ { int ds; for(ds=0;ds<LOCAL_STACKS_NUM;ds++) { fcs_cards_column_t dest_col; int top_card_idx; fcs_card_t dest_card; dest_col = fcs_state_get_col(*(ptr_state_key), ds); top_card_idx = fcs_col_len(dest_col); if ((top_card_idx--) == 0) { continue; } { fcs_card_t dest_below_card; int dc; for ( dc=0, dest_card = fcs_col_get_card(dest_col, 0) ; dc < top_card_idx ; dc++, dest_card = dest_below_card ) { dest_below_card = fcs_col_get_card(dest_col, dc+1); if (!fcs_is_parent_card(dest_below_card, dest_card)) { *(positions_by_rank_slots[fcs_card_card_num(dest_card)-1]++) = (char)ds; *(positions_by_rank_slots[fcs_card_card_num(dest_card)-1]++) = (char)dc; } } } *(positions_by_rank_slots[fcs_card_card_num(dest_card)-1]++) = (char)ds; *(positions_by_rank_slots[fcs_card_card_num(dest_card)-1]++) = (char)top_card_idx; } } } *positions_by_rank_location = positions_by_rank; } return *positions_by_rank_location; }
/* * 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; } }
char * fc_solve_move_to_string_w_state( fcs_state_extra_info_t * state_val, int freecells_num GCC_UNUSED, int stacks_num GCC_UNUSED, int decks_num GCC_UNUSED, fcs_move_t move, int standard_notation ) { char string[256]; fcs_state_t * state_key = state_val->key; switch(fcs_move_get_type(move)) { case FCS_MOVE_TYPE_STACK_TO_STACK: if ((standard_notation == STANDARD_NOTATION_EXTENDED) && /* More than one card was moved */ (fcs_move_get_num_cards_in_seq(move) > 1) && /* It was a move to an empty stack */ (fcs_col_len(fcs_state_get_col(*state_key, fcs_move_get_dest_stack(move))) == fcs_move_get_num_cards_in_seq(move)) ) { sprintf(string, "%i%iv%x", 1+fcs_move_get_src_stack(move), 1+fcs_move_get_dest_stack(move), fcs_move_get_num_cards_in_seq(move) ); } else if (standard_notation) { sprintf(string, "%i%i", 1+fcs_move_get_src_stack(move), 1+fcs_move_get_dest_stack(move) ); } else { sprintf(string, "Move %i cards from stack %i to stack %i", fcs_move_get_num_cards_in_seq(move), fcs_move_get_src_stack(move), fcs_move_get_dest_stack(move) ); } break; case FCS_MOVE_TYPE_FREECELL_TO_STACK: if (standard_notation) { sprintf(string, "%c%i", ('a'+convert_freecell_num(fcs_move_get_src_freecell(move))), 1+fcs_move_get_dest_stack(move) ); } else { sprintf(string, "Move a card from freecell %i to stack %i", fcs_move_get_src_freecell(move), fcs_move_get_dest_stack(move) ); } break; case FCS_MOVE_TYPE_FREECELL_TO_FREECELL: if (standard_notation) { register char src_c = (char)('a'+(char)convert_freecell_num(fcs_move_get_src_freecell(move))); register char dest_c = (char)('a'+(char)convert_freecell_num(fcs_move_get_dest_freecell(move))); sprintf(string, "%c%c", src_c, dest_c); } else { sprintf(string, "Move a card from freecell %i to freecell %i", fcs_move_get_src_freecell(move), fcs_move_get_dest_freecell(move) ); } break; case FCS_MOVE_TYPE_STACK_TO_FREECELL: if (standard_notation) { sprintf(string, "%i%c", 1+fcs_move_get_src_stack(move), ('a'+convert_freecell_num(fcs_move_get_dest_freecell(move))) ); } else { sprintf(string, "Move a card from stack %i to freecell %i", fcs_move_get_src_stack(move), fcs_move_get_dest_freecell(move) ); } break; case FCS_MOVE_TYPE_STACK_TO_FOUNDATION: if (standard_notation) { sprintf(string, "%ih", 1+fcs_move_get_src_stack(move)); } else { sprintf(string, "Move a card from stack %i to the foundations", fcs_move_get_src_stack(move) ); } break; case FCS_MOVE_TYPE_FREECELL_TO_FOUNDATION: if (standard_notation) { sprintf(string, "%ch", ('a'+convert_freecell_num(fcs_move_get_src_freecell(move)))); } else { sprintf(string, "Move a card from freecell %i to the foundations", fcs_move_get_src_freecell(move) ); } break; case FCS_MOVE_TYPE_SEQ_TO_FOUNDATION: if (standard_notation) { sprintf(string, "%ih", fcs_move_get_src_stack(move)); } else { sprintf(string, "Move the sequence on top of Stack %i to the foundations", fcs_move_get_src_stack(move) ); } break; default: string[0] = '\0'; break; } return strdup(string); }
static void GCC_INLINE fc_solve_cache_stacks( fc_solve_hard_thread_t * hard_thread, fcs_state_t * new_state_key, fcs_state_extra_info_t * new_state_val ) { int a; #if (FCS_STACK_STORAGE == FCS_STACK_STORAGE_INTERNAL_HASH) #ifdef FCS_ENABLE_SECONDARY_HASH_VALUE SFO_hash_value_t hash_value_int; #endif #elif (FCS_STACK_STORAGE == FCS_STACK_STORAGE_JUDY) PWord_t * PValue; #endif void * cached_stack; char * new_ptr; fc_solve_instance_t * instance = hard_thread->instance; #ifndef HARD_CODED_NUM_STACKS int stacks_num = instance->stacks_num; #endif fcs_cards_column_t column; register int col_len; for(a=0 ; a < LOCAL_STACKS_NUM ; a++) { /* * If the stack is not a copy - it is already cached so skip * to the next stack * */ if (! (new_state_val->stacks_copy_on_write_flags & (1 << a))) { continue; } /* new_state_key->stacks[a] = realloc(new_state_key->stacks[a], fcs_stack_len(new_state_key, a)+1); */ column = fcs_state_get_col(*new_state_key, a); col_len = (fcs_col_len(column)+1); fcs_compact_alloc_typed_ptr_into_var(new_ptr, char, hard_thread->stacks_allocator, col_len); memcpy(new_ptr, column, col_len); new_state_key->stacks[a] = new_ptr; #if FCS_STACK_STORAGE == FCS_STACK_STORAGE_INTERNAL_HASH #ifdef FCS_ENABLE_SECONDARY_HASH_VALUE /* Calculate the hash value for the stack */ /* This hash function was ripped from the Perl source code. * (It is not derived work however). */ { const char * s_ptr = (char*)(new_state_key->stacks[a]); const char * s_end = s_ptr+fcs_stack_len(*new_state_key, a)+1; 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 * dummy; int verdict; column = fcs_state_get_col(*new_state_key, a); verdict = fc_solve_hash_insert( instance->stacks_hash, column, column, &cached_stack, &dummy, perl_hash_function( (ub1 *)new_state_key->stacks[a], col_len ) #ifdef FCS_ENABLE_SECONDARY_HASH_VALUE , hash_value_int #endif ); replace_with_cached(verdict); } #elif (FCS_STACK_STORAGE == FCS_STACK_STORAGE_LIBAVL_AVL_TREE) || (FCS_STACK_STORAGE == FCS_STACK_STORAGE_LIBAVL_REDBLACK_TREE) #if (FCS_STACK_STORAGE == FCS_STACK_STORAGE_LIBAVL_AVL_TREE) #define LIBAVL_INSERT(x,y) avl_insert(x,y) #elif (FCS_STACK_STORAGE == FCS_STACK_STORAGE_LIBAVL_REDBLACK_TREE) #define LIBAVL_INSERT(x,y) rb_insert(x,y) #else #error unknown FCS_STACK_STORAGE #endif cached_stack = LIBAVL_INSERT( instance->stacks_tree, new_state_key->stacks[a] ); #undef LIBAVL_INSERT replace_with_cached(cached_stack != NULL); #elif (FCS_STACK_STORAGE == FCS_STACK_STORAGE_LIBREDBLACK_TREE) cached_stack = (void *)rbsearch( new_state_key->stacks[a], instance->stacks_tree ); replace_with_cached(cached_stack != new_state_key->stacks[a]); #elif (FCS_STACK_STORAGE == FCS_STACK_STORAGE_GLIB_TREE) cached_stack = g_tree_lookup( instance->stacks_tree, (gpointer)new_state_key->stacks[a] ); /* replace_with_cached contains an if statement */ replace_with_cached(cached_stack != NULL) else { g_tree_insert( instance->stacks_tree, (gpointer)new_state_key->stacks[a], (gpointer)new_state_key->stacks[a] ); } #elif (FCS_STACK_STORAGE == FCS_STACK_STORAGE_GLIB_HASH) cached_stack = g_hash_table_lookup( instance->stacks_hash, (gconstpointer)new_state_key->stacks[a] ); replace_with_cached(cached_stack != NULL) else { g_hash_table_insert( instance->stacks_hash, (gpointer)new_state_key->stacks[a], (gpointer)new_state_key->stacks[a] ); } #elif (FCS_STACK_STORAGE == FCS_STACK_STORAGE_JUDY) JHSI( PValue, instance->stacks_judy_array, new_state_key->stacks[a], (fcs_stack_len(*new_state_key, a)+1) ); /* TODO : Handle out-of-memory. */ if (*PValue == 0) { /* A new stack */ *PValue = (PWord_t)new_state_key->stacks[a]; } else { cached_stack = (void *)(*PValue); replace_with_cached(1); } #else #error FCS_STACK_STORAGE is not set to a good value. #endif } }
static GCC_INLINE pq_rating_t fc_solve_a_star_rate_state( fc_solve_soft_thread_t * soft_thread, fcs_state_extra_info_t * ptr_state_val ) { #ifndef FCS_FREECELL_ONLY fc_solve_hard_thread_t * hard_thread = soft_thread->hard_thread; fc_solve_instance_t * instance = hard_thread->instance; #endif fcs_state_t * ptr_state_key = ptr_state_val->key; double ret=0; int a, c, cards_num, num_cards_in_founds; int num_vacant_stacks, num_vacant_freecells; double cards_under_sequences, temp; double seqs_over_renegade_cards; fcs_cards_column_t col; #ifndef HARD_CODED_NUM_FREECELLS int freecells_num = INSTANCE_FREECELLS_NUM; #endif #ifndef HARD_CODED_NUM_STACKS int stacks_num = INSTANCE_STACKS_NUM; #endif #define my_a_star_weights soft_thread->method_specific.befs.meth.befs.a_star_weights double * a_star_weights = my_a_star_weights; #ifndef FCS_FREECELL_ONLY int unlimited_sequence_move = INSTANCE_UNLIMITED_SEQUENCE_MOVE; #else #define unlimited_sequence_move 0 #endif #ifndef HARD_CODED_NUM_DECKS int decks_num = INSTANCE_DECKS_NUM; #endif cards_under_sequences = 0; num_vacant_stacks = 0; seqs_over_renegade_cards = 0; for(a=0;a<LOCAL_STACKS_NUM;a++) { col = fcs_state_get_col(*(ptr_state_key), a); cards_num = fcs_col_len(col); if (cards_num == 0) { num_vacant_stacks++; } if (cards_num <= 1) { continue; } c = update_col_cards_under_sequences(soft_thread, col, &cards_under_sequences); if (c >= 0) { seqs_over_renegade_cards += ((unlimited_sequence_move) ? 1 : FCS_SEQS_OVER_RENEGADE_POWER(cards_num-c-1) ); } } ret += ((soft_thread->method_specific.befs.meth.befs.a_star_initial_cards_under_sequences - cards_under_sequences) / soft_thread->method_specific.befs.meth.befs.a_star_initial_cards_under_sequences) * a_star_weights[FCS_A_STAR_WEIGHT_CARDS_UNDER_SEQUENCES]; ret += (seqs_over_renegade_cards / FCS_SEQS_OVER_RENEGADE_POWER(LOCAL_DECKS_NUM*(13*4)) ) * a_star_weights[FCS_A_STAR_WEIGHT_SEQS_OVER_RENEGADE_CARDS]; num_cards_in_founds = 0; for(a=0;a<(LOCAL_DECKS_NUM<<2);a++) { num_cards_in_founds += fcs_foundation_value((*ptr_state_key), a); } ret += ((double)num_cards_in_founds/(LOCAL_DECKS_NUM*52)) * a_star_weights[FCS_A_STAR_WEIGHT_CARDS_OUT]; num_vacant_freecells = 0; for(a=0;a<LOCAL_FREECELLS_NUM;a++) { if (fcs_freecell_card_num((*ptr_state_key),a) == 0) { num_vacant_freecells++; } } #ifdef FCS_FREECELL_ONLY #define is_filled_by_any_card() 1 #else #define is_filled_by_any_card() (INSTANCE_EMPTY_STACKS_FILL == FCS_ES_FILLED_BY_ANY_CARD) #endif if (is_filled_by_any_card()) { if (unlimited_sequence_move) { temp = (((double)num_vacant_freecells+num_vacant_stacks)/(LOCAL_FREECELLS_NUM+INSTANCE_STACKS_NUM)); } else { temp = (((double)((num_vacant_freecells+1)<<num_vacant_stacks)) / ((LOCAL_FREECELLS_NUM+1)<<(INSTANCE_STACKS_NUM))); } } else { if (unlimited_sequence_move) { temp = (((double)num_vacant_freecells)/LOCAL_FREECELLS_NUM); } else { temp = 0; } } ret += (temp * a_star_weights[FCS_A_STAR_WEIGHT_MAX_SEQUENCE_MOVE]); if (ptr_state_val->depth <= 20000) { ret += ((20000 - ptr_state_val->depth)/20000.0) * a_star_weights[FCS_A_STAR_WEIGHT_DEPTH]; } TRACE0("Before return"); return (int)(ret*INT_MAX); }
/* * 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 }
static GCC_INLINE const fcs_bool_t generic_false_seq_index_loop( const int stacks_num, fcs_kv_state_t * const raw_ptr_state_raw, const int num_vacant_stacks, const fcs_cards_column_t col, sequences_analysis_t * const seqs, const int stack_idx, const int ds, const fcs_bool_t behavior_flag, const fcs_bool_t should_src_col, const fcs_card_t src_card, const int num_src_junk_true_seqs ) { const int num_separate_false_seqs = seqs->num_separate_false_seqs; fcs_bool_t stacks_map[STACKS_MAP_LEN]; init_stacks_map(stacks_map, stack_idx, ds); int after_junk_num_freestacks = num_vacant_stacks; const int false_seq_index_limit = num_separate_false_seqs + (should_src_col ? 1 : 0); int false_seq_index; for (false_seq_index = 0 ; false_seq_index < false_seq_index_limit ; false_seq_index++) { const fcs_bool_t is_ultimate_iter = (false_seq_index == num_separate_false_seqs); /* Find a suitable place to put it */ const fcs_card_t the_card = is_ultimate_iter ? src_card : fcs_col_get_card(col, seqs->seq_points[false_seq_index]); const int the_num_true_seqs = is_ultimate_iter ? num_src_junk_true_seqs : seqs->above_num_true_seqs[false_seq_index]; /* Let's try to find a suitable parent on top one of the stacks */ int clear_junk_dest_stack; for(clear_junk_dest_stack=0; clear_junk_dest_stack < stacks_num; clear_junk_dest_stack++ ) { const fcs_const_cards_column_t clear_junk_dest_col = fcs_state_get_col(state, clear_junk_dest_stack); const int clear_junk_stack_len = fcs_col_len(clear_junk_dest_col); if (! ((clear_junk_stack_len > 0) && (! stacks_map[clear_junk_dest_stack]))) { continue; } if ( fcs_is_ss_false_parent( fcs_col_get_card( clear_junk_dest_col, clear_junk_stack_len-1 ), the_card ) ) { if (calc_max_simple_simon_seq_move(after_junk_num_freestacks) >= the_num_true_seqs) { stacks_map[clear_junk_dest_stack] = TRUE; break; } } } if (clear_junk_dest_stack == stacks_num) { /* Check if there is a vacant stack */ if (behavior_flag || (! ( (num_vacant_stacks > 0) && (calc_max_simple_simon_seq_move(after_junk_num_freestacks-1) >= the_num_true_seqs) ) )) { break; } /* Find an empty stack and designate it as the destination for the junk */ for( clear_junk_dest_stack = 0; clear_junk_dest_stack < stacks_num; clear_junk_dest_stack++ ) { if ((fcs_col_len(fcs_state_get_col(state, clear_junk_dest_stack)) == 0) && (! stacks_map[clear_junk_dest_stack])) { stacks_map[clear_junk_dest_stack] = TRUE; break; } } after_junk_num_freestacks--; } seqs->junk_move_to_stacks[false_seq_index] = clear_junk_dest_stack; } seqs->after_junk_num_freestacks = after_junk_num_freestacks; return (false_seq_index == false_seq_index_limit); }
static inline bool generic_false_seq_index_loop(const int stacks_num, fcs_kv_state raw_state_raw, const int num_vacant_stacks, const fcs_cards_column col, sequences_analysis *const seqs, const stack_i stack_idx, const int ds, const bool behavior_flag, const bool should_src_col, const fcs_card src_card, const size_t num_src_junk_true_seqs) { const size_t num_separate_false_seqs = seqs->num_separate_false_seqs; bool stacks_map[STACKS_MAP_LEN]; init_stacks_map(stacks_map, stack_idx, ds); int after_junk_num_freestacks = num_vacant_stacks; const size_t false_seq_index_limit = num_separate_false_seqs + (should_src_col ? 1 : 0); size_t false_seq_idx; for (false_seq_idx = 0; false_seq_idx < false_seq_index_limit; false_seq_idx++) { const bool is_ultimate_iter = (false_seq_idx == num_separate_false_seqs); /* Find a suitable place to put it */ const fcs_card the_card = is_ultimate_iter ? src_card : fcs_col_get_card(col, seqs->seq_points[false_seq_idx]); const size_t the_num_true_seqs = is_ultimate_iter ? num_src_junk_true_seqs : seqs->above_num_true_seqs[false_seq_idx]; /* Let's try to find a suitable parent on top one of the stacks */ int clear_junk_dest_stack; for (clear_junk_dest_stack = 0; clear_junk_dest_stack < stacks_num; ++clear_junk_dest_stack) { const fcs_const_cards_column clear_junk_dest_col = fcs_state_get_col(state, clear_junk_dest_stack); const int clear_junk_stack_len = fcs_col_len(clear_junk_dest_col); if (!((clear_junk_stack_len > 0) && (!stacks_map[clear_junk_dest_stack]))) { continue; } if (fcs_is_ss_false_parent(fcs_col_get_card(clear_junk_dest_col, clear_junk_stack_len - 1), the_card)) { if (calc_max_simple_simon_seq_move(after_junk_num_freestacks) >= the_num_true_seqs) { goto found; } } } /* Check if there is a vacant stack */ if (behavior_flag || (!((num_vacant_stacks > 0) && (calc_max_simple_simon_seq_move( after_junk_num_freestacks - 1) >= the_num_true_seqs)))) { break; } --after_junk_num_freestacks; /* Find an empty stack and designate it as the destination for the * junk */ for (clear_junk_dest_stack = 0;; ++clear_junk_dest_stack) { if (fcs_state_col_is_empty(state, clear_junk_dest_stack) && (!stacks_map[clear_junk_dest_stack])) { break; } } found: stacks_map[clear_junk_dest_stack] = true; seqs->junk_move_to_stacks[false_seq_idx] = (size_t)clear_junk_dest_stack; } seqs->after_junk_num_freestacks = after_junk_num_freestacks; return (false_seq_idx == false_seq_index_limit); }