You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/kpat/freecell-solver/preset.c

638 lines
13 KiB

/*
* 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);
}