diff options
Diffstat (limited to 'kpat/freecell-solver/preset.c')
-rw-r--r-- | kpat/freecell-solver/preset.c | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/kpat/freecell-solver/preset.c b/kpat/freecell-solver/preset.c new file mode 100644 index 00000000..16a02f1d --- /dev/null +++ b/kpat/freecell-solver/preset.c @@ -0,0 +1,637 @@ +/* + * preset.c - game presets management for Freecell Solver + * + * Written by Shlomi Fish ([email protected]), 2000 + * + * This file is in the public domain (it's uncopyrighted). + * + */ + + +#include <string.h> +#include <stdlib.h> + +#include "fcs.h" +#include "preset.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +enum fcs_presets_ids +{ + FCS_PRESET_BAKERS_DOZEN, + FCS_PRESET_BAKERS_GAME, + FCS_PRESET_CRUEL, + FCS_PRESET_DER_KATZENSCHWANZ, + FCS_PRESET_DIE_SCHLANGE, + FCS_PRESET_EIGHT_OFF, + FCS_PRESET_FAN, + FCS_PRESET_FORECELL, + FCS_PRESET_FREECELL, + FCS_PRESET_GOOD_MEASURE, + FCS_PRESET_KINGS_ONLY_BAKERS_GAME, + FCS_PRESET_RELAXED_FREECELL, + FCS_PRESET_RELAXED_SEAHAVEN_TOWERS, + FCS_PRESET_SEAHAVEN_TOWERS, + FCS_PRESET_SIMPLE_SIMON, + FCS_PRESET_YUKON, + FCS_PRESET_BELEAGUERED_CASTLE +}; + +static const fcs_preset_t fcs_presets[16] = +{ + { + FCS_PRESET_BAKERS_DOZEN, + 0, + 13, + 1, + + FCS_SEQ_BUILT_BY_RANK, + 0, + FCS_ES_FILLED_BY_NONE, + + "0123456789", + "0123456789", + }, + { + FCS_PRESET_BAKERS_GAME, + 4, + 8, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 0, + FCS_ES_FILLED_BY_ANY_CARD, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_BELEAGUERED_CASTLE, + 0, + 8, + 1, + + FCS_SEQ_BUILT_BY_RANK, + 0, + FCS_ES_FILLED_BY_ANY_CARD, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_CRUEL, + 0, + 12, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 0, + FCS_ES_FILLED_BY_NONE, + + "0123456789", + "0123456789", + }, + { + FCS_PRESET_DER_KATZENSCHWANZ, + 8, + 9, + 2, + + FCS_SEQ_BUILT_BY_ALTERNATE_COLOR, + 1, + FCS_ES_FILLED_BY_NONE, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_DIE_SCHLANGE, + 8, + 9, + 2, + + FCS_SEQ_BUILT_BY_ALTERNATE_COLOR, + 0, + FCS_ES_FILLED_BY_NONE, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_EIGHT_OFF, + 8, + 8, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 0, + FCS_ES_FILLED_BY_KINGS_ONLY, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_FAN, + 0, + 18, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 0, + FCS_ES_FILLED_BY_KINGS_ONLY, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_FORECELL, + 4, + 8, + 1, + + FCS_SEQ_BUILT_BY_ALTERNATE_COLOR, + 0, + FCS_ES_FILLED_BY_KINGS_ONLY, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_FREECELL, + 4, + 8, + 1, + + FCS_SEQ_BUILT_BY_ALTERNATE_COLOR, + 0, + FCS_ES_FILLED_BY_ANY_CARD, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_GOOD_MEASURE, + 0, + 10, + 1, + + FCS_SEQ_BUILT_BY_RANK, + 0, + FCS_ES_FILLED_BY_NONE, + + "0123456789", + "0123456789", + }, + { + FCS_PRESET_KINGS_ONLY_BAKERS_GAME, + 4, + 8, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 0, + FCS_ES_FILLED_BY_KINGS_ONLY, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_RELAXED_FREECELL, + 4, + 8, + 1, + + FCS_SEQ_BUILT_BY_ALTERNATE_COLOR, + 1, + FCS_ES_FILLED_BY_ANY_CARD, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_RELAXED_SEAHAVEN_TOWERS, + 4, + 10, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 1, + FCS_ES_FILLED_BY_KINGS_ONLY, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_SEAHAVEN_TOWERS, + 4, + 10, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 0, + FCS_ES_FILLED_BY_KINGS_ONLY, + + "[01][23456789]", + "0123456789", + }, + { + FCS_PRESET_SIMPLE_SIMON, + 0, + 10, + 1, + + FCS_SEQ_BUILT_BY_SUIT, + 0, + FCS_ES_FILLED_BY_ANY_CARD, + + "abcdefgh", + "abcdefgh", + }, +}; + +struct fcs_preset_name_struct +{ + const char name[32]; + int preset_id; +}; + +typedef struct fcs_preset_name_struct fcs_preset_name_t; + +static const fcs_preset_name_t fcs_preset_names[23] = +{ + { + "bakers_dozen", + FCS_PRESET_BAKERS_DOZEN, + }, + { + "bakers_game", + FCS_PRESET_BAKERS_GAME, + }, + { + "beleaguered_castle", + FCS_PRESET_BELEAGUERED_CASTLE, + }, + { + "citadel", + FCS_PRESET_BELEAGUERED_CASTLE, + }, + { + "cruel", + FCS_PRESET_CRUEL, + }, + { + "der_katzenschwanz", + FCS_PRESET_DER_KATZENSCHWANZ, + }, + { + "der_katz", + FCS_PRESET_DER_KATZENSCHWANZ, + }, + { + "die_schlange", + FCS_PRESET_DIE_SCHLANGE, + }, + { + "eight_off", + FCS_PRESET_EIGHT_OFF, + }, + { + "fan", + FCS_PRESET_FAN, + }, + { + "forecell", + FCS_PRESET_FORECELL, + }, + { + "freecell", + FCS_PRESET_FREECELL, + }, + { + "good_measure", + FCS_PRESET_GOOD_MEASURE, + }, + { + "ko_bakers_game", + FCS_PRESET_KINGS_ONLY_BAKERS_GAME, + }, + { + "kings_only_bakers_game", + FCS_PRESET_KINGS_ONLY_BAKERS_GAME, + }, + { + "relaxed_freecell", + FCS_PRESET_RELAXED_FREECELL, + }, + { + "relaxed_seahaven_towers", + FCS_PRESET_RELAXED_SEAHAVEN_TOWERS, + }, + { + "relaxed_seahaven", + FCS_PRESET_RELAXED_SEAHAVEN_TOWERS, + }, + { + "seahaven_towers", + FCS_PRESET_SEAHAVEN_TOWERS, + }, + { + "seahaven", + FCS_PRESET_SEAHAVEN_TOWERS, + }, + { + "simple_simon", + FCS_PRESET_SIMPLE_SIMON, + }, + { + "streets_and_alleys", + FCS_PRESET_BELEAGUERED_CASTLE, + }, + { + "yukon", + FCS_PRESET_YUKON, + }, +}; + +static int fcs_get_preset_id_by_name( + const char * name +) +{ + int a; + int ret = -1; + int num_elems; + + num_elems = ( (int) (sizeof(fcs_preset_names)/sizeof(fcs_preset_names[0]))); + for(a=0;a<num_elems;a++) + { + if (!strcmp(name, fcs_preset_names[a].name)) + { + ret = fcs_preset_names[a].preset_id; + break; + } + } + + return ret; +} + +static int freecell_solver_char_to_test_num(char c) +{ + if ((c >= '0') && (c <= '9')) + { + return c-'0'; + } + else if ((c >= 'a') && (c <= 'h')) + { + return c-'a'+10; + } + else if ((c >= 'A') && (c <= 'Z')) + { + return c-'A'+18; + } + else + { + return 0; + } +} + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +struct internal_tests_order_struct +{ + int tests_order_num; + int tests_order[FCS_TESTS_NUM]; +}; + +typedef struct internal_tests_order_struct internal_tests_order_t; + +int freecell_solver_apply_tests_order( + fcs_tests_order_t * tests_order, + const char * string, + char * * error_string + ) + +{ + int a; + int len; + int test_index; + int is_group, is_start_group; + if (tests_order->tests) + { + free(tests_order->tests); + tests_order->max_num = 10; + tests_order->num = 0; + tests_order->tests = malloc(sizeof(tests_order->tests[0])*tests_order->max_num ); + } + +#if 0 + instance->tests_order_num = min(strlen(string), FCS_TESTS_NUM); +#endif + len = strlen(string); + test_index = 0; + is_group = 0; + is_start_group = 0; + for(a=0;(a<len) ;a++) + { + if ((string[a] == '(') || (string[a] == '[')) + { + if (is_group) + { + *error_string = strdup("There's a nested random group."); + return 1; + } + is_group = 1; + is_start_group = 1; + continue; + } + + if ((string[a] == ')') || (string[a] == ']')) + { + if (is_start_group) + { + *error_string = strdup("There's an empty group."); + return 2; + } + if (! is_group) + { + *error_string = strdup("There's a renegade right parenthesis or bracket."); + return 3; + } + is_group = 0; + is_start_group = 0; + continue; + } + if (test_index == tests_order->max_num) + { + tests_order->max_num += 10; + tests_order->tests = realloc(tests_order->tests, sizeof(tests_order->tests[0]) * tests_order->max_num); + } + tests_order->tests[test_index] = (freecell_solver_char_to_test_num(string[a])%FCS_TESTS_NUM) | (is_group ? FCS_TEST_ORDER_FLAG_RANDOM : 0) | (is_start_group ? FCS_TEST_ORDER_FLAG_START_RANDOM_GROUP : 0); + + test_index++; + is_start_group = 0; + } + if (a != len) + { + *error_string = strdup("The Input string is too long."); + return 4; + } + + tests_order->num = test_index; + *error_string = NULL; + + return 0; +} + +int freecell_solver_apply_preset_by_ptr( + freecell_solver_instance_t * instance, + const fcs_preset_t * preset_ptr + ) +{ + char * no_use; + +#define preset (*preset_ptr) + if (preset.freecells_num > MAX_NUM_FREECELLS) + { + return FCS_PRESET_CODE_FREECELLS_EXCEED_MAX; + } + if (preset.stacks_num > MAX_NUM_STACKS) + { + return FCS_PRESET_CODE_STACKS_EXCEED_MAX; + } + if (preset.decks_num > MAX_NUM_DECKS) + { + return FCS_PRESET_CODE_DECKS_EXCEED_MAX; + } + instance->freecells_num = preset.freecells_num; + instance->stacks_num = preset.stacks_num; + instance->decks_num = preset.decks_num; + + instance->sequences_are_built_by = preset.sequences_are_built_by; + instance->unlimited_sequence_move = preset.unlimited_sequence_move; + instance->empty_stacks_fill = preset.empty_stacks_fill; + + /* + * This code makes sure that all the tests in all the existing + * soft threads are acceptable by the new preset. + * */ + + { + int ht_idx, st_idx; + for(ht_idx = 0; ht_idx < instance->num_hard_threads ; ht_idx++) + { + for(st_idx = 0; st_idx < instance->hard_threads[ht_idx]->num_soft_threads; st_idx++) + { + freecell_solver_soft_thread_t * soft_thread = instance->hard_threads[ht_idx]->soft_threads[st_idx]; + + int num_valid_tests; + const char * s; + + /* Check every test */ + + for(num_valid_tests=0;num_valid_tests < soft_thread->tests_order.num; num_valid_tests++) + { + for(s = preset.allowed_tests;*s != '\0';s++) + { + /* Check if this test corresponds to this character */ + if ((soft_thread->tests_order.tests[num_valid_tests] & FCS_TEST_ORDER_NO_FLAGS_MASK) == ((freecell_solver_char_to_test_num(*s)%FCS_TESTS_NUM))) + { + break; + } + } + /* If the end of the string was reached, it means + * this test is unacceptable by this preset. */ + if (*s == '\0') + { + break; + } + } + if (num_valid_tests < soft_thread->tests_order.num) + { + freecell_solver_apply_tests_order( + &(soft_thread->tests_order), + preset.tests_order, + &no_use); + } + } + } + } + + /* Assign the master tests order */ + + { + freecell_solver_apply_tests_order( + &(instance->instance_tests_order), + preset.tests_order, + &no_use); + } +#undef preset + return FCS_PRESET_CODE_OK; +} + +static int fcs_get_preset_by_id( + int preset_id, + const fcs_preset_t * * preset_ptr + ) +{ + int preset_index; + int num_elems; + + num_elems = ( (int) (sizeof(fcs_presets)/sizeof(fcs_presets[0]))); + + for(preset_index=0 ; preset_index < num_elems ; preset_index++) + { + if (fcs_presets[preset_index].preset_id == preset_id) + { + *preset_ptr = &(fcs_presets[preset_index]); + return FCS_PRESET_CODE_OK; + } + } + + return FCS_PRESET_CODE_NOT_FOUND; +} + +int freecell_solver_get_preset_by_name( + const char * name, + const fcs_preset_t * * preset_ptr + ) +{ + int preset_id; + + preset_id = fcs_get_preset_id_by_name(name); + if (preset_id >= 0) + { + return fcs_get_preset_by_id( + preset_id, + preset_ptr + ); + } + else + { + return FCS_PRESET_CODE_NOT_FOUND; + } +} + +int freecell_solver_apply_preset_by_name( + freecell_solver_instance_t * instance, + const char * name + ) +{ + int ret; + const fcs_preset_t * preset_ptr; + + ret = freecell_solver_get_preset_by_name( + name, + &preset_ptr + ); + + if (ret != FCS_PRESET_CODE_OK) + { + return ret; + } + + return freecell_solver_apply_preset_by_ptr(instance, preset_ptr); +} |