Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,238 @@
#include <stdio.h>
#include <string.h>
enum HouseStatus { Invalid, Underfull, Valid };
enum Attrib { C, M, D, A, S };
// Unfilled attributes are represented by -1
enum Colors { Red, Green, White, Yellow, Blue };
enum Mans { English, Swede, Dane, German, Norwegian };
enum Drinks { Tea, Coffee, Milk, Beer, Water };
enum Animals { Dog, Birds, Cats, Horse, Zebra };
enum Smokes { PallMall, Dunhill, Blend, BlueMaster, Prince };
void printHouses(int ha[5][5]) {
const char *color[] = { "Red", "Green", "White", "Yellow", "Blue" };
const char *man[] = { "English", "Swede", "Dane", "German", "Norwegian" };
const char *drink[] = { "Tea", "Coffee", "Milk", "Beer", "Water" };
const char *animal[] = { "Dog", "Birds", "Cats", "Horse", "Zebra" };
const char *smoke[] = { "PallMall", "Dunhill", "Blend", "BlueMaster", "Prince" };
printf("%-10.10s%-10.10s%-10.10s%-10.10s%-10.10s%-10.10s\n",
"House", "Color", "Man", "Drink", "Animal", "Smoke");
for (int i = 0; i < 5; i++) {
printf("%-10d", i);
if (ha[i][C] >= 0)
printf("%-10.10s", color[ha[i][C]]);
else
printf("%-10.10s", "-");
if (ha[i][M] >= 0)
printf("%-10.10s", man[ha[i][M]]);
else
printf("%-10.10s", "-");
if (ha[i][D] >= 0)
printf("%-10.10s", drink[ha[i][D]]);
else
printf("%-10.10s", "-");
if (ha[i][A] >= 0)
printf("%-10.10s", animal[ha[i][A]]);
else
printf("%-10.10s", "-");
if (ha[i][S] >= 0)
printf("%-10.10s\n", smoke[ha[i][S]]);
else
printf("-\n");
}
}
int checkHouses(int ha[5][5]) {
int c_add = 0, c_or = 0;
int m_add = 0, m_or = 0;
int d_add = 0, d_or = 0;
int a_add = 0, a_or = 0;
int s_add = 0, s_or = 0;
// Cond 9: In the middle house they drink milk.
if (ha[2][D] >= 0 && ha[2][D] != Milk)
return Invalid;
// Cond 10: The Norwegian lives in the first house.
if (ha[0][M] >= 0 && ha[0][M] != Norwegian)
return Invalid;
for (int i = 0; i < 5; i++) {
// Uniqueness tests.
if (ha[i][C] >= 0) {
c_add += (1 << ha[i][C]);
c_or |= (1 << ha[i][C]);
}
if (ha[i][M] >= 0) {
m_add += (1 << ha[i][M]);
m_or |= (1 << ha[i][M]);
}
if (ha[i][D] >= 0) {
d_add += (1 << ha[i][D]);
d_or |= (1 << ha[i][D]);
}
if (ha[i][A] >= 0) {
a_add += (1 << ha[i][A]);
a_or |= (1 << ha[i][A]);
}
if (ha[i][S] >= 0) {
s_add += (1 << ha[i][S]);
s_or |= (1 << ha[i][S]);
}
// Cond 2: The English man lives in the red house.
if ((ha[i][M] >= 0 && ha[i][C] >= 0) &&
((ha[i][M] == English && ha[i][C] != Red) || // Checking both
(ha[i][M] != English && ha[i][C] == Red))) // to make things quicker.
return Invalid;
// Cond 3: The Swede has a dog.
if ((ha[i][M] >= 0 && ha[i][A] >= 0) &&
((ha[i][M] == Swede && ha[i][A] != Dog) ||
(ha[i][M] != Swede && ha[i][A] == Dog)))
return Invalid;
// Cond 4: The Dane drinks tea.
if ((ha[i][M] >= 0 && ha[i][D] >= 0) &&
((ha[i][M] == Dane && ha[i][D] != Tea) ||
(ha[i][M] != Dane && ha[i][D] == Tea)))
return Invalid;
// Cond 5: The green house is immediately to the left of the white house.
if ((i > 0 && ha[i][C] >= 0 /*&& ha[i-1][C] >= 0 */ ) &&
((ha[i - 1][C] == Green && ha[i][C] != White) ||
(ha[i - 1][C] != Green && ha[i][C] == White)))
return Invalid;
// Cond 6: drink coffee in the green house.
if ((ha[i][C] >= 0 && ha[i][D] >= 0) &&
((ha[i][C] == Green && ha[i][D] != Coffee) ||
(ha[i][C] != Green && ha[i][D] == Coffee)))
return Invalid;
// Cond 7: The man who smokes Pall Mall has birds.
if ((ha[i][S] >= 0 && ha[i][A] >= 0) &&
((ha[i][S] == PallMall && ha[i][A] != Birds) ||
(ha[i][S] != PallMall && ha[i][A] == Birds)))
return Invalid;
// Cond 8: In the yellow house they smoke Dunhill.
if ((ha[i][S] >= 0 && ha[i][C] >= 0) &&
((ha[i][S] == Dunhill && ha[i][C] != Yellow) ||
(ha[i][S] != Dunhill && ha[i][C] == Yellow)))
return Invalid;
// Cond 11: The man who smokes Blend lives in the house next to the house with cats.
if (ha[i][S] == Blend) {
if (i == 0 && ha[i + 1][A] >= 0 && ha[i + 1][A] != Cats)
return Invalid;
else if (i == 4 && ha[i - 1][A] != Cats)
return Invalid;
else if (ha[i + 1][A] >= 0 && ha[i + 1][A] != Cats && ha[i - 1][A] != Cats)
return Invalid;
}
// Cond 12: In a house next to the house where they have a horse, they smoke Dunhill.
if (ha[i][S] == Dunhill) {
if (i == 0 && ha[i + 1][A] >= 0 && ha[i + 1][A] != Horse)
return Invalid;
else if (i == 4 && ha[i - 1][A] != Horse)
return Invalid;
else if (ha[i + 1][A] >= 0 && ha[i + 1][A] != Horse && ha[i - 1][A] != Horse)
return Invalid;
}
// Cond 13: The man who smokes Blue Master drinks beer.
if ((ha[i][S] >= 0 && ha[i][D] >= 0) &&
((ha[i][S] == BlueMaster && ha[i][D] != Beer) ||
(ha[i][S] != BlueMaster && ha[i][D] == Beer)))
return Invalid;
// Cond 14: The German smokes Prince
if ((ha[i][M] >= 0 && ha[i][S] >= 0) &&
((ha[i][M] == German && ha[i][S] != Prince) ||
(ha[i][M] != German && ha[i][S] == Prince)))
return Invalid;
// Cond 15: The Norwegian lives next to the blue house.
if (ha[i][M] == Norwegian &&
((i < 4 && ha[i + 1][C] >= 0 && ha[i + 1][C] != Blue) ||
(i > 0 && ha[i - 1][C] != Blue)))
return Invalid;
// Cond 16: They drink water in a house next to the house where they smoke Blend.
if (ha[i][S] == Blend) {
if (i == 0 && ha[i + 1][D] >= 0 && ha[i + 1][D] != Water)
return Invalid;
else if (i == 4 && ha[i - 1][D] != Water)
return Invalid;
else if (ha[i + 1][D] >= 0 && ha[i + 1][D] != Water && ha[i - 1][D] != Water)
return Invalid;
}
}
if ((c_add != c_or) || (m_add != m_or) || (d_add != d_or)
|| (a_add != a_or) || (s_add != s_or)) {
return Invalid;
}
if ((c_add != 0b11111) || (m_add != 0b11111) || (d_add != 0b11111)
|| (a_add != 0b11111) || (s_add != 0b11111)) {
return Underfull;
}
return Valid;
}
int bruteFill(int ha[5][5], int hno, int attr) {
int stat = checkHouses(ha);
if ((stat == Valid) || (stat == Invalid))
return stat;
int hb[5][5];
memcpy(hb, ha, sizeof(int) * 5 * 5);
for (int i = 0; i < 5; i++) {
hb[hno][attr] = i;
stat = checkHouses(hb);
if (stat != Invalid) {
int nexthno, nextattr;
if (attr < 4) {
nextattr = attr + 1;
nexthno = hno;
} else {
nextattr = 0;
nexthno = hno + 1;
}
stat = bruteFill(hb, nexthno, nextattr);
if (stat != Invalid) {
memcpy(ha, hb, sizeof(int) * 5 * 5);
return stat;
}
}
}
// We only come here if none of the attr values assigned were valid.
return Invalid;
}
int main() {
int ha[5][5] = {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1}};
bruteFill(ha, 0, 0);
printHouses(ha);
return 0;
}

View file

@ -0,0 +1,176 @@
#!/usr/bin/perl
use utf8;
no strict;
my (%props, %name, @pre, @conds, @works, $find_all_solutions);
sub do_consts {
local $";
for my $p (keys %props) {
my @s = @{ $props{$p} };
$" = ", ";
print "enum { ${p}_none = 0, @s };\n";
$" = '", "';
print "const char *string_$p [] = { \"###\", \"@s\" };\n\n";
}
print "#define FIND_BY(p) \\
int find_by_##p(int v) { \\
int i; \\
for (i = 0; i < N_ITEMS; i++) \\
if (house[i].p == v) return i; \\
return -1; }\n";
print "FIND_BY($_)" for (keys %props);
local $" = ", ";
my @k = keys %props;
my $sl = 0;
for (keys %name) {
if (length > $sl) { $sl = length }
}
my $fmt = ("%".($sl + 1)."s ") x @k;
my @arg = map { "string_$_"."[house[i].$_]" } @k;
print << "SNIPPET";
int work0(void) {
int i;
for (i = 0; i < N_ITEMS; i++)
printf("%d $fmt\\n", i, @arg);
puts(\"\");
return 1;
}
SNIPPET
}
sub setprops {
%props = @_;
my $l = 0;
my @k = keys %props;
for my $p (@k) {
my @s = @{ $props{$p} };
if ($l && $l != @s) {
die "bad length @s";
}
$l = @s;
$name{$_} = $p for @s;
}
local $" = ", ";
print "#include <stdio.h>
#define N_ITEMS $l
struct item_t { int @k; } house[N_ITEMS] = {{0}};\n";
}
sub pair {NB. h =.~.&> compose&.>~/y,<h
my ($c1, $c2, $diff) = @_;
$diff //= [0];
$diff = [$diff] unless ref $diff;
push @conds, [$c1, $c2, $diff];
}
sub make_conditions {
my $idx = 0;
my $return1 = $find_all_solutions ? "" : "return 1";
print "
#define TRY(a, b, c, d, p, n) \\
if ((b = a d) >= 0 && b < N_ITEMS) { \\
if (!house[b].p) { \\
house[b].p = c; \\
if (n()) $return1; \\
house[b].p = 0; \\
}}
";
while (@conds) {
my ($c1, $c2, $diff) = @{ pop @conds };
my $p2 = $name{$c2} or die "bad prop $c2";
if ($c1 =~ /^\d+$/) {
push @pre, "house[$c1].$p2 = $c2;";
next;
}
my $p1 = $name{$c1} or die "bad prop $c1";
my $next = "work$idx";
my $this = "work".++$idx;
print "
/* condition pair($c1, $c2, [@$diff]) */
int $this(void) {
int a = find_by_$p1($c1);
int b = find_by_$p2($c2);
if (a != -1 && b != -1) {
switch(b - a) {
";
print "case $_: " for @$diff;
print "return $next(); default: return 0; }\n } if (a != -1) {";
print "TRY(a, b, $c2, +($_), $p2, $next);" for @$diff;
print " return 0; } if (b != -1) {";
print "TRY(b, a, $c1, -($_), $p1, $next);" for @$diff;
print "
return 0; }
/* neither condition is set; try all possibles */
for (a = 0; a < N_ITEMS; a++) {
if (house[a].$p1) continue;
house[a].$p1 = $c1;
";
print "TRY(a, b, $c2, +($_), $p2, $next);" for @$diff;
print " house[a].$p1 = 0; } return 0; }";
}
print "int main() { @pre return !work$idx(); }";
}
sub make_c {
do_consts;
make_conditions;
}
# ---- above should be generic for all similar puzzles ---- #
# ---- below: per puzzle setup ---- #
# property names and values
setprops (
'nationality' # Svensk n. a Swede, not a swede (kålrot).
# AEnglisk (from middle Viking "Æŋløsåksen") n. a Brit.
=> [ qw(Deutsch Svensk Norske Danske AEnglisk) ],
'pet' => [ qw(birds dog horse zebra cats) ],
'drink' => [ qw(water tea milk beer coffee) ],
'smoke' => [ qw(dunhill blue_master prince blend pall_mall) ],
'color' => [ qw(red green yellow white blue) ]
);
# constraints
pair(AEnglisk, red);
pair(Svensk, dog);
pair(Danske, tea);
pair(green, white, 1); # "to the left of" can mean either 1 or -1: ambiguous
pair(coffee, green);
pair(pall_mall, birds);
pair(yellow, dunhill);
pair(2, milk);
pair(0, Norske);
pair(blend, cats, [-1, 1]);
pair(horse, dunhill, [-1, 1]);
pair(blue_master, beer); # Nicht das Deutsche Bier trinken? Huh.
pair(Deutsch, prince);
pair(Norske, blue, [-1, 1]);
pair(water, blend, [-1, 1]);
# "zebra lives *somewhere* relative to the Brit". It has no effect on
# the logic. It's here just to make sure the code will insert a zebra
# somewhere in the table (after all other conditions are met) so the
# final print-out shows it. (the C code can be better structured, but
# meh, I ain't reading it, so who cares).
pair(zebra, AEnglisk, [ -4 .. 4 ]);
# write C code. If it's ugly to you: I didn't write; Perl did.
make_c;