/* * state.h - header file for state functions and macros for Freecell Solver * * Written by Shlomi Fish (shlomif@vipe.technion.ac.il), 2000 * * This file is in the public domain (it's uncopyrighted). */ #include "fcs_config.h" #include "fcs_move.h" #ifndef FC_SOLVE__STATE_H #define FC_SOLVE__STATE_H #ifdef __cplusplus extern "C" { #endif #if MAX_NUM_INITIAL_CARDS_IN_A_STACK+12>(MAX_NUM_DECKS*52) #define MAX_NUM_CARDS_IN_A_STACK (MAX_NUM_DECKS*52) #else #define MAX_NUM_CARDS_IN_A_STACK (MAX_NUM_INITIAL_CARDS_IN_A_STACK+12) #endif #define MAX_NUM_SCANS_BUCKETS 1 #define MAX_NUM_SCANS (MAX_NUM_SCANS_BUCKETS * (sizeof(int)*8)) /********** * TODO: Change 5 to the log2 of sizeof(int)*8 * ************/ #define is_scan_visited(ptr_state, scan_id) (ptr_state->scan_visited[(scan_id)>>5] & (1 << ((scan_id)&((1<<(5))-1)))) #define set_scan_visited(ptr_state, scan_id) { ptr_state->scan_visited[(scan_id)>>5] |= (1 << ((scan_id)&((1<<(5))-1))); } #ifdef DEBUG_STATES struct fcs_struct_card_t { short card_num; char suit; char flags; }; typedef struct fcs_struct_card_t fcs_card_t; struct fcs_struct_stack_t { unsigned int num_cards; fcs_card_t cards[MAX_NUM_CARDS_IN_A_STACK]; }; typedef struct fcs_struct_stack_t fc_stack_t; struct fcs_struct_state_t { fc_stack_t stacks[MAX_NUM_STACKS]; fcs_card_t freecells[MAX_NUM_FREECELLS]; int foundations[MAX_NUM_DECKS*4]; #ifdef FCS_WITH_TALONS fcs_card_t * talon; char talon_params[4]; #endif }; typedef struct fcs_struct_state_t fcs_state_t; #if 0 struct fcs_struct_state_with_locations_t { fcs_state_t s; int stack_locs[MAX_NUM_STACKS]; int fc_locs[MAX_NUM_FREECELLS]; struct fcs_struct_state_with_locations_t * parent; fcs_move_stack_t * moves_to_parent; int depth; int visited; int visited_iter; int num_active_children; int scan_visited[MAX_NUM_SCANS_BUCKETS]; }; typedef struct fcs_struct_state_with_locations_t fcs_state_with_locations_t; #endif typedef int fcs_locs_t; #define fcs_stack_len(state, s) \ ( (state).stacks[(s)].num_cards ) #define fcs_stack_card(state, s, c) \ ( (state).stacks[(s)].cards[(c)] ) #define fcs_stack_card_suit(state, s, c) \ ( fcs_card_suit(fcs_stack_card((state),(s),(c))) ) #define fcs_stack_card_num(state, s, c) \ ( fcs_card_card_num(fcs_stack_card((state),(s),(c))) ) #define fcs_card_card_num(card) \ ( (card).card_num ) #define fcs_card_suit(card) \ ((int)( (card).suit )) #define fcs_card_get_flipped(card) \ ( (card).flags ) #define fcs_freecell_card(state, f) \ ( (state).freecells[(f)] ) #define fcs_freecell_card_num(state, f) \ ( fcs_card_card_num(fcs_freecell_card((state),(f))) ) #define fcs_freecell_card_suit(state, f) \ ( fcs_card_suit(fcs_freecell_card((state),(f))) ) #define fcs_foundation_value(state, found) \ ( (state).foundations[(found)] ) #define fcs_increment_foundation(state, found) \ ( (state).foundations[(found)]++ ) #define fcs_set_foundation(state, found, value) \ ( (state).foundations[(found)] = (value) ) #define fcs_pop_stack_card(state, s, into) \ { \ into = (state).stacks[(s)].cards[(state).stacks[(s)].num_cards-1]; \ (state).stacks[(s)].cards[(state).stacks[(s)].num_cards-1] = fcs_empty_card; \ (state).stacks[(s)].num_cards--; \ } #define fcs_push_stack_card_into_stack(state, ds, ss, sc) \ { \ (state).stacks[(ds)].cards[(state).stacks[(ds)].num_cards] = (state).stacks[(ss)].cards[(sc)]; \ (state).stacks[(ds)].num_cards++; \ } #define fcs_push_card_into_stack(state, ds, from) \ { \ (state).stacks[(ds)].cards[(state).stacks[(ds)].num_cards] = (from); \ (state).stacks[(ds)].num_cards++; \ } #define fcs_duplicate_state(dest, src) \ (dest) = (src) #define fcs_put_card_in_freecell(state, f, card) \ (state).freecells[(f)] = (card) #define fcs_empty_freecell(state, f) \ (state).freecells[(f)] = fcs_empty_card #define fcs_card_set_suit(card, d) \ (card).suit = (d) #define fcs_card_set_num(card, num) \ (card).card_num = (num) #define fcs_card_set_flipped(card, flipped) \ (card).flags = (flipped) #define fcs_flip_stack_card(state, s, c) \ fcs_card_set_flipped(fcs_stack_card((state),(s),(c)), 0) #ifdef FCS_WITH_TALONS #define fcs_talon_len(state) \ ((state).talon_params[0]) #define fcs_talon_pos(state) \ ((state).talon_params[1]) #define fcs_get_talon_card(state, pos) \ ((state).talon[pos]) #define fcs_put_card_in_talon(state, pos, card) \ ((state).talon[pos] = (card)) #endif #define fcs_copy_stack(state, idx, buffer) {} #elif defined(COMPACT_STATES) /* #ifdef DEBUG_STATES */ typedef char fcs_card_t; /* * Card: * Bits 0-3 - Card Number * Bits 4-5 - Deck * */ struct fcs_struct_state_t { char data[MAX_NUM_STACKS*(MAX_NUM_CARDS_IN_A_STACK+1)+MAX_NUM_FREECELLS+4*MAX_NUM_DECKS]; #ifdef FCS_WITH_TALON fcs_card_t * talon; char talon_params[4]; #endif }; /* * Stack: 0 - Number of cards * 1-19 - Cards * Stacks: stack_num*20 where stack_num >= 0 and * stack_num <= (MAX_NUM_STACKS-1) * Bytes: (MAX_NUM_STACKS*20) to * (MAX_NUM_STACKS*20+MAX_NUM_FREECELLS-1) * are Freecells. * Bytes: (MAX_NUM_STACKS*20+MAX_NUM_FREECELLS) to * MAX_NUM_STACKS*20+MAX_NUM_FREECELLS+3 * are Foundations. * */ /* ===== Depracated Information ===== * Stack: 0 - Number of cards 1-19 - Cards * Stacks: stack_num*20 where stack_num >= 0 and stack_num <= 7 * Bytes 160-163 - Freecells * Bytes 164-167 - Decks */ typedef struct fcs_struct_state_t fcs_state_t; #if 0 struct fcs_struct_state_with_locations_t { fcs_state_t s; char stack_locs[MAX_NUM_STACKS]; char fc_locs[MAX_NUM_FREECELLS]; struct fcs_struct_state_with_locations_t * parent; fcs_move_stack_t * moves_to_parent; int depth; int visited; int visited_iter; int num_active_children; int scan_visited[MAX_NUM_SCANS_BUCKETS]; }; typedef struct fcs_struct_state_with_locations_t fcs_state_with_locations_t; #endif typedef char fcs_locs_t; #define fcs_card_card_num(card) \ ( (card) & 0x0F ) #define fcs_card_suit(card) \ ( ((card) >> 4) & 0x03 ) #define fcs_stack_len(state, s) \ ( (size_t)(state).data[s*(MAX_NUM_CARDS_IN_A_STACK+1)] ) #define fcs_stack_card(state, s, c) \ ( (state).data[(s)*(MAX_NUM_CARDS_IN_A_STACK+1)+(c)+1] ) #define fcs_stack_card_num(state, s, c) \ ( fcs_card_card_num(fcs_stack_card((state),(s),(c))) ) #define fcs_stack_card_suit(state, s, c) \ ( fcs_card_suit(fcs_stack_card((state),(s),(c))) ) #define FCS_FREECELLS_OFFSET ((MAX_NUM_STACKS)*(MAX_NUM_CARDS_IN_A_STACK+1)) #define fcs_freecell_card(state, f) \ ( (state).data[FCS_FREECELLS_OFFSET+(f)] ) #define fcs_freecell_card_num(state, f) \ ( fcs_card_card_num(fcs_freecell_card((state),(f))) ) #define fcs_freecell_card_suit(state, f) \ ( fcs_card_suit(fcs_freecell_card((state),(f))) ) #define FCS_FOUNDATIONS_OFFSET (((MAX_NUM_STACKS)*(MAX_NUM_CARDS_IN_A_STACK+1))+(MAX_NUM_FREECELLS)) #define fcs_foundation_value(state, d) \ ( (state).data[FCS_FOUNDATIONS_OFFSET+(d)]) #define fcs_increment_foundation(state, d) \ ( (state).data[FCS_FOUNDATIONS_OFFSET+(d)]++ ) #define fcs_set_foundation(state, d, value) \ ( (state).data[FCS_FOUNDATIONS_OFFSET+(d)] = (value) ) #define fcs_pop_stack_card(state, s, into) \ { \ into = fcs_stack_card((state), (s), (fcs_stack_len((state), (s))-1)); \ (state).data[((s)*(MAX_NUM_CARDS_IN_A_STACK+1))+1+(fcs_stack_len((state), (s))-1)] = fcs_empty_card; \ (state).data[(s)*(MAX_NUM_CARDS_IN_A_STACK+1)]--; \ } #define fcs_push_card_into_stack(state, ds, from) \ { \ (state).data[(ds)*(MAX_NUM_CARDS_IN_A_STACK+1)+1+fcs_stack_len((state), (ds))] = (from); \ (state).data[(ds)*(MAX_NUM_CARDS_IN_A_STACK+1)]++; \ } #define fcs_push_stack_card_into_stack(state, ds, ss, sc) \ fcs_push_card_into_stack((state), (ds), fcs_stack_card((state), (ss), (sc))) #define fcs_duplicate_state(dest, src) \ (dest) = (src) #define fcs_put_card_in_freecell(state, f, card) \ (state).data[FCS_FREECELLS_OFFSET+(f)] = (card); #define fcs_empty_freecell(state, f) \ fcs_put_card_in_freecell((state), (f), fcs_empty_card) #define fcs_card_set_num(card, num) \ (card) = (((card)&0xF0)|(num)); #define fcs_card_set_suit(card, suit) \ (card) = (((card)&0x4F)|((suit)<<4)); #define fcs_card_set_flipped(card, flipped) \ (card) = (((card)&((fcs_card_t)0x3F))|((fcs_card_t)((flipped)<<6))) #define fcs_card_get_flipped(card) \ ( (card) >> 6 ) #ifdef FCS_WITH_TALONS #define fcs_talon_len(state) \ ((state).talon_params[0]) #define fcs_talon_pos(state) \ ((state).talon_params[1]) #define fcs_put_card_in_talon(state, pos, card) \ ((state).talon[pos] = (card)) #define fcs_get_talon_card(state, pos) \ ((state).talon[pos]) #endif #define fcs_flip_stack_card(state, s, c) \ (fcs_card_set_flipped(fcs_stack_card((state),(s),(c)), ((fcs_card_t)0) )) #define fcs_copy_stack(state, idx, buffer) {} #elif defined(INDIRECT_STACK_STATES) /* #ifdef DEBUG_STATES #elif defined(COMPACT_STATES) */ typedef char fcs_card_t; struct fcs_struct_state_t { fcs_card_t * stacks[MAX_NUM_STACKS]; fcs_card_t freecells[MAX_NUM_FREECELLS]; char foundations[MAX_NUM_DECKS*4]; #ifdef FCS_WITH_TALONS fcs_card_t * talon; char talon_params[4]; #endif }; typedef struct fcs_struct_state_t fcs_state_t; #define fcs_card_card_num(card) \ ( (card) & 0x0F ) #define fcs_card_suit(card) \ ( ((card) >> 4) & 0x03 ) #define fcs_card_get_flipped(card) \ ( (card) >> 6 ) #define fcs_standalone_stack_len(stack) \ ( (size_t)(stack[0]) ) #define fcs_stack_len(state, s) \ ( (unsigned int)(state).stacks[(s)][0] ) #define fcs_stack_card(state, s, c) \ ( (state).stacks[(s)][c+1] ) #define fcs_stack_card_num(state, s, c) \ ( fcs_card_card_num(fcs_stack_card((state),(s),(c))) ) #define fcs_stack_card_suit(state, s, c) \ ( fcs_card_suit(fcs_stack_card((state),(s),(c))) ) #define fcs_freecell_card(state, f) \ ( (state).freecells[(f)] ) #define fcs_freecell_card_num(state, f) \ ( fcs_card_card_num(fcs_freecell_card((state),(f))) ) #define fcs_freecell_card_suit(state, f) \ ( fcs_card_suit(fcs_freecell_card((state),(f))) ) #define fcs_foundation_value(state, d) \ ( (state).foundations[(d)] ) #define fcs_increment_foundation(state, d) \ ( (state).foundations[(d)]++ ) #define fcs_set_foundation(state, d, value) \ ( (state).foundations[(d)] = (value) ) #define fcs_pop_stack_card(state, s, into) \ { \ into = fcs_stack_card((state), (s), (fcs_stack_len((state), (s))-1)); \ (state).stacks[s][fcs_stack_len((state), (s))] = fcs_empty_card; \ (state).stacks[s][0]--; \ } #define fcs_push_card_into_stack(state, ds, from) \ { \ (state).stacks[(ds)][fcs_stack_len((state), (ds))+1] = (from); \ (state).stacks[(ds)][0]++; \ } #define fcs_push_stack_card_into_stack(state, ds, ss, sc) \ fcs_push_card_into_stack((state), (ds), fcs_stack_card((state), (ss), (sc))) #define fcs_put_card_in_freecell(state, f, card) \ (state).freecells[(f)] = (card) #define fcs_empty_freecell(state, f) \ fcs_put_card_in_freecell((state), (f), fcs_empty_card) #define fcs_card_set_num(card, num) \ (card) = (((card)&0xF0)|(num)) #define fcs_card_set_suit(card, suit) \ (card) = (((card)&0x4F)|((suit)<<4)) #define fcs_card_set_flipped(card, flipped) \ (card) = (fcs_card_t)(((card)&0x3F)|((fcs_card_t)(flipped<<6))) #ifdef FCS_WITH_TALONS #define fcs_talon_len(state) \ ((state).talon_params[0]) #define fcs_talon_pos(state) \ ((state).talon_params[1]) #define fcs_put_card_in_talon(state, pos, card) \ ((state).talon[pos] = (card)) #define fcs_get_talon_card(state, pos) \ ((state).talon[pos]) #endif #define fcs_flip_stack_card(state, s, c) \ (fcs_card_set_flipped(fcs_stack_card(state,s,c), ((fcs_card_t)0) )) #define fcs_duplicate_state(dest,src) \ { \ (dest) = (src); \ (dest).stacks_copy_on_write_flags = 0; \ } #define fcs_copy_stack(state, idx, buffer) \ { \ if (! ((state).stacks_copy_on_write_flags & (1 << idx))) \ { \ size_t stack_len; \ (state).stacks_copy_on_write_flags |= (1 << idx); \ stack_len = fcs_stack_len((state).s,idx); \ memcpy(&buffer[idx << 7], (state).s.stacks[idx], stack_len+1); \ (state).s.stacks[idx] = &buffer[idx << 7]; \ } \ } typedef char fcs_locs_t; #endif /* #ifdef DEBUG_STATES - #elif defined COMPACT_STATES - #elif defined INDIRECT_STACK_STATES */ struct fcs_struct_state_with_locations_t { fcs_state_t s; fcs_locs_t stack_locs[MAX_NUM_STACKS]; fcs_locs_t fc_locs[MAX_NUM_FREECELLS]; struct fcs_struct_state_with_locations_t * parent; fcs_move_stack_t * moves_to_parent; int depth; /* * This field contains global, scan-independant flags, which are used * from the FCS_VISITED_T enum below. * * FCS_VISITED_VISITED - deprecated * * FCS_VISITED_IN_SOLUTION_PATH - indicates that the state is in the * solution path found by the scan. (used by the optimization scan) * * FCS_VISITED_IN_OPTIMIZED_PATH - indicates that the state is in the * optimized solution path which is computed by the optimization scan. * * FCS_VISITED_DEAD_END - indicates that the state does not lead to * anywhere useful, and scans should not examine it in the first place. * */ int visited; /* * The iteration in which this state was marked as visited * */ int visited_iter; /* * This is the number of direct children of this state which were not * yet declared as dead ends. Once this counter reaches zero, this * state too is declared as a dead end. * */ int num_active_children; /* * This is a vector of flags - one for each scan. Each indicates whether * its scan has already visited this state * */ int scan_visited[MAX_NUM_SCANS_BUCKETS]; #ifdef INDIRECT_STACK_STATES /* * A vector of flags that indicates which stacks were already copied. * */ int stacks_copy_on_write_flags; #endif }; typedef struct fcs_struct_state_with_locations_t fcs_state_with_locations_t; extern fcs_card_t freecell_solver_empty_card; #define fcs_empty_card freecell_solver_empty_card #ifdef FCS_WITH_TALONS #define fcs_klondike_talon_len(state) \ ((state).talon[0]) #define fcs_klondike_talon_stack_pos(state) \ ((state).talon_params[0]) #define fcs_klondike_talon_queue_pos(state) \ ((state).talon_params[1]) #define fcs_klondike_talon_num_redeals_left(state) \ ((state).talon_params[2]) #define fcs_klondike_talon_get_top_card(state) \ ((state).talon[(int)fcs_klondike_talon_stack_pos(state)]) #define fcs_klondike_talon_queue_to_stack(state) \ ( ((state).talon[(int)((++fcs_klondike_talon_stack_pos(state))+1)]) = \ ((state).talon[(int)((fcs_klondike_talon_queue_pos(state)++)+1)]) ) #define fcs_klondike_talon_redeal_bare(state) \ { \ fcs_klondike_talon_stack_pos(state) = -1; \ fcs_klondike_talon_queue_pos(state) = 0; \ } #define fcs_klondike_talon_decrement_stack(state) \ ((state).talon[(int)((fcs_klondike_talon_stack_pos(state)--)+1)] = fcs_empty_card) #endif extern void freecell_solver_canonize_state( fcs_state_with_locations_t * state, int freecells_num, int stacks_num ); #define fcs_canonize_state(state,freecells_num,stacks_num) freecell_solver_canonize_state((state),(freecells_num),(stacks_num)) #if (FCS_STATE_STORAGE != FCS_STATE_STORAGE_INDIRECT) #if (FCS_STATE_STORAGE != FCS_STATE_STORAGE_LIBREDBLACK_TREE) typedef void * fcs_compare_context_t; #else typedef const void * fcs_compare_context_t; #endif extern int freecell_solver_state_compare(const void * s1, const void * s2); extern int freecell_solver_state_compare_equal(const void * s1, const void * s2); extern int freecell_solver_state_compare_with_context(const void * s1, const void * s2, fcs_compare_context_t context); #else extern int freecell_solver_state_compare_indirect(const void * s1, const void * s2); extern int freecell_solver_state_compare_indirect_with_context(const void * s1, const void * s2, void * context); #endif #ifdef FCS_WITH_TALONS extern int fcs_talon_compare_with_context(const void * s1, const void * s2, fcs_compare_context_t context); #endif enum FCS_USER_STATE_TO_C_RETURN_CODES { FCS_USER_STATE_TO_C__SUCCESS = 0, FCS_USER_STATE_TO_C__PREMATURE_END_OF_INPUT }; 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 ); extern char * freecell_solver_state_as_string( fcs_state_with_locations_t * state, int freecells_num, int stacks_num, int decks_num, int parseable_output, int canonized_order_output, int display_10_as_t ); enum FCS_STATE_VALIDITY_CODES { FCS_STATE_VALIDITY__OK = 0, FCS_STATE_VALIDITY__EMPTY_SLOT = 3, FCS_STATE_VALIDITY__EXTRA_CARD = 2, FCS_STATE_VALIDITY__MISSING_CARD = 1, FCS_STATE_VALIDITY__PREMATURE_END_OF_INPUT = 4 }; extern int freecell_solver_check_state_validity( fcs_state_with_locations_t * state, int freecells_num, int stacks_num, int decks_num, #ifdef FCS_WITH_TALONS int talon_type, #endif fcs_card_t * misplaced_card ); #ifdef __cplusplus } #endif enum FCS_VISITED_T { FCS_VISITED_VISITED = 0x1, FCS_VISITED_IN_SOLUTION_PATH = 0x2, FCS_VISITED_IN_OPTIMIZED_PATH = 0x4, FCS_VISITED_DEAD_END = 0x8, FCS_VISITED_ALL_TESTS_DONE = 0x10 }; #endif /* FC_SOLVE__STATE_H */