summaryrefslogtreecommitdiffstats
path: root/kpat/freecell-solver/preset.c
diff options
context:
space:
mode:
Diffstat (limited to 'kpat/freecell-solver/preset.c')
-rw-r--r--kpat/freecell-solver/preset.c637
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);
+}