/* * preset.c - game presets management for Freecell Solver * * Written by Shlomi Fish (shlomif@vipe.technion.ac.il), 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); }