/* * freecell.c - The various movement tests performed by Freecell Solver * * Written by Shlomi Fish (shlomif@vipe.technion.ac.il), 2000-2001 * * This file is in the public domain (it's uncopyrighted). */ #include #include #include #include #include #include "fcs_config.h" #if FCS_STATE_STORAGE==FCS_STATE_STORAGE_LIBREDBLACK_TREE #include #endif #include "state.h" #include "card.h" #include "fcs_dm.h" #include "fcs.h" #include "fcs_isa.h" #include "tests.h" #include "ms_ca.h" #ifdef DMALLOC #include "dmalloc.h" #endif #define state_with_locations (*ptr_state_with_locations) #define state (ptr_state_with_locations->s) #define new_state_with_locations (*ptr_new_state_with_locations) #define new_state (ptr_new_state_with_locations->s) #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) #endif /* * Throughout this code the following local variables are used to quickly * access the instance's members: * * state_stacks_num - the number of stacks in the state * state_freecells_num - the number of freecells in the state * sequences_are_built_by - the type of sequences of this board. * */ /* * This function tries to move stack cards that are present at the * top of stacks to the foundations. * */ int freecell_solver_sfs_move_top_stack_cards_to_founds( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int stack; int cards_num; int deck; fcs_card_t card; fcs_card_t temp_card; int check; int state_stacks_num; fcs_move_t temp_move; tests_define_accessors(); moves = hard_thread->reusable_move_stack; indirect_stacks_buffer = hard_thread->indirect_stacks_buffer; state_stacks_num = instance->stacks_num; for(stack=0;stackdecks_num;deck++) { if (fcs_foundation_value(state, deck*4+fcs_card_suit(card)) == fcs_card_card_num(card) - 1) { /* We can put it there */ sfs_check_state_begin(); my_copy_stack(stack); fcs_pop_stack_card(new_state, stack, temp_card); fcs_increment_foundation(new_state, deck*4+fcs_card_suit(card)); fcs_move_init(temp_move); fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FOUNDATION); fcs_move_set_src_stack(temp_move,stack); fcs_move_set_foundation(temp_move,deck*4+fcs_card_suit(card)); fcs_move_stack_push(moves, temp_move); fcs_flip_top_card(stack); /* The last move needs to be FCS_MOVE_TYPE_CANONIZE * because it indicates that the internal order of the * stacks * and freecells may have changed. */ fcs_move_set_type(temp_move,FCS_MOVE_TYPE_CANONIZE); fcs_move_stack_push(moves, temp_move); sfs_check_state_end() break; } } } } return FCS_STATE_IS_NOT_SOLVEABLE; } /* * This test moves single cards that are present in the freecells to * the foundations. * */ int freecell_solver_sfs_move_freecell_cards_to_founds( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int fc; int deck; fcs_card_t card; int check; fcs_move_t temp_move; int state_freecells_num; tests_define_accessors(); state_freecells_num = instance->freecells_num; /* Now check the same for the free cells */ for(fc=0;fcdecks_num;deck++) { if (fcs_foundation_value(state, deck*4+fcs_card_suit(card)) == fcs_card_card_num(card) - 1) { /* We can put it there */ sfs_check_state_begin() fcs_empty_freecell(new_state, fc); fcs_increment_foundation(new_state, deck*4+fcs_card_suit(card)); fcs_move_init(temp_move); fcs_move_set_type(temp_move,FCS_MOVE_TYPE_FREECELL_TO_FOUNDATION); fcs_move_set_src_freecell(temp_move,fc); fcs_move_set_foundation(temp_move,deck*4+fcs_card_suit(card)); fcs_move_stack_push(moves, temp_move); fcs_move_set_type(temp_move,FCS_MOVE_TYPE_CANONIZE); fcs_move_stack_push(moves, temp_move); sfs_check_state_end(); } } } } return FCS_STATE_IS_NOT_SOLVEABLE; } int freecell_solver_sfs_move_freecell_cards_on_top_of_stacks( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int dest_cards_num; int ds, fc, dc; fcs_card_t dest_card, src_card, temp_card, dest_below_card; int check; fcs_move_t temp_move; int is_seq_in_dest; int num_cards_to_relocate; int freecells_to_fill, freestacks_to_fill; int a,b; int state_freecells_num, state_stacks_num, sequences_are_built_by; tests_define_accessors(); state_freecells_num = instance->freecells_num; state_stacks_num = instance->stacks_num; sequences_are_built_by = instance->sequences_are_built_by; /* Let's try to put cards in the freecells on top of stacks */ /* ds stands for destination stack */ for(ds=0;ds 0) { /* * Let's search for a suitable card in the stack * */ for(dc=dest_cards_num-1;dc>=0;dc--) { dest_card = fcs_stack_card(state, ds, dc); /* Scan the freecells */ for(fc=0;fc dc) { dest_below_card = fcs_stack_card(state, ds, dc+1); if (fcs_is_parent_card(dest_below_card, dest_card)) { is_seq_in_dest = 1; } } if (! is_seq_in_dest) { num_cards_to_relocate = dest_cards_num - dc - 1; freecells_to_fill = min(num_cards_to_relocate, num_freecells); num_cards_to_relocate -= freecells_to_fill; if (instance->empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) { freestacks_to_fill = min(num_cards_to_relocate, num_freestacks); num_cards_to_relocate -= freestacks_to_fill; } else { freestacks_to_fill = 0; } if (num_cards_to_relocate == 0) { /* We can move it */ sfs_check_state_begin() /* Fill the freecells with the top cards */ my_copy_stack(ds); for(a=0 ; afreecells_num; state_stacks_num = instance->stacks_num; /* Now let's check if a card that is under some other cards can be placed * in the foundations. */ for(stack=0;stack= 0 ; c--) { card = fcs_stack_card(state, stack, c); for(deck=0;deckdecks_num;deck++) { if (fcs_foundation_value(state, deck*4+fcs_card_suit(card)) == fcs_card_card_num(card)-1) { /* The card is foundation-able. Now let's check if we * can move the cards above it to the freecells and * stacks */ if ((num_freecells + ((instance->empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) ? num_freestacks : 0 )) >= cards_num-(c+1)) { /* We can move it */ sfs_check_state_begin() my_copy_stack(stack); /* Fill the freecells with the top cards */ for(a=0 ; afreecells_num; state_stacks_num = instance->stacks_num; sequences_are_built_by = instance->sequences_are_built_by; /* * Now let's try to move a stack card to a parent card which is found * on the same stack. * */ for (stack=0;stackempty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) { freestacks_to_fill = min(num_cards_to_relocate, num_freestacks); num_cards_to_relocate -= freestacks_to_fill; } else { freestacks_to_fill = 0; } if (num_cards_to_relocate == 0) { /* We can move it */ sfs_check_state_begin() { int i_card_pos; fcs_card_t moved_card; int source_type, source_index; i_card_pos = fcs_stack_len(new_state,stack)-1; a = 0; my_copy_stack(ds); while(i_card_pos>c) { if (a < freecells_to_fill) { for(b=0;bdc) { if (a < freecells_to_fill) { for(b=0;bfreecells_num; state_stacks_num = instance->stacks_num; sequences_are_built_by = instance->sequences_are_built_by; /* Now let's try to move a card from one stack to the other * * Note that it does not involve moving cards lower than king * * to empty stacks */ for (stack=0;stack dc) { dest_below_card = fcs_stack_card(state, ds, dc+1); if (fcs_is_parent_card(dest_below_card, dest_card)) { is_seq_in_dest = 1; } } if (! is_seq_in_dest) { num_cards_to_relocate = dest_cards_num - dc - 1 + cards_num - seq_end - 1; freecells_to_fill = min(num_cards_to_relocate, num_freecells); num_cards_to_relocate -= freecells_to_fill; if (instance->empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) { freestacks_to_fill = min(num_cards_to_relocate, num_freestacks); num_cards_to_relocate -= freestacks_to_fill; } else { freestacks_to_fill = 0; } if ((num_cards_to_relocate == 0) && (calc_max_sequence_move(num_freecells-freecells_to_fill, num_freestacks-freestacks_to_fill) >= seq_end - c + 1)) { /* We can move it */ int from_which_stack; sfs_check_state_begin() /* Fill the freecells with the top cards */ my_copy_stack(stack); my_copy_stack(ds); for(a=0 ; aempty_stacks_fill == FCS_ES_FILLED_BY_NONE) { return FCS_STATE_IS_NOT_SOLVEABLE; } state_freecells_num = instance->freecells_num; state_stacks_num = instance->stacks_num; sequences_are_built_by = instance->sequences_are_built_by; max_sequence_len = calc_max_sequence_move(num_freecells, num_freestacks-1); /* Now try to move sequences to empty stacks */ if (num_freestacks > 0) { for(stack=0;stackempty_stacks_fill == FCS_ES_FILLED_BY_KINGS_ONLY)) { continue; } if (seq_end == cards_num -1) { /* One stack is the destination stack, so we have one * * less stack in that case */ while ((max_sequence_len < cards_num -c) && (c > 0)) { c--; } if ( (c > 0) && ((instance->empty_stacks_fill == FCS_ES_FILLED_BY_KINGS_ONLY) ? (fcs_card_card_num(fcs_stack_card(state, stack, c)) == 13) : 1 ) ) { sfs_check_state_begin(); for(ds=0;dsempty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) { freestacks_to_fill = min(num_cards_to_relocate, num_freestacks); num_cards_to_relocate -= freestacks_to_fill; } else { freestacks_to_fill = 0; } if ((num_cards_to_relocate == 0) && (num_freestacks-freestacks_to_fill > 0)) { /* We can move it */ int seq_start = c; while ( (calc_max_sequence_move( num_freecells-freecells_to_fill, num_freestacks-freestacks_to_fill-1) < seq_end-seq_start+1) && (seq_start <= seq_end) ) { seq_start++; } if ((seq_start <= seq_end) && ((instance->empty_stacks_fill == FCS_ES_FILLED_BY_KINGS_ONLY) ? (fcs_card_card_num(fcs_stack_card(state, stack, seq_start)) == 13) : 1 ) ) { sfs_check_state_begin(); /* Fill the freecells with the top cards */ my_copy_stack(stack); for(a=0; aempty_stacks_fill == FCS_ES_FILLED_BY_NONE) { return FCS_STATE_IS_NOT_SOLVEABLE; } state_freecells_num = instance->freecells_num; state_stacks_num = instance->stacks_num; for(fc=0;fcempty_stacks_fill == FCS_ES_FILLED_BY_KINGS_ONLY) ? (fcs_card_card_num(card) == 13) : (fcs_card_card_num(card) != 0) ) { for(stack=0;stackfreecells_num; state_stacks_num = instance->stacks_num; sequences_are_built_by = instance->sequences_are_built_by; fcs_move_init(temp_move); /* This time try to move cards that are already on top of a parent to a different parent */ for (stack=0;stack dc) { dest_below_card = fcs_stack_card(state, ds, dc+1); if (fcs_is_parent_card(dest_below_card,dest_card)) { is_seq_in_dest = 1; } } if (! is_seq_in_dest) { if (is_seq_in_src) { num_cards_to_relocate = dest_cards_num - dc - 1; freecells_to_fill = min(num_cards_to_relocate, num_freecells); num_cards_to_relocate -= freecells_to_fill; if (instance->empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) { freestacks_to_fill = min(num_cards_to_relocate, num_freestacks); num_cards_to_relocate -= freestacks_to_fill; } else { freestacks_to_fill = 0; } if ((num_cards_to_relocate == 0) && (calc_max_sequence_move(num_freecells-freecells_to_fill, num_freestacks-freestacks_to_fill) >= cards_num - c)) { /* We can move it */ sfs_check_state_begin() /* Fill the freecells with the top cards */ my_copy_stack(ds); for(a=0 ; aempty_stacks_fill == FCS_ES_FILLED_BY_NONE) { return FCS_STATE_IS_NOT_SOLVEABLE; } state_stacks_num = instance->stacks_num; state_freecells_num = instance->freecells_num; /* Now, let's try to empty an entire stack into the freecells, so other cards can * inhabit it */ if (num_freestacks == 0) { for(stack=0;stackstacks_num; sequences_are_built_by = instance->sequences_are_built_by; for( ds=0 ; ds < state_stacks_num ; ds++ ) { dest_cards_num = fcs_stack_len(state, ds); if (dest_cards_num > 0) { dest_card = fcs_stack_card(state, ds, dest_cards_num-1); for( stack=0 ; stack < state_stacks_num ; stack++) { if (stack == ds) { continue; } cards_num = fcs_stack_len(state, stack); for( c=cards_num-1 ; c >= 0 ; c--) { card = fcs_stack_card(state, stack, c); if (fcs_card_get_flipped(card)) { break; } if (fcs_is_parent_card(card, dest_card)) { /* We can move it there - now let's check to see * if it is already above a suitable parent. */ if ((c == 0) || (! fcs_is_parent_card(card, fcs_stack_card(state, stack, c-1)))) { /* Let's move it */ sfs_check_state_begin(); my_copy_stack(stack); my_copy_stack(ds); fcs_move_sequence(ds, stack, c, cards_num-1, a); fcs_flip_top_card(stack); sfs_check_state_end(); } } } } } } return FCS_STATE_IS_NOT_SOLVEABLE; } int freecell_solver_sfs_yukon_move_kings_to_empty_stack( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int check; int stack, cards_num, c, a, ds; fcs_card_t card, temp_card; int state_stacks_num; fcs_move_t temp_move; tests_define_accessors(); if (num_freestacks == 0) { return FCS_STATE_IS_NOT_SOLVEABLE; } state_stacks_num = instance->stacks_num; for( stack=0 ; stack < state_stacks_num ; stack++) { cards_num = fcs_stack_len(state, stack); for( c=cards_num-1 ; c >= 1 ; c--) { card = fcs_stack_card(state, stack, c); if (fcs_card_get_flipped(card)) { break; } if (fcs_card_card_num(card) == 13) { /* It's a King - so let's move it */ sfs_check_state_begin(); for( ds=0 ; ds < state_stacks_num ; ds++) { if (fcs_stack_len(state, ds) == 0) { break; } } my_copy_stack(stack); my_copy_stack(ds); fcs_move_sequence(ds, stack, c, cards_num-1, a); fcs_flip_top_card(stack); sfs_check_state_end(); } } } return FCS_STATE_IS_NOT_SOLVEABLE; } #ifdef FCS_WITH_TALONS /* Let's try to deal the Gypsy-type Talon. */ int freecell_solver_sfs_deal_gypsy_talon( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int check; fcs_card_t temp_card; int a; fcs_move_t temp_move; tests_define_accessors(); if (instance->talon_type != FCS_TALON_GYPSY) { return FCS_STATE_IS_NOT_SOLVEABLE; } moves = hard_thread->reusable_move_stack; indirect_stacks_buffer = hard_thread->indirect_stacks_buffer; if (fcs_talon_pos(state) < fcs_talon_len(state)) { sfs_check_state_begin() for(a=0;atalon_type != FCS_TALON_KLONDIKE) { return FCS_STATE_IS_NOT_SOLVEABLE; } /* Duplicate the talon and its parameters into talon_temp */ talon_temp = malloc(sizeof(fcs_state_with_locations_t)); talon_temp->s.talon = malloc(fcs_klondike_talon_len(state)+1); memcpy( talon_temp->s.talon, ptr_state_with_locations->s.talon, fcs_klondike_talon_len(state)+1 ); memcpy( talon_temp->s.talon_params, ptr_state_with_locations->s.talon_params, sizeof(ptr_state_with_locations->s.talon_params) ); /* Make sure we redeal the talon only once */ num_redeals_left = fcs_klondike_talon_num_redeals_left(state); if ((num_redeals_left > 0) || (num_redeals_left < 0)) { num_redeals_left = 1; } num_redeals_done = 0; num_cards_moved[0] = 0; num_cards_moved[1] = 0; first_iter = 1; while (num_redeals_left >= 0) { if ((fcs_klondike_talon_stack_pos(talon_temp->s) == -1) && (fcs_klondike_talon_queue_pos(talon_temp->s) == fcs_klondike_talon_len(talon_temp->s))) { break; } if ((!first_iter) || (fcs_klondike_talon_stack_pos(talon_temp->s) == -1)) { if (fcs_klondike_talon_queue_pos(talon_temp->s) == fcs_klondike_talon_len(talon_temp->s)) { if (num_redeals_left > 0) { fcs_klondike_talon_len(talon_temp->s) = fcs_klondike_talon_stack_pos(talon_temp->s); fcs_klondike_talon_redeal_bare(talon_temp->s); num_redeals_left--; num_redeals_done++; } else { break; } } fcs_klondike_talon_queue_to_stack(talon_temp->s); num_cards_moved[num_redeals_done]++; } first_iter = 0; card_to_check = fcs_klondike_talon_get_top_card(talon_temp->s); for(s=0 ; ss)+1); memcpy( new_state.talon, talon_temp->s.talon, fcs_klondike_talon_len(talon_temp->s)+1 ); memcpy( ptr_new_state_with_locations->s.talon_params, talon_temp->s.talon_params, sizeof(ptr_state_with_locations->s.talon_params) ); for(a=0;a<=num_redeals_done;a++) { fcs_move_set_type(temp_move, FCS_MOVE_TYPE_KLONDIKE_FLIP_TALON); fcs_move_set_num_cards_flipped(temp_move, num_cards_moved[a]); fcs_move_stack_push(moves, temp_move); if (a != num_redeals_done) { fcs_move_set_type(temp_move, FCS_MOVE_TYPE_KLONDIKE_REDEAL_TALON); fcs_move_stack_push(moves,temp_move); } } fcs_push_card_into_stack(new_state, s, fcs_klondike_talon_get_top_card(new_state)); fcs_move_set_type(temp_move, FCS_MOVE_TYPE_KLONDIKE_TALON_TO_STACK); fcs_move_set_dest_stack(temp_move, s); fcs_klondike_talon_decrement_stack(new_state); sfs_check_state_end() } } } #if 0 cleanup: #endif free(talon_temp->s.talon); free(talon_temp); return FCS_STATE_IS_NOT_SOLVEABLE; } #endif int freecell_solver_sfs_atomic_move_card_to_empty_stack( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int empty_stacks_filled_by, state_stacks_num; int stack, cards_num; fcs_card_t card, temp_card; fcs_move_t temp_move; int check; int empty_stack_idx; tests_define_accessors(); if (num_freestacks == 0) { return FCS_STATE_IS_NOT_SOLVEABLE; } state_stacks_num = instance->stacks_num; for(empty_stack_idx=0;empty_stack_idxempty_stacks_fill; if (empty_stacks_filled_by == FCS_ES_FILLED_BY_NONE) { return FCS_STATE_IS_NOT_SOLVEABLE; } for(stack=0;stack 0) { card = fcs_stack_card(state, stack, cards_num-1); if ((empty_stacks_filled_by == FCS_ES_FILLED_BY_KINGS_ONLY) && (fcs_card_card_num(card) != 13)) { continue; } /* Let's move it */ { sfs_check_state_begin(); my_copy_stack(stack); fcs_pop_stack_card(new_state, stack, temp_card); my_copy_stack(empty_stack_idx); fcs_push_card_into_stack(new_state, empty_stack_idx, card); fcs_move_set_type(temp_move, FCS_MOVE_TYPE_STACK_TO_STACK); fcs_move_set_src_stack(temp_move, stack); fcs_move_set_dest_stack(temp_move, empty_stack_idx); fcs_move_set_num_cards_in_seq(temp_move, 1); fcs_move_stack_push(moves, temp_move); fcs_move_set_type(temp_move,FCS_MOVE_TYPE_CANONIZE); fcs_move_stack_push(moves, temp_move); sfs_check_state_end() } } } return FCS_STATE_IS_NOT_SOLVEABLE; } int freecell_solver_sfs_atomic_move_card_to_parent( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int state_stacks_num; int stack, cards_num, ds, ds_cards_num; fcs_card_t card, dest_card, temp_card; fcs_move_t temp_move; int check; int sequences_are_built_by; tests_define_accessors(); state_stacks_num = instance->stacks_num; sequences_are_built_by = instance->sequences_are_built_by; for(stack=0;stack 0) { card = fcs_stack_card(state, stack, cards_num-1); for(ds=0;ds 0) { dest_card = fcs_stack_card(state, ds, ds_cards_num-1); if (fcs_is_parent_card(card, dest_card)) { /* Let's move it */ { sfs_check_state_begin(); my_copy_stack(stack); my_copy_stack(ds); fcs_pop_stack_card(new_state, stack, temp_card); fcs_push_card_into_stack(new_state, ds, card); fcs_move_set_type(temp_move, FCS_MOVE_TYPE_STACK_TO_STACK); fcs_move_set_src_stack(temp_move, stack); fcs_move_set_dest_stack(temp_move, ds); fcs_move_set_num_cards_in_seq(temp_move, 1); fcs_move_stack_push(moves, temp_move); fcs_move_set_type(temp_move,FCS_MOVE_TYPE_CANONIZE); fcs_move_stack_push(moves, temp_move); sfs_check_state_end() } } } } } } return FCS_STATE_IS_NOT_SOLVEABLE; } int freecell_solver_sfs_atomic_move_card_to_freecell( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int state_stacks_num; int state_freecells_num; int stack, cards_num, ds; fcs_card_t card, temp_card; fcs_move_t temp_move; int check; int sequences_are_built_by; tests_define_accessors(); state_stacks_num = instance->stacks_num; state_freecells_num = instance->freecells_num; sequences_are_built_by = instance->sequences_are_built_by; if (num_freecells == 0) { return FCS_STATE_IS_NOT_SOLVEABLE; } for(ds=0;ds 0) { card = fcs_stack_card(state, stack, cards_num-1); /* Let's move it */ { sfs_check_state_begin(); my_copy_stack(stack); fcs_pop_stack_card(new_state, stack, temp_card); fcs_put_card_in_freecell(new_state, ds, card); fcs_move_init(temp_move); fcs_move_set_type(temp_move, FCS_MOVE_TYPE_STACK_TO_FREECELL); fcs_move_set_src_stack(temp_move, stack); fcs_move_set_dest_freecell(temp_move, ds); fcs_move_stack_push(moves, temp_move); fcs_move_set_type(temp_move,FCS_MOVE_TYPE_CANONIZE); fcs_move_stack_push(moves, temp_move); sfs_check_state_end() } } } return FCS_STATE_IS_NOT_SOLVEABLE; } int freecell_solver_sfs_atomic_move_freecell_card_to_parent( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int state_stacks_num, state_freecells_num; int fc, ds, ds_cards_num; fcs_card_t card, dest_card; fcs_move_t temp_move; int check; int sequences_are_built_by; tests_define_accessors(); state_stacks_num = instance->stacks_num; state_freecells_num = instance->freecells_num; sequences_are_built_by = instance->sequences_are_built_by; for(fc=0;fc 0) { dest_card = fcs_stack_card(state, ds, ds_cards_num-1); if (fcs_is_parent_card(card, dest_card)) { /* Let's move it */ { sfs_check_state_begin(); my_copy_stack(ds); fcs_empty_freecell(new_state, fc); fcs_push_card_into_stack(new_state, ds, card); fcs_move_set_type(temp_move, FCS_MOVE_TYPE_FREECELL_TO_STACK); fcs_move_set_src_freecell(temp_move, fc); fcs_move_set_dest_stack(temp_move, ds); fcs_move_set_num_cards_in_seq(temp_move, 1); fcs_move_stack_push(moves, temp_move); fcs_move_set_type(temp_move,FCS_MOVE_TYPE_CANONIZE); fcs_move_stack_push(moves, temp_move); sfs_check_state_end() } } } } } return FCS_STATE_IS_NOT_SOLVEABLE; } int freecell_solver_sfs_atomic_move_freecell_card_to_empty_stack( freecell_solver_soft_thread_t * soft_thread, fcs_state_with_locations_t * ptr_state_with_locations, int num_freestacks, int num_freecells, fcs_derived_states_list_t * derived_states_list, int reparent ) { tests_declare_accessors(); int state_stacks_num, state_freecells_num; int fc, ds; fcs_card_t card; fcs_move_t temp_move; int check; int sequences_are_built_by, empty_stacks_filled_by; tests_define_accessors(); moves = hard_thread->reusable_move_stack; indirect_stacks_buffer = hard_thread->indirect_stacks_buffer; state_stacks_num = instance->stacks_num; state_freecells_num = instance->freecells_num; sequences_are_built_by = instance->sequences_are_built_by; if (num_freestacks == 0) { return FCS_STATE_IS_NOT_SOLVEABLE; } empty_stacks_filled_by = instance->empty_stacks_fill; if (empty_stacks_filled_by == FCS_ES_FILLED_BY_NONE) { return FCS_STATE_IS_NOT_SOLVEABLE; } for(ds=0;ds