#!/usr/bin/perl -w
use strict;
my %presets =
(
'bakers_game' => [ qw(i freecell sbb suit) ],
'bakers_dozen' => [ qw(s 13 f 0 d 1 sbb rank sm limited esf none to 0123456789 at 0123456789) ],
'beleaguered_castle' => [ qw(i freecell sbb rank f 0) ],
'cruel' => [ qw(i bakers_dozen s 12 sbb suit) ],
'der_katzenschwanz' => [ qw(i die_schlange sm unlimited) ],
'die_schlange' => [ qw(i freecell f 8 s 9 d 2 esf none) ],
'eight_off' => [ qw(i kings_only_bakers_game f 8) ],
'fan' => [ qw(i freecell s 18 sbb suit sm limited esf kings_only f 0) ],
'forecell' => [ qw(i freecell esf kings_only) ],
'freecell' => [ qw(s 8 f 4 d 1 sbb ac sm limited esf any_card to [01][23456789] at 0123456789) ],
'good_measure' => [ qw(i bakers_dozen s 10) ],
'kings_only_bakers_game' => [ qw(i bakers_game esf kings_only) ],
'relaxed_freecell' => [ qw(i freecell sm unlimited) ],
'relaxed_seahaven_towers' => [ qw(i seahaven_towers sm unlimited) ],
'seahaven_towers' => [ qw(i bakers_game esf kings_only s 10) ],
'simple_simon' => [ qw(i bakers_game s 10 f 0 to abcdefgh at abcdefgh) ],
# 'yukon' => [ qw(i freecell s 7 f 0 to ABCDEFG) ],
);
my @strings;
sub compile_preset
{
my $preset_name = shift;
my $preset = $presets{$preset_name};
# For inheritance
my $compiled = shift || {};
my @params = @{$preset};
my ($cmd, $arg);
eval {
while ($cmd = shift(@params))
{
$arg = shift(@params);
if ($cmd =~ /^(i|inherits?)$/)
{
if (!exists($presets{$arg}))
{
die "Unknown inheritor!\n";
}
compile_preset($arg, $compiled);
}
elsif ($cmd =~ /^(s|stacks?)$/)
{
if ($arg !~ /^(\d+)$/)
{
die "Argument to stacks is not an integer!\n";
}
$compiled->{'stacks'} = $arg;
}
elsif ($cmd =~ /^(f|freecells?)$/)
{
if ($arg !~ /^(\d+)$/)
{
die "Argument to freecells is not an integer!\n";
}
$compiled->{'freecells'} = $arg;
}
elsif ($cmd =~ /^(d|decks?)$/)
{
if ($arg !~ /^(1|2)$/)
{
die "Argument to decks is not 1 or 2!\n";
}
$compiled->{'decks'} = $arg;
}
elsif ($cmd =~ /^(sbb|seqs_build_by)$/)
{
if ($arg !~ /^(ac|suit|rank)$/)
{
die "Argument to stacks_build_by is improper!\n";
}
$compiled->{'seqs_build_by'} = $arg;
}
elsif ($cmd =~ /^(sm|(seq|sequence)_move)$/)
{
if ($arg !~ /^(limited|unlimited)$/)
{
die "Argument to sequence move is not limited/unlimited!\n";
}
$compiled->{'sequence_move'} = (($arg eq "unlimited")?1:0);
}
elsif ($cmd =~ /^(esf|empty_stacks_fill(ed(_by)?)?)$/)
{
if ($arg !~ /^(any_card|kings_only|none)$/)
{
die "Improper parameter to Empty Stacks Filled By!\n";
}
$compiled->{'empty_stacks_fill'} = $arg;
}
elsif ($cmd =~ /^(to|tests_order)$/)
{
if ($arg =~ /[^0-9a-hA-G\[\(\)\]]/)
{
die "Unrecognized character in Tests order!\n";
}
$compiled->{'tests_order'} = $arg;
}
elsif ($cmd =~ /^(at|allowed_tests)$/)
{
if ($arg =~ /[^0-9a-hA-G]/)
{
die "Unrecognized character in Allowed Tests!\n";
}
$compiled->{'allowed_tests'} = $arg;
}
else
{
die "Unknown Command $cmd\n";
}
}
};
if ($@)
{
die "Preset Name: $preset_name\n$@";
}
return $compiled;
}
sub preset_to_string
{
my $preset_name = shift;
my $pc = shift;
my @lines = ();
my $arg;
eval
{
push @lines, ("FCS_PRESET_" . uc($preset_name));
if (!exists($pc->{'freecells'}))
{
die "Freecells were not defined!\n";
}
push @lines, $pc->{'freecells'};
if (!exists($pc->{'stacks'}))
{
die "Stacks were not defined!\n";
}
push @lines, $pc->{'stacks'};
if (!exists($pc->{'decks'}))
{
die "Decks Number was not defined!\n";
}
push @lines, $pc->{'decks'};
if (!exists($pc->{'seqs_build_by'}))
{
die "Seqs Build by was not defined!\n";
}
$arg = $pc->{'seqs_build_by'};
push @lines, ("FCS_SEQ_BUILT_BY_". (($arg eq "ac") ? "ALTERNATE_COLOR" : ($arg eq "suit") ? "SUIT" : "RANK"));
if (!exists($pc->{'sequence_move'}))
{
die "Sequence move was not defined!\n";
}
push @lines, $pc->{'sequence_move'};
if (!exists($pc->{'empty_stacks_fill'}))
{
die "Empty Stacks Fill is undefined!\n";
}
$arg = $pc->{'empty_stacks_fill'};
push @lines, "FCS_ES_FILLED_BY_" . (($arg eq "none") ? "NONE" : ($arg eq "any_card") ? "ANY_CARD" : "KINGS_ONLY");
if (!exists($pc->{'tests_order'}))
{
die "Tests order is undefined!\n";
}
push @lines, "\"" . $pc->{'tests_order'} . "\"";
if (!exists($pc->{'allowed_tests'}))
{
die "Allowed Tests' is undefined!\n";
}
push @lines, "\"" . $pc->{'allowed_tests'} . "\"";
};
if ($@)
{
die "Preset name: $preset_name\n$@\n";
}
my @lines_p = (map { " $_," } @lines);
my @lines_with_spaces = (@lines_p[0 .. 3], "", @lines_p[4 .. 6], "", @lines_p[7 .. $#lines_p]);
return " {\n" . join("\n", @lines_with_spaces) . "\n" . " },\n";
}
sub preset_to_docbook_string
{
my $preset_name = shift;
my $pc = shift;
my @lines;
push @lines, join(" ", (map { ucfirst($_) } split(/_/, $preset_name)));
push @lines, ($pc->{'stacks'}, $pc->{'freecells'}, $pc->{'decks'});
my $sbb = $pc->{'seqs_build_by'};
push @lines,
(($sbb eq "ac") ? "Alternate Colour" :
($sbb eq "suit") ? "Suit" :
"Rank");
my $arg = $pc->{'empty_stacks_fill'};
push @lines, (($arg eq "none") ? "None" : ($arg eq "any_card") ? "Any Card" : "Kings Only");
push @lines, ($pc->{'sequence_move'} ? "Limited" : "Unlimited");
return join("", map { " $_\n" } @lines);
}
my $docbook = 0;
if ($ARGV[0] = "--docbook")
{
$docbook = 1;
}
foreach my $preset_name (sort {$a cmp $b } keys(%presets))
{
if ($docbook && ($preset_name eq "simple_simon"))
{
next;
}
my $preset_compiled = compile_preset($preset_name);
push @strings, ($docbook ? \&preset_to_docbook_string : \&preset_to_string)->($preset_name, $preset_compiled);
}
if ($docbook)
{
print join("", map { "\n$_
\n" } @strings);
}
else
{
print "static const fcs_preset_t fcs_presets[" . scalar(@strings) . "] = \n";
print "{\n";
print join("", @strings);
print "};\n";
}