diff options
Diffstat (limited to 'kpat/freecell-solver/freecell.c')
-rw-r--r-- | kpat/freecell-solver/freecell.c | 2433 |
1 files changed, 2433 insertions, 0 deletions
diff --git a/kpat/freecell-solver/freecell.c b/kpat/freecell-solver/freecell.c new file mode 100644 index 00000000..159772ff --- /dev/null +++ b/kpat/freecell-solver/freecell.c @@ -0,0 +1,2433 @@ +/* + * 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 <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <limits.h> + + +#include "fcs_config.h" + +#if FCS_STATE_STORAGE==FCS_STATE_STORAGE_LIBREDBLACK_TREE +#include <search.h> +#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;stack<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + if (cards_num) + { + /* Get the top card in the stack */ + card = fcs_stack_card(state,stack,cards_num-1); + for(deck=0;deck<instance->decks_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;fc<state_freecells_num;fc++) + { + card = fcs_freecell_card(state, fc); + if (fcs_card_card_num(card) != 0) + { + for(deck=0;deck<instance->decks_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<state_stacks_num;ds++) + { + dest_cards_num = fcs_stack_len(state, ds); + + /* If the stack is not empty we can proceed */ + if (dest_cards_num > 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<state_freecells_num;fc++) + { + src_card = fcs_freecell_card(state, fc); + + /* If the freecell is not empty and dest_card is its parent + * */ + if ( (fcs_card_card_num(src_card) != 0) && + fcs_is_parent_card(src_card,dest_card) ) + { + /* Let's check if we can put it there */ + + /* Check if the destination card is already below a + * suitable card */ + is_seq_in_dest = 0; + if (dest_cards_num - 1 > 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 ; a<freecells_to_fill ; a++) + { + /* Find a vacant freecell */ + for(b=0;b<state_freecells_num;b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + fcs_pop_stack_card(new_state, ds, temp_card); + + fcs_put_card_in_freecell(new_state, b, temp_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,ds); + fcs_move_set_dest_freecell(temp_move,b); + fcs_move_stack_push(moves, temp_move); + } + + /* Fill the free stacks with the cards below them */ + for(a=0; a < freestacks_to_fill ; a++) + { + /* Find a vacant stack */ + for(b=0;b<state_stacks_num;b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + my_copy_stack(b); + + fcs_pop_stack_card(new_state, ds, temp_card); + fcs_push_card_into_stack(new_state, b, temp_card); + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_STACK); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_stack(temp_move,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + fcs_move_stack_push(moves, temp_move); + } + + /* Now put the freecell card on top of the stack */ + + fcs_push_card_into_stack(new_state, ds, src_card); + fcs_empty_freecell(new_state, fc); + 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_stack_push(moves, temp_move); + + sfs_check_state_end() + } + } + } + } + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} + + + +int freecell_solver_sfs_move_non_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 check; + + int stack; + int cards_num; + int c, a, b; + fcs_card_t temp_card, card; + int deck; + int state_freecells_num; + int state_stacks_num; + + fcs_move_t temp_move; + fcs_move_init(temp_move); + + tests_define_accessors(); + + state_freecells_num = instance->freecells_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<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + /* + * We starts from cards_num-2 because the top card is already covered + * by move_top_stack_cards_to_founds. + * */ + for(c=cards_num-2 ; c >= 0 ; c--) + { + card = fcs_stack_card(state, stack, c); + for(deck=0;deck<instance->decks_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 ; a<min(num_freecells, cards_num-(c+1)) ; a++) + { + /* Find a vacant freecell */ + for(b=0; b<state_freecells_num; b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + fcs_pop_stack_card(new_state, stack, temp_card); + + fcs_put_card_in_freecell(new_state, b, temp_card); + + 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,b); + + fcs_move_stack_push(moves, temp_move); + + fcs_flip_top_card(stack); + } + + /* Fill the free stacks with the cards below them */ + for(a=0; a < cards_num-(c+1) - min(num_freecells, cards_num-(c+1)) ; a++) + { + /* Find a vacant stack */ + for(b=0;b<state_stacks_num;b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + my_copy_stack(b); + + fcs_pop_stack_card(new_state, stack, temp_card); + fcs_push_card_into_stack(new_state, b, temp_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,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + + fcs_move_stack_push(moves, temp_move); + + fcs_flip_top_card(stack); + } + + fcs_pop_stack_card(new_state, stack, temp_card); + fcs_increment_foundation(new_state, deck*4+fcs_card_suit(temp_card)); + + 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(temp_card)); + + fcs_move_stack_push(moves, temp_move); + + fcs_flip_top_card(stack); + + sfs_check_state_end() + } + break; + } + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} + + + + +int freecell_solver_sfs_move_stack_cards_to_a_parent_on_the_same_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, c, cards_num, a, dc,b; + int is_seq_in_dest; + fcs_card_t card, temp_card, prev_card; + fcs_card_t dest_below_card, dest_card; + int freecells_to_fill, freestacks_to_fill; + int dest_cards_num, num_cards_to_relocate; + int state_freecells_num; + int state_stacks_num; + int sequences_are_built_by; + + fcs_move_t temp_move; + fcs_move_init(temp_move); + + tests_define_accessors(); + + state_freecells_num = instance->freecells_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;stack<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + + for (c=0 ; c<cards_num ; c++) + { + /* Find a card which this card can be put on; */ + + card = fcs_stack_card(state, stack, c); + + + /* Do not move cards that are already found above a suitable parent */ + a = 1; + if (c != 0) + { + prev_card = fcs_stack_card(state, stack, c-1); + if ((fcs_card_card_num(prev_card) == fcs_card_card_num(card)+1) && + ((fcs_card_suit(prev_card) & 0x1) != (fcs_card_suit(card) & 0x1))) + { + a = 0; + } + } + if (a) + { +#define ds stack + /* Check if it can be moved to something on the same stack */ + dest_cards_num = fcs_stack_len(state, ds); + for(dc=0;dc<c-1;dc++) + { + dest_card = fcs_stack_card(state, ds, dc); + if (fcs_is_parent_card(card, dest_card)) + { + /* Corresponding cards - see if it is feasible to move + the source to the destination. */ + + is_seq_in_dest = 0; + 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() + + + { + 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;b<state_freecells_num;b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + fcs_pop_stack_card(new_state, ds, temp_card); + fcs_put_card_in_freecell(new_state, b, temp_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FREECELL); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_freecell(temp_move,b); + + fcs_move_stack_push(moves, temp_move); + + } + else + { + + /* Find a vacant stack */ + for(b=0;b<state_stacks_num;b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + my_copy_stack(b); + + fcs_pop_stack_card(new_state, ds, temp_card); + fcs_push_card_into_stack(new_state, b, temp_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_STACK); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_stack(temp_move,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + + fcs_move_stack_push(moves, temp_move); + + } + a++; + + i_card_pos--; + } + fcs_pop_stack_card(new_state, ds, moved_card); + if (a < freecells_to_fill) + { + for(b=0;b<state_freecells_num;b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + fcs_put_card_in_freecell(new_state, b, moved_card); + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FREECELL); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_freecell(temp_move,b); + fcs_move_stack_push(moves, temp_move); + + source_type = 0; + source_index = b; + } + else + { + for(b=0;b<state_stacks_num;b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + my_copy_stack(b); + fcs_push_card_into_stack(new_state, b, moved_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_STACK); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_stack(temp_move,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + fcs_move_stack_push(moves, temp_move); + + source_type = 1; + source_index = b; + } + i_card_pos--; + a++; + + while(i_card_pos>dc) + { + if (a < freecells_to_fill) + { + for(b=0;b<state_freecells_num;b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + fcs_pop_stack_card(new_state, ds, temp_card); + fcs_put_card_in_freecell(new_state, b, temp_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FREECELL); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_freecell(temp_move,b); + + fcs_move_stack_push(moves, temp_move); + } + else + { + + /* Find a vacant stack */ + for(b=0;b<state_stacks_num;b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + fcs_pop_stack_card(new_state, ds, temp_card); + my_copy_stack(b); + fcs_push_card_into_stack(new_state, b, temp_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_STACK); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_stack(temp_move,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + + fcs_move_stack_push(moves, temp_move); + + } + a++; + + i_card_pos--; + } + + if (source_type == 0) + { + moved_card = fcs_freecell_card(new_state, source_index); + fcs_empty_freecell(new_state, source_index); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_FREECELL_TO_STACK); + fcs_move_set_src_freecell(temp_move,source_index); + fcs_move_set_dest_stack(temp_move,ds); + fcs_move_stack_push(moves, temp_move); + } + else + { + my_copy_stack(source_index); + fcs_pop_stack_card(new_state, source_index, moved_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_STACK); + fcs_move_set_src_stack(temp_move,source_index); + 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_push_card_into_stack(new_state, ds, moved_card); + } + + sfs_check_state_end() + } + } + } + } + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} +#undef ds + + +int freecell_solver_sfs_move_stack_cards_to_different_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 check; + + int stack, c, cards_num, a, dc, ds,b; + int is_seq_in_dest; + fcs_card_t card, temp_card, this_card, prev_card; + fcs_card_t dest_below_card, dest_card; + int freecells_to_fill, freestacks_to_fill; + int dest_cards_num, num_cards_to_relocate; + int seq_end; + int state_freecells_num; + int state_stacks_num; + int sequences_are_built_by; + + fcs_move_t temp_move; + fcs_move_init(temp_move); + + tests_define_accessors(); + + state_freecells_num = instance->freecells_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<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + + for (c=0 ; c<cards_num ; c=seq_end+1) + { + /* Check if there is a sequence here. */ + for(seq_end=c ; seq_end<cards_num-1 ; seq_end++) + { + this_card = fcs_stack_card(state, stack, seq_end+1); + prev_card = fcs_stack_card(state, stack, seq_end); + + if (fcs_is_parent_card(this_card,prev_card)) + { + } + else + { + break; + } + } + + /* Find a card which this card can be put on; */ + + card = fcs_stack_card(state, stack, c); + + /* Make sure the card is not flipped or else we can't move it */ + if (fcs_card_get_flipped(card) == 0) + { + for(ds=0 ; ds<state_stacks_num; ds++) + { + if (ds != stack) + { + dest_cards_num = fcs_stack_len(state, ds); + for(dc=0;dc<dest_cards_num;dc++) + { + dest_card = fcs_stack_card(state, ds, dc); + + if (fcs_is_parent_card(card, dest_card)) + { + /* Corresponding cards - see if it is feasible to move + the source to the destination. */ + + is_seq_in_dest = 0; + if (dest_cards_num - 1 > 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 ; a<freecells_to_fill ; a++) + { + /* Find a vacant freecell */ + for(b=0;b<state_freecells_num;b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + + if (fcs_stack_len(new_state, ds) == dc+1) + { + from_which_stack = stack; + } + else + { + from_which_stack = ds; + } + my_copy_stack(from_which_stack); + + fcs_pop_stack_card(new_state, from_which_stack, temp_card); + + fcs_put_card_in_freecell(new_state, b, temp_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FREECELL); + fcs_move_set_src_stack(temp_move,from_which_stack); + fcs_move_set_dest_freecell(temp_move,b); + fcs_move_stack_push(moves, temp_move); + + fcs_flip_top_card(from_which_stack); + } + + /* Fill the free stacks with the cards below them */ + for(a=0; a < freestacks_to_fill ; a++) + { + /* Find a vacant stack */ + for(b=0;b<state_stacks_num;b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + if (fcs_stack_len(new_state, ds) == dc+1) + { + from_which_stack = stack; + } + else + { + from_which_stack = ds; + } + + my_copy_stack(b); + fcs_pop_stack_card(new_state, from_which_stack, temp_card); + fcs_push_card_into_stack(new_state, b, temp_card); + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_STACK); + fcs_move_set_src_stack(temp_move,from_which_stack); + fcs_move_set_dest_stack(temp_move,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + fcs_move_stack_push(moves, temp_move); + + fcs_flip_top_card(from_which_stack); + } + + for(a=c ; a <= seq_end ; a++) + { + fcs_push_stack_card_into_stack(new_state, ds, stack, a); + } + + for(a=0; a < seq_end-c+1 ;a++) + { + fcs_pop_stack_card(new_state, stack, temp_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,seq_end-c+1); + fcs_move_stack_push(moves, temp_move); + + fcs_flip_top_card(stack); + + sfs_check_state_end() + } + } + } + } + } + } + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} + + + +int freecell_solver_sfs_move_sequences_to_free_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 check; + + int stack, cards_num, c, ds, a, b, seq_end; + fcs_card_t this_card, prev_card, temp_card; + int max_sequence_len; + int num_cards_to_relocate, freecells_to_fill, freestacks_to_fill; + int state_freecells_num; + int state_stacks_num; + int sequences_are_built_by; + + fcs_move_t temp_move; + fcs_move_init(temp_move); + + tests_define_accessors(); + + if (instance->empty_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;stack<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + + for(c=0; c<cards_num; c=seq_end+1) + { + /* Check if there is a sequence here. */ + for(seq_end=c ; seq_end<cards_num-1; seq_end++) + { + this_card = fcs_stack_card(state, stack, seq_end+1); + prev_card = fcs_stack_card(state, stack, seq_end); + + if (! fcs_is_parent_card(this_card, prev_card)) + { + break; + } + } + + if ((fcs_stack_card_num(state, stack, c) != 13) && + (instance->empty_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;ds<state_stacks_num;ds++) + { + if (fcs_stack_len(state, ds) == 0) + break; + } + + my_copy_stack(ds); + + for(a=c ; a <= cards_num-1 ; a++) + { + fcs_push_stack_card_into_stack(new_state, ds, stack, a); + } + + my_copy_stack(stack); + + for(a=0;a<cards_num-c;a++) + { + fcs_pop_stack_card(new_state, stack, temp_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,cards_num-c); + + fcs_move_stack_push(moves, temp_move); + + + sfs_check_state_end() + } + } + else + { + num_cards_to_relocate = 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) && (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; a<freecells_to_fill ; a++) + { + /* Find a vacant freecell */ + for(b=0;b<state_freecells_num;b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + fcs_pop_stack_card(new_state, stack, temp_card); + fcs_put_card_in_freecell(new_state, b, temp_card); + + 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,b); + fcs_move_stack_push(moves, temp_move); + } + + my_copy_stack(stack); + + /* Fill the free stacks with the cards below them */ + for(a=0; a < freestacks_to_fill ; a++) + { + /* Find a vacant stack */ + for(b=0; b<state_stacks_num; b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + my_copy_stack(b); + fcs_pop_stack_card(new_state, stack, temp_card); + fcs_push_card_into_stack(new_state, b, temp_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,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + fcs_move_stack_push(moves, temp_move); + } + + /* Find a vacant stack */ + for(b=0; b<state_stacks_num; b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + my_copy_stack(b); + + for(a=seq_start ; a <= seq_end ; a++) + { + fcs_push_stack_card_into_stack(new_state, b, stack, a); + } + for(a=seq_start ; a <= seq_end ; a++) + { + fcs_pop_stack_card(new_state, stack, temp_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,b); + fcs_move_set_num_cards_in_seq(temp_move,seq_end-seq_start+1); + fcs_move_stack_push(moves, temp_move); + + sfs_check_state_end(); + } + } + } + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} + + + +int freecell_solver_sfs_move_freecell_cards_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 fc, stack; + fcs_card_t card; + + fcs_move_t temp_move; + + int state_freecells_num; + int state_stacks_num; + + /* Let's try to put cards that occupy freecells on an empty stack */ + + tests_define_accessors(); + + if (instance->empty_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;fc<state_freecells_num;fc++) + { + card = fcs_freecell_card(state, fc); + if ( + (instance->empty_stacks_fill == FCS_ES_FILLED_BY_KINGS_ONLY) ? + (fcs_card_card_num(card) == 13) : + (fcs_card_card_num(card) != 0) + ) + { + for(stack=0;stack<state_stacks_num;stack++) + { + if (fcs_stack_len(state, stack) == 0) + { + break; + } + } + if (stack != state_stacks_num) + { + /* We can move it */ + + sfs_check_state_begin(); + + my_copy_stack(stack); + + fcs_push_card_into_stack(new_state, stack, card); + fcs_empty_freecell(new_state, fc); + + fcs_move_init(temp_move); + 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,stack); + fcs_move_stack_push(moves, temp_move); + + sfs_check_state_end() + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} + +int freecell_solver_sfs_move_cards_to_a_different_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 check; + + int stack, cards_num, c, a, b, ds, dc; + int is_seq_in_src, is_seq_in_dest; + int num_cards_to_relocate; + int dest_cards_num; + fcs_card_t card, this_card, prev_card, temp_card; + fcs_card_t dest_card, dest_below_card; + int freecells_to_fill, freestacks_to_fill; + + fcs_move_t temp_move; + + int state_freecells_num; + int state_stacks_num; + int 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; + + 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<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + + for (c=0 ; c<cards_num ; c++) + { + /* Check if there is a sequence here. */ + is_seq_in_src = 1; + for(a=c+1 ; a<cards_num ; a++) + { + this_card = fcs_stack_card(state, stack, a); + prev_card = fcs_stack_card(state, stack, a-1); + + if (fcs_is_parent_card(this_card,prev_card)) + { + } + else + { + is_seq_in_src = 0; + break; + } + } + + /* Find a card which this card can be put on; */ + + card = fcs_stack_card(state, stack, c); + + + /* Do not move cards that are already found above a suitable parent */ + a = 1; + if (c != 0) + { + prev_card = fcs_stack_card(state, stack, c-1); + if (fcs_is_parent_card(card,prev_card)) + { + a = 0; + } + } + /* And do not move cards that are flipped */ + if (!a) + { + this_card = fcs_stack_card(state,stack,c); + if (fcs_card_get_flipped(this_card)) + { + a = 0; + } + } + if (!a) + { + for(ds=0 ; ds<state_stacks_num; ds++) + { + if (ds != stack) + { + dest_cards_num = fcs_stack_len(state, ds); + for(dc=0;dc<dest_cards_num;dc++) + { + dest_card = fcs_stack_card(state, ds, dc); + + if (fcs_is_parent_card(card,dest_card)) + { + /* Corresponding cards - see if it is feasible to move + the source to the destination. */ + + is_seq_in_dest = 0; + if (dest_cards_num - 1 > 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 ; a<freecells_to_fill ; a++) + { + /* Find a vacant freecell */ + for(b=0;b<state_freecells_num;b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + + fcs_pop_stack_card(new_state, ds, temp_card); + + fcs_put_card_in_freecell(new_state, b, temp_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FREECELL); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_freecell(temp_move,b); + fcs_move_stack_push(moves, temp_move); + } + + /* Fill the free stacks with the cards below them */ + for(a=0; a < freestacks_to_fill ; a++) + { + /* Find a vacant stack */ + for(b=0;b<state_stacks_num;b++) + { + if (fcs_stack_len(new_state, b) == 0) + { + break; + } + } + + my_copy_stack(b); + + fcs_pop_stack_card(new_state, ds, temp_card); + fcs_push_card_into_stack(new_state, b, temp_card); + + fcs_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_STACK); + fcs_move_set_src_stack(temp_move,ds); + fcs_move_set_dest_stack(temp_move,b); + fcs_move_set_num_cards_in_seq(temp_move,1); + fcs_move_stack_push(moves, temp_move); + } + + my_copy_stack(stack); + + for(a=c ; a <= cards_num-1 ; a++) + { + fcs_push_stack_card_into_stack(new_state, ds, stack, a); + } + + for(a=0;a<cards_num-c;a++) + { + fcs_pop_stack_card(new_state, stack, temp_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,cards_num-c); + fcs_move_stack_push(moves, temp_move); + + sfs_check_state_end() + } + } + } + } + } + } + } + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} + + + + +int freecell_solver_sfs_empty_stack_into_freecells( + 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, b; + fcs_card_t temp_card; + int state_stacks_num; + int state_freecells_num; + + fcs_move_t temp_move; + + tests_define_accessors(); + + if (instance->empty_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;stack<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + if (cards_num <= num_freecells) + { + /* We can empty it */ + + sfs_check_state_begin() + + my_copy_stack(stack); + + for(c=0;c<cards_num;c++) + { + /* Find a vacant freecell */ + for(b=0; b<state_freecells_num; b++) + { + if (fcs_freecell_card_num(new_state, b) == 0) + { + break; + } + } + fcs_pop_stack_card(new_state, stack, temp_card); + + fcs_put_card_in_freecell(new_state, b, temp_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,b); + fcs_move_stack_push(moves, temp_move); + } + + sfs_check_state_end() + } + } + } + + return FCS_STATE_IS_NOT_SOLVEABLE; + +} + +int freecell_solver_sfs_yukon_do_nothing( + 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 + ) +{ + return FCS_STATE_IS_NOT_SOLVEABLE; +} + +int freecell_solver_sfs_yukon_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 check; + + int stack, cards_num, c, a, ds; + int dest_cards_num; + fcs_card_t card, temp_card; + fcs_card_t dest_card; + + int state_stacks_num; + int sequences_are_built_by; + + fcs_move_t temp_move; + + tests_define_accessors(); + + state_stacks_num = instance->stacks_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;a<state_stacks_num;a++) + { + temp_card = fcs_get_talon_card(new_state, fcs_talon_pos(new_state)+a); + fcs_push_card_into_stack(new_state,a,temp_card); + } + fcs_talon_pos(new_state) += state_stacks_num; + fcs_move_set_type(temp_move, FCS_MOVE_TYPE_DEAL_GYPSY_TALON); + fcs_move_stack_push(moves, temp_move); + + sfs_check_state_end() + } + + return FCS_STATE_IS_NOT_SOLVEABLE; +} + + +int freecell_solver_sfs_get_card_from_klondike_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(); + + + fcs_state_with_locations_t * talon_temp; + + fcs_move_t temp_move; + + int check; + int num_redeals_left, num_redeals_done, num_cards_moved[2]; + int first_iter; + fcs_card_t card_to_check, top_card; + int s; + int cards_num; + int a; + + tests_define_accessors(); + + if (instance->talon_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 ; s<state_stacks_num ; s++) + { + cards_num = fcs_stack_len(state,s); + top_card = fcs_stack_card(state,s,cards_num-1); + if (fcs_is_parent_card(card_to_check, top_card)) + { + /* We have a card in the talon that we can move + to the stack, so let's move it */ + sfs_check_state_begin() + + new_state.talon = malloc(fcs_klondike_talon_len(talon_temp->s)+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_idx<state_stacks_num;empty_stack_idx++) + { + if (fcs_stack_len(state, empty_stack_idx) == 0) + { + break; + } + } + + 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(stack=0;stack<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + if (cards_num > 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<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + if (cards_num > 0) + { + card = fcs_stack_card(state, stack, cards_num-1); + + for(ds=0;ds<state_stacks_num;ds++) + { + if (ds == stack) + { + continue; + } + + ds_cards_num = fcs_stack_len(state, ds); + if (ds_cards_num > 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<state_freecells_num;ds++) + { + if (fcs_freecell_card_num(state, ds) == 0) + { + break; + } + } + + + + for(stack=0;stack<state_stacks_num;stack++) + { + cards_num = fcs_stack_len(state, stack); + if (cards_num > 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<state_freecells_num;fc++) + { + card = fcs_freecell_card(state, fc); + if (fcs_card_card_num(card) == 0) + { + continue; + } + + for(ds=0;ds<state_stacks_num;ds++) + { + ds_cards_num = fcs_stack_len(state, ds); + if (ds_cards_num > 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<state_stacks_num;ds++) + { + if (fcs_stack_len(state, ds) == 0) + { + break; + } + } + + for(fc=0;fc<state_freecells_num;fc++) + { + card = fcs_freecell_card(state, fc); + if (fcs_card_card_num(card) == 0) + { + continue; + } + + if ((empty_stacks_filled_by == FCS_ES_FILLED_BY_KINGS_ONLY) && + (fcs_card_card_num(card) != 13)) + { + continue; + } + + { + 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; +} + + +#undef state_with_locations +#undef state +#undef new_state_with_locations +#undef new_state + + +freecell_solver_solve_for_state_test_t freecell_solver_sfs_tests[FCS_TESTS_NUM] = +{ + freecell_solver_sfs_move_top_stack_cards_to_founds, + freecell_solver_sfs_move_freecell_cards_to_founds, + freecell_solver_sfs_move_freecell_cards_on_top_of_stacks, + freecell_solver_sfs_move_non_top_stack_cards_to_founds, + freecell_solver_sfs_move_stack_cards_to_different_stacks, + freecell_solver_sfs_move_stack_cards_to_a_parent_on_the_same_stack, + freecell_solver_sfs_move_sequences_to_free_stacks, + freecell_solver_sfs_move_freecell_cards_to_empty_stack, + freecell_solver_sfs_move_cards_to_a_different_parent, + freecell_solver_sfs_empty_stack_into_freecells, + freecell_solver_sfs_simple_simon_move_sequence_to_founds, + freecell_solver_sfs_simple_simon_move_sequence_to_true_parent, + freecell_solver_sfs_simple_simon_move_whole_stack_sequence_to_false_parent, + freecell_solver_sfs_simple_simon_move_sequence_to_true_parent_with_some_cards_above, + freecell_solver_sfs_simple_simon_move_sequence_with_some_cards_above_to_true_parent, + freecell_solver_sfs_simple_simon_move_sequence_with_junk_seq_above_to_true_parent_with_some_cards_above, + freecell_solver_sfs_simple_simon_move_whole_stack_sequence_to_false_parent_with_some_cards_above, + freecell_solver_sfs_simple_simon_move_sequence_to_parent_on_the_same_stack, + freecell_solver_sfs_atomic_move_card_to_empty_stack, + freecell_solver_sfs_atomic_move_card_to_parent, + freecell_solver_sfs_atomic_move_card_to_freecell, + freecell_solver_sfs_atomic_move_freecell_card_to_parent, + freecell_solver_sfs_atomic_move_freecell_card_to_empty_stack, +#if 0 + freecell_solver_sfs_move_top_stack_cards_to_founds, + freecell_solver_sfs_yukon_move_card_to_parent, + freecell_solver_sfs_yukon_move_kings_to_empty_stack, + freecell_solver_sfs_yukon_do_nothing, + freecell_solver_sfs_yukon_do_nothing, +#endif + freecell_solver_sfs_yukon_do_nothing, + freecell_solver_sfs_yukon_do_nothing +#ifdef FCS_WITH_TALONS + , + freecell_solver_sfs_deal_gypsy_talon, + freecell_solver_sfs_get_card_from_klondike_talon +#endif +}; |