/* * state.c - state functions module for Freecell Solver * * Written by Shlomi Fish (shlomif@vipe.technion.ac.il), 2000 * * This file is in the public domain (it's uncopyrighted). */ #include #include #include #include "fcs_config.h" #include "state.h" #include "card.h" #include "fcs_enums.h" #include "app_str.h" #ifdef DMALLOC #include "dmalloc.h" #endif #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif #ifdef DEBUG_STATES fcs_card_t freecell_solver_empty_card = {0,0}; #elif defined(COMPACT_STATES) || defined (INDIRECT_STACK_STATES) fcs_card_t freecell_solver_empty_card = (fcs_card_t)0; #endif static int fcs_card_compare(const void * card1, const void * card2) { const fcs_card_t * c1 = (const fcs_card_t *)card1; const fcs_card_t * c2 = (const fcs_card_t *)card2; if (fcs_card_card_num(*c1) > fcs_card_card_num(*c2)) { return 1; } else if (fcs_card_card_num(*c1) < fcs_card_card_num(*c2)) { return -1; } else { if (fcs_card_suit(*c1) > fcs_card_suit(*c2)) { return 1; } else if (fcs_card_suit(*c1) < fcs_card_suit(*c2)) { return -1; } else { return 0; } } } #ifdef DEBUG_STATES static int fcs_stack_compare(const void * s1, const void * s2) { fcs_card_t card1 = ((const fc_stack_t *)s1)->cards[0]; fcs_card_t card2 = ((const fc_stack_t *)s2)->cards[0]; return fcs_card_compare(&card1, &card2); } #elif defined(COMPACT_STATES) static int fcs_stack_compare(const void * s1, const void * s2) { fcs_card_t card1 = ((fcs_card_t*)s1)[1]; fcs_card_t card2 = ((fcs_card_t*)s2)[1]; return fcs_card_compare(&card1, &card2); } #elif defined(INDIRECT_STACK_STATES) #if MAX_NUM_DECKS == 1 static int fcs_stack_compare_for_stack_sort(const void * s1, const void * s2) { fcs_card_t card1 = ((fcs_card_t*)s1)[1]; fcs_card_t card2 = ((fcs_card_t*)s2)[1]; return fcs_card_compare(&card1, &card2); } #endif int freecell_solver_stack_compare_for_comparison(const void * v_s1, const void * v_s2) { const fcs_card_t * s1 = (const fcs_card_t *)v_s1; const fcs_card_t * s2 = (const fcs_card_t *)v_s2; int min_len; int a, ret; min_len = min(s1[0], s2[0]); for(a=0;a s2[0]) { return 1; } else { return 0; } } #endif #ifdef FCS_WITH_TALONS static int fcs_talon_compare_with_context(const void * p1, const void * p2, fcs_compare_context_t context) { fcs_card_t * t1 = (fcs_card_t *)p1; fcs_card_t * t2 = (fcs_card_t *)p2; if (t1[0] < t2[0]) { return -1; } else if (t1[0] > t2[0]) { return 1; } else { return memcmp(t1,t2,t1[0]+1); } } #endif #ifdef DEBUG_STATES void freecell_solver_canonize_state(fcs_state_with_locations_t * state, int freecells_num, int stacks_num) { int b,c; fc_stack_t temp_stack; fcs_card_t temp_freecell; int temp_loc; /* Insertion-sort the stacks */ for(b=1;b0) && (fcs_stack_compare( &(state->s.stacks[c]), &(state->s.stacks[c-1]) ) < 0) ) { temp_stack = state->s.stacks[c]; state->s.stacks[c] = state->s.stacks[c-1]; state->s.stacks[c-1] = temp_stack; temp_loc = state->stack_locs[c]; state->stack_locs[c] = state->stack_locs[c-1]; state->stack_locs[c-1] = temp_loc; c--; } } /* Insertion sort the freecells */ for(b=1;b0) && (fcs_card_compare( &(state->s.freecells[c]), &(state->s.freecells[c-1]) ) < 0) ) { temp_freecell = state->s.freecells[c]; state->s.freecells[c] = state->s.freecells[c-1]; state->s.freecells[c-1] = temp_freecell; temp_loc = state->fc_locs[c]; state->fc_locs[c] = state->fc_locs[c-1]; state->fc_locs[c-1] = temp_loc; c--; } } } #elif defined(COMPACT_STATES) void freecell_solver_canonize_state( fcs_state_with_locations_t * state, int freecells_num, int stacks_num) { int b,c; char temp_stack[(MAX_NUM_CARDS_IN_A_STACK+1)]; fcs_card_t temp_freecell; char temp_loc; /* Insertion-sort the stacks */ for(b=1;b0) && (fcs_stack_compare( state->s.data+c*(MAX_NUM_CARDS_IN_A_STACK+1), state->s.data+(c-1)*(MAX_NUM_CARDS_IN_A_STACK+1) ) < 0) ) { memcpy(temp_stack, state->s.data+c*(MAX_NUM_CARDS_IN_A_STACK+1), (MAX_NUM_CARDS_IN_A_STACK+1)); memcpy(state->s.data+c*(MAX_NUM_CARDS_IN_A_STACK+1), state->s.data+(c-1)*(MAX_NUM_CARDS_IN_A_STACK+1), (MAX_NUM_CARDS_IN_A_STACK+1)); memcpy(state->s.data+(c-1)*(MAX_NUM_CARDS_IN_A_STACK+1), temp_stack, (MAX_NUM_CARDS_IN_A_STACK+1)); temp_loc = state->stack_locs[c]; state->stack_locs[c] = state->stack_locs[c-1]; state->stack_locs[c-1] = temp_loc; c--; } } /* Insertion-sort the freecells */ for(b=1;b0) && (fcs_card_compare( state->s.data+FCS_FREECELLS_OFFSET+c, state->s.data+FCS_FREECELLS_OFFSET+c-1 ) < 0) ) { temp_freecell = (state->s.data[FCS_FREECELLS_OFFSET+c]); state->s.data[FCS_FREECELLS_OFFSET+c] = state->s.data[FCS_FREECELLS_OFFSET+c-1]; state->s.data[FCS_FREECELLS_OFFSET+c-1] = temp_freecell; temp_loc = state->fc_locs[c]; state->fc_locs[c] = state->fc_locs[c-1]; state->fc_locs[c-1] = temp_loc; c--; } } } #elif defined(INDIRECT_STACK_STATES) void freecell_solver_canonize_state( fcs_state_with_locations_t * state, int freecells_num, int stacks_num) { int b,c; fcs_card_t * temp_stack; fcs_card_t temp_freecell; char temp_loc; /* Insertion-sort the stacks */ for(b=1;b0) && ( #if MAX_NUM_DECKS > 1 freecell_solver_stack_compare_for_comparison #else fcs_stack_compare_for_stack_sort #endif ( (state->s.stacks[c]), (state->s.stacks[c-1]) ) < 0 ) ) { temp_stack = state->s.stacks[c]; state->s.stacks[c] = state->s.stacks[c-1]; state->s.stacks[c-1] = temp_stack; temp_loc = state->stack_locs[c]; state->stack_locs[c] = state->stack_locs[c-1]; state->stack_locs[c-1] = temp_loc; c--; } } /* Insertion sort the freecells */ for(b=1;b0) && (fcs_card_compare( &(state->s.freecells[c]), &(state->s.freecells[c-1]) ) < 0) ) { temp_freecell = state->s.freecells[c]; state->s.freecells[c] = state->s.freecells[c-1]; state->s.freecells[c-1] = temp_freecell; temp_loc = state->fc_locs[c]; state->fc_locs[c] = state->fc_locs[c-1]; state->fc_locs[c-1] = temp_loc; c--; } } } #endif static void fcs_state_init( fcs_state_with_locations_t * state, int stacks_num #ifdef INDIRECT_STACK_STATES ,fcs_card_t * indirect_stacks_buffer #endif ) { int a; memset((void*)&(state->s), 0, sizeof(fcs_state_t)); for(a=0;astack_locs[a] = a; } #ifdef INDIRECT_STACK_STATES for(a=0;as.stacks[a] = &indirect_stacks_buffer[a << 7]; memset(state->s.stacks[a], '\0', MAX_NUM_DECKS*52+1); } for(;as.stacks[a] = NULL; } #endif for(a=0;afc_locs[a] = a; } } #if (FCS_STATE_STORAGE != FCS_STATE_STORAGE_INDIRECT) int freecell_solver_state_compare(const void * s1, const void * s2) { return memcmp(s1,s2,sizeof(fcs_state_t)); } int freecell_solver_state_compare_equal(const void * s1, const void * s2) { return (!memcmp(s1,s2,sizeof(fcs_state_t))); } int freecell_solver_state_compare_with_context( const void * s1, const void * s2, fcs_compare_context_t context ) { (void)context; return memcmp(s1,s2,sizeof(fcs_state_t)); } #else int freecell_solver_state_compare_indirect(const void * s1, const void * s2) { return memcmp(*(fcs_state_with_locations_t * *)s1, *(fcs_state_with_locations_t * *)s2, sizeof(fcs_state_t)); } int freecell_solver_state_compare_indirect_with_context(const void * s1, const void * s2, void * context) { return memcmp(*(fcs_state_with_locations_t * *)s1, *(fcs_state_with_locations_t * *)s2, sizeof(fcs_state_t)); } #endif static const char * const freecells_prefixes[] = { "FC:", "Freecells:", "Freecell:", ""}; static const char * const foundations_prefixes[] = { "Decks:", "Deck:", "Founds:", "Foundations:", "Foundation:", "Found:", ""}; static const char * const talon_prefixes[] = { "Talon:", "Queue:" , ""}; static const char * const num_redeals_prefixes[] = { "Num-Redeals:", "Readels-Num:", "Readeals-Number:", ""}; #ifdef WIN32 #define strncasecmp(a,b,c) (strnicmp((a),(b),(c))) #endif int freecell_solver_initial_user_state_to_c( const char * string, fcs_state_with_locations_t * out_state, int freecells_num, int stacks_num, int decks_num #ifdef FCS_WITH_TALONS ,int talon_type #endif #ifdef INDIRECT_STACK_STATES , fcs_card_t * indirect_stacks_buffer #endif ) { fcs_state_with_locations_t ret_with_locations; int s,c; const char * str; fcs_card_t card; int first_line; int prefix_found; const char * const * prefixes; int i; int decks_index[4]; fcs_state_init( &ret_with_locations, stacks_num #ifdef INDIRECT_STACK_STATES , indirect_stacks_buffer #endif ); str = string; first_line = 1; #define ret (ret_with_locations.s) /* Handle the end of string - shouldn't happen */ #define handle_eos() \ { \ if ((*str) == '\0') \ { \ return FCS_USER_STATE_TO_C__PREMATURE_END_OF_INPUT; \ } \ } #ifdef FCS_WITH_TALONS if (talon_type == FCS_TALON_KLONDIKE) { fcs_klondike_talon_num_redeals_left(ret) = -1; } #endif for(s=0;s= decks_num) { decks_index[d] = 0; } } s--; continue; } #ifdef FCS_WITH_TALONS prefixes = talon_prefixes; prefix_found = 0; for(i=0;prefixes[i][0] != '\0'; i++) { if (!strncasecmp(str, prefixes[i], strlen(prefixes[i]))) { prefix_found = 1; str += strlen(prefixes[i]); break; } } if (prefix_found) { /* Input the Talon */ int talon_size; talon_size = MAX_NUM_DECKS*52+16; ret.talon = malloc(sizeof(fcs_card_t)*talon_size); fcs_talon_pos(ret) = 0; for(c=0 ; c < talon_size ; c++) { /* Move to the next card */ if (c!=0) { while( ((*str) != ' ') && ((*str) != '\t') && ((*str) != '\n') && ((*str) != '\r') ) { handle_eos(); str++; } if ((*str == '\n') || (*str == '\r')) { break; } } while ((*str == ' ') || (*str == '\t')) { str++; } if ((*str == '\n') || (*str == '\r')) { break; } card = fcs_card_user2perl(str); fcs_put_card_in_talon(ret, c+(talon_type==FCS_TALON_KLONDIKE), card); } fcs_talon_len(ret) = c; if (talon_type == FCS_TALON_KLONDIKE) { int talon_len; talon_len = fcs_talon_len(ret); fcs_klondike_talon_len(ret) = talon_len; fcs_klondike_talon_stack_pos(ret) = -1; fcs_klondike_talon_queue_pos(ret) = 0; } s--; continue; } prefixes = num_redeals_prefixes; prefix_found = 0; for(i=0;prefixes[i][0] != '\0'; i++) { if (!strncasecmp(str, prefixes[i], strlen(prefixes[i]))) { prefix_found = 1; str += strlen(prefixes[i]); break; } } if (prefix_found) { while ((*str < '0') && (*str > '9') && (*str != '\n')) { handle_eos(); str++; } if (*str != '\n') { int num_redeals; num_redeals = atoi(str); if (talon_type == FCS_TALON_KLONDIKE) { fcs_klondike_talon_num_redeals_left(ret) = (num_redeals < 0) ? (-1) : ((num_redeals > 127) ? 127 : num_redeals) ; } } s--; continue; } #endif for(c=0 ; c < MAX_NUM_CARDS_IN_A_STACK ; c++) { /* Move to the next card */ if (c!=0) { while( ((*str) != ' ') && ((*str) != '\t') && ((*str) != '\n') && ((*str) != '\r') ) { handle_eos(); str++; } if ((*str == '\n') || (*str == '\r')) { break; } } while ((*str == ' ') || (*str == '\t')) { str++; } if ((*str == '\n') || (*str == '\r')) { break; } card = fcs_card_user2perl(str); fcs_push_card_into_stack(ret, s, card); } } *out_state = ret_with_locations; return FCS_USER_STATE_TO_C__SUCCESS; } #undef ret #undef handle_eos int freecell_solver_check_state_validity( fcs_state_with_locations_t * state_with_locations, int freecells_num, int stacks_num, int decks_num, #ifdef FCS_WITH_TALONS int talon_type, #endif fcs_card_t * misplaced_card) { int cards[4][14]; int c, s, d, f; fcs_state_t * state; state = (&(state_with_locations->s)); /* Initialize all cards to 0 */ for(d=0;d<4;d++) { for(c=1;c<=13;c++) { cards[d][c] = 0; } } /* Mark the cards in the decks */ for(d=0;ds)); if (canonized_order_output) { for(a=0;astack_locs[a])] = a; } for(a=0;afc_locs[a])] = a; } } for(a=0;a max_num_cards) { max_num_cards = fcs_stack_len(*state, stack_locs[s]); } } for(card_num=0;card_num= fcs_stack_len(*state, stack_locs[s])) { freecell_solver_append_string_sprintf( app_str, " " ); } else { freecell_solver_append_string_sprintf( app_str, "%3s ", fcs_card_perl2user( fcs_stack_card( *state, stack_locs[s], card_num), stack_card_, display_10_as_t ) ); } } freecell_solver_append_string_sprintf(app_str, "%s", "\n"); } } else { freecell_solver_append_string_sprintf(app_str, "%s", "Foundations: "); for(a=0;a