|
|
|
/*
|
|
|
|
* fcs.h - header file of the test functions for Freecell Solver.
|
|
|
|
*
|
|
|
|
* The test functions code is found in freecell.c
|
|
|
|
*
|
|
|
|
* Written by Shlomi Fish (shlomif@vipe.technion.ac.il), 2000
|
|
|
|
*
|
|
|
|
* This file is in the public domain (it's uncopyrighted).
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef FC_SOLVE__TESTS_H
|
|
|
|
#define FC_SOLVE__TESTS_H
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "fcs_isa.h"
|
|
|
|
#include "fcs.h"
|
|
|
|
|
|
|
|
#include "test_arr.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The number of cards that can be moved is
|
|
|
|
* (freecells_number + 1) * 2 ^ (free_stacks_number)
|
|
|
|
*
|
|
|
|
* See the Freecell FAQ and the source code of PySol
|
|
|
|
*
|
|
|
|
* */
|
|
|
|
#define calc_max_sequence_move(fc_num, fs_num) \
|
|
|
|
((instance->empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) ? \
|
|
|
|
( \
|
|
|
|
(instance->unlimited_sequence_move) ? \
|
|
|
|
INT_MAX : \
|
|
|
|
(((fc_num)+1)<<(fs_num)) \
|
|
|
|
) : \
|
|
|
|
((fc_num)+1) \
|
|
|
|
)
|
|
|
|
|
|
|
|
#include "caas.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These are some macros to make it easier for the programmer.
|
|
|
|
* */
|
|
|
|
#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)
|
|
|
|
|
|
|
|
#define sfs_check_state_begin() \
|
|
|
|
fcs_state_ia_alloc_into_var(ptr_new_state_with_locations, hard_thread); \
|
|
|
|
fcs_duplicate_state(new_state_with_locations, state_with_locations); \
|
|
|
|
/* Some A* and BFS parameters that need to be initialized in \
|
|
|
|
* the derived state. \
|
|
|
|
* */ \
|
|
|
|
ptr_new_state_with_locations->parent = ptr_state_with_locations; \
|
|
|
|
ptr_new_state_with_locations->moves_to_parent = moves; \
|
|
|
|
/* Make sure depth is consistent with the game graph. \
|
|
|
|
* I.e: the depth of every newly discovered state is derived from \
|
|
|
|
* the state from which it was discovered. */ \
|
|
|
|
ptr_new_state_with_locations->depth = ptr_state_with_locations->depth + 1; \
|
|
|
|
/* Mark this state as a state that was not yet visited */ \
|
|
|
|
ptr_new_state_with_locations->visited = 0; \
|
|
|
|
/* It's a newly created state which does not have tqchildren yet. */ \
|
|
|
|
ptr_new_state_with_locations->num_active_tqchildren = 0; \
|
|
|
|
memset(ptr_new_state_with_locations->scan_visited, '\0', \
|
|
|
|
sizeof(ptr_new_state_with_locations->scan_visited) \
|
|
|
|
); \
|
|
|
|
fcs_move_stack_reset(moves); \
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define sfs_check_state_end() \
|
|
|
|
/* The last move in a move stack should be FCS_MOVE_TYPE_CANONIZE \
|
|
|
|
* because it indicates that the order of the stacks and freecells \
|
|
|
|
* need to be recalculated \
|
|
|
|
* */ \
|
|
|
|
fcs_move_set_type(temp_move,FCS_MOVE_TYPE_CANONIZE); \
|
|
|
|
fcs_move_stack_push(moves, temp_move); \
|
|
|
|
\
|
|
|
|
{ \
|
|
|
|
fcs_state_with_locations_t * existing_state; \
|
|
|
|
check = freecell_solver_check_and_add_state( \
|
|
|
|
soft_thread, \
|
|
|
|
ptr_new_state_with_locations, \
|
|
|
|
&existing_state \
|
|
|
|
); \
|
|
|
|
if ((check == FCS_STATE_BEGIN_SUSPEND_PROCESS) || \
|
|
|
|
(check == FCS_STATE_SUSPEND_PROCESS)) \
|
|
|
|
{ \
|
|
|
|
/* This state is not going to be used, so \
|
|
|
|
* let's clean it. */ \
|
|
|
|
fcs_state_ia_release(hard_thread); \
|
|
|
|
return check; \
|
|
|
|
} \
|
|
|
|
else if (check == FCS_STATE_ALREADY_EXISTS) \
|
|
|
|
{ \
|
|
|
|
fcs_state_ia_release(hard_thread); \
|
|
|
|
calculate_real_depth(existing_state); \
|
|
|
|
/* Re-parent the existing state to this one. \
|
|
|
|
* \
|
|
|
|
* What it means is that if the depth of the state if it \
|
|
|
|
* can be reached from this one is lower than what it \
|
|
|
|
* already have, then re-assign its parent to this state. \
|
|
|
|
* */ \
|
|
|
|
if (reparent && \
|
|
|
|
(existing_state->depth > ptr_state_with_locations->depth+1)) \
|
|
|
|
{ \
|
|
|
|
/* Make a copy of "moves" because "moves" will be destroyed */\
|
|
|
|
existing_state->moves_to_parent = \
|
|
|
|
freecell_solver_move_stack_compact_allocate( \
|
|
|
|
hard_thread, moves \
|
|
|
|
); \
|
|
|
|
if (!(existing_state->visited & FCS_VISITED_DEAD_END)) \
|
|
|
|
{ \
|
|
|
|
if ((--existing_state->parent->num_active_tqchildren) == 0) \
|
|
|
|
{ \
|
|
|
|
mark_as_dead_end( \
|
|
|
|
existing_state->parent \
|
|
|
|
); \
|
|
|
|
} \
|
|
|
|
ptr_state_with_locations->num_active_tqchildren++; \
|
|
|
|
} \
|
|
|
|
existing_state->parent = ptr_state_with_locations; \
|
|
|
|
existing_state->depth = ptr_state_with_locations->depth + 1; \
|
|
|
|
} \
|
|
|
|
fcs_derived_states_list_add_state( \
|
|
|
|
derived_states_list, \
|
|
|
|
existing_state \
|
|
|
|
); \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
fcs_derived_states_list_add_state( \
|
|
|
|
derived_states_list, \
|
|
|
|
ptr_new_state_with_locations \
|
|
|
|
); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
This macro checks if the top card in the stack is a flipped card
|
|
|
|
, and if so flips it so its face is up.
|
|
|
|
*/
|
|
|
|
#define fcs_flip_top_card(stack) \
|
|
|
|
{ \
|
|
|
|
int cards_num; \
|
|
|
|
cards_num = fcs_stack_len(new_state,stack); \
|
|
|
|
\
|
|
|
|
if (cards_num > 0) \
|
|
|
|
{ \
|
|
|
|
if (fcs_card_get_flipped( \
|
|
|
|
fcs_stack_card( \
|
|
|
|
new_state, \
|
|
|
|
stack, \
|
|
|
|
cards_num-1) \
|
|
|
|
) == 1 \
|
|
|
|
) \
|
|
|
|
{ \
|
|
|
|
fcs_flip_stack_card(new_state,stack,cards_num-1); \
|
|
|
|
fcs_move_set_type(temp_move, FCS_MOVE_TYPE_FLIP_CARD); \
|
|
|
|
fcs_move_set_src_stack(temp_move, stack); \
|
|
|
|
\
|
|
|
|
fcs_move_stack_push(moves, temp_move); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dest is the destination stack
|
|
|
|
* source is the source stack
|
|
|
|
* start is the start height
|
|
|
|
* end is the end height
|
|
|
|
* a is the iterator
|
|
|
|
* */
|
|
|
|
#define fcs_move_sequence(dest, source, start, end, a) \
|
|
|
|
{ \
|
|
|
|
for ( a = (start) ; a <= (end) ; a++) \
|
|
|
|
{ \
|
|
|
|
fcs_push_stack_card_into_stack(new_state, dest, source, a); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
for ( a = (start) ; a <= (end) ; a++) \
|
|
|
|
{ \
|
|
|
|
fcs_pop_stack_card(new_state, source, temp_card); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
fcs_move_set_type(temp_move, FCS_MOVE_TYPE_STACK_TO_STACK); \
|
|
|
|
fcs_move_set_src_stack(temp_move, source); \
|
|
|
|
fcs_move_set_dest_stack(temp_move, dest); \
|
|
|
|
fcs_move_set_num_cards_in_seq(temp_move, (end)-(start)+1); \
|
|
|
|
\
|
|
|
|
fcs_move_stack_push(moves, temp_move); \
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This test declares a few access variables that are used in all
|
|
|
|
* the tests.
|
|
|
|
* */
|
|
|
|
#define tests_declare_accessors() \
|
|
|
|
freecell_solver_hard_thread_t * hard_thread; \
|
|
|
|
freecell_solver_instance_t * instance; \
|
|
|
|
fcs_state_with_locations_t * ptr_new_state_with_locations; \
|
|
|
|
fcs_move_stack_t * moves; \
|
|
|
|
char * indirect_stacks_buffer; \
|
|
|
|
int calc_real_depth; \
|
|
|
|
int scans_synergy
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This macro defines these accessors to have some value.
|
|
|
|
* */
|
|
|
|
#define tests_define_accessors() \
|
|
|
|
hard_thread = soft_thread->hard_thread; \
|
|
|
|
instance = hard_thread->instance; \
|
|
|
|
moves = hard_thread->reusable_move_stack; \
|
|
|
|
indirect_stacks_buffer = hard_thread->indirect_stacks_buffer; \
|
|
|
|
calc_real_depth = instance->calc_real_depth; \
|
|
|
|
scans_synergy = instance->scans_synergy;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_sequence_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
|
|
|
|
);
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_sequence_to_true_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
|
|
|
|
);
|
|
|
|
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_whole_stack_sequence_to_false_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
|
|
|
|
);
|
|
|
|
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_sequence_to_true_parent_with_some_cards_above(
|
|
|
|
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
|
|
|
|
);
|
|
|
|
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_sequence_with_some_cards_above_to_true_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
|
|
|
|
);
|
|
|
|
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_sequence_with_junk_seq_above_to_true_parent_with_some_cards_above(
|
|
|
|
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
|
|
|
|
);
|
|
|
|
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_whole_stack_sequence_to_false_parent_with_some_cards_above(
|
|
|
|
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
|
|
|
|
);
|
|
|
|
|
|
|
|
extern int freecell_solver_sfs_simple_simon_move_sequence_to_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
|
|
|
|
);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define my_copy_stack(idx) fcs_copy_stack(new_state_with_locations, idx, indirect_stacks_buffer);
|
|
|
|
|
|
|
|
#endif /* FC_SOLVE__TESTS_H */
|