164 lines
6.2 KiB
JavaScript
164 lines
6.2 KiB
JavaScript
// Define enums and their string representations
|
|
const Attrib = { Color: 0, Man: 1, Drink: 2, Animal: 3, Smoke: 4 };
|
|
const Attrib_str = ["Color", "Man", "Drink", "Animal", "Smoke"];
|
|
|
|
const Colors = { Red: 0, Green: 1, White: 2, Yellow: 3, Blue: 4 };
|
|
const Colors_str = ["Red", "Green", "White", "Yellow", "Blue"];
|
|
|
|
const Mans = { English: 0, Swede: 1, Dane: 2, German: 3, Norwegian: 4 };
|
|
const Mans_str = ["English", "Swede", "Dane", "German", "Norwegian"];
|
|
|
|
const Drinks = { Tea: 0, Coffee: 1, Milk: 2, Beer: 3, Water: 4 };
|
|
const Drinks_str = ["Tea", "Coffee", "Milk", "Beer", "Water"];
|
|
|
|
const Animals = { Dog: 0, Birds: 1, Cats: 2, Horse: 3, Zebra: 4 };
|
|
const Animals_str = ["Dog", "Birds", "Cats", "Horse", "Zebra"];
|
|
|
|
const Smokes = { PallMall: 0, Dunhill: 1, Blend: 2, BlueMaster: 3, Prince: 4 };
|
|
const Smokes_str = ["PallMall", "Dunhill", "Blend", "BlueMaster", "Prince"];
|
|
|
|
function printHouses(ha) {
|
|
const attr_names = [Colors_str, Mans_str, Drinks_str, Animals_str, Smokes_str];
|
|
|
|
let output = "House".padEnd(10);
|
|
for (const name of Attrib_str) {
|
|
output += name.padEnd(10);
|
|
}
|
|
console.log(output);
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
output = String(i).padEnd(10);
|
|
for (let j = 0; j < 5; j++) {
|
|
output += attr_names[j][ha[i][j]].padEnd(10);
|
|
}
|
|
console.log(output);
|
|
}
|
|
}
|
|
|
|
// House number specific rules
|
|
const housenos = [
|
|
{ houseno: 2, a: Attrib.Drink, v: Drinks.Milk }, // Cond 9: In the middle house they drink milk.
|
|
{ houseno: 0, a: Attrib.Man, v: Mans.Norwegian } // Cond 10: The Norwegian lives in the first house.
|
|
];
|
|
|
|
// Attribute pair rules
|
|
const pairs = [
|
|
{ a1: Attrib.Man, v1: Mans.English, a2: Attrib.Color, v2: Colors.Red }, // Cond 2: The English man lives in the red house.
|
|
{ a1: Attrib.Man, v1: Mans.Swede, a2: Attrib.Animal, v2: Animals.Dog }, // Cond 3: The Swede has a dog.
|
|
{ a1: Attrib.Man, v1: Mans.Dane, a2: Attrib.Drink, v2: Drinks.Tea }, // Cond 4: The Dane drinks tea.
|
|
{ a1: Attrib.Color, v1: Colors.Green, a2: Attrib.Drink, v2: Drinks.Coffee }, // Cond 6: drink coffee in the green house.
|
|
{ a1: Attrib.Smoke, v1: Smokes.PallMall, a2: Attrib.Animal, v2: Animals.Birds }, // Cond 7: The man who smokes Pall Mall has birds.
|
|
{ a1: Attrib.Smoke, v1: Smokes.Dunhill, a2: Attrib.Color, v2: Colors.Yellow }, // Cond 8: In the yellow house they smoke Dunhill.
|
|
{ a1: Attrib.Smoke, v1: Smokes.BlueMaster, a2: Attrib.Drink, v2: Drinks.Beer }, // Cond 13: The man who smokes Blue Master drinks beer.
|
|
{ a1: Attrib.Man, v1: Mans.German, a2: Attrib.Smoke, v2: Smokes.Prince } // Cond 14: The German smokes Prince
|
|
];
|
|
|
|
// Next to rules
|
|
const nexttos = [
|
|
{ a1: Attrib.Smoke, v1: Smokes.Blend, a2: Attrib.Animal, v2: Animals.Cats }, // Cond 11: The man who smokes Blend lives in the house next to the house with cats.
|
|
{ a1: Attrib.Smoke, v1: Smokes.Dunhill, a2: Attrib.Animal, v2: Animals.Horse }, // Cond 12: In a house next to the house where they have a horse, they smoke Dunhill.
|
|
{ a1: Attrib.Man, v1: Mans.Norwegian, a2: Attrib.Color, v2: Colors.Blue }, // Cond 15: The Norwegian lives next to the blue house.
|
|
{ a1: Attrib.Smoke, v1: Smokes.Blend, a2: Attrib.Drink, v2: Drinks.Water } // Cond 16: They drink water in a house next to the house where they smoke Blend.
|
|
];
|
|
|
|
// Left of rules
|
|
const leftofs = [
|
|
{ a1: Attrib.Color, v1: Colors.Green, a2: Attrib.Color, v2: Colors.White } // Cond 5: The green house is immediately to the left of the white house.
|
|
];
|
|
|
|
function invalid(ha) {
|
|
// Check leftofs global rules
|
|
for (const rule of leftofs) {
|
|
if (ha[0][rule.a2] === rule.v2 || ha[4][rule.a1] === rule.v1) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check rules for each house
|
|
for (let i = 0; i < 5; i++) {
|
|
// Check pair rules
|
|
for (const rule of pairs) {
|
|
if (ha[i][rule.a1] >= 0 && ha[i][rule.a2] >= 0 &&
|
|
((ha[i][rule.a1] === rule.v1 && ha[i][rule.a2] !== rule.v2) ||
|
|
(ha[i][rule.a1] !== rule.v1 && ha[i][rule.a2] === rule.v2))) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check next to rules
|
|
for (const rule of nexttos) {
|
|
if (ha[i][rule.a1] === rule.v1) {
|
|
if (i === 0 && ha[i + 1][rule.a2] >= 0 && ha[i + 1][rule.a2] !== rule.v2) {
|
|
return true;
|
|
} else if (i === 4 && ha[i - 1][rule.a2] !== rule.v2) {
|
|
return true;
|
|
} else if (i > 0 && i < 4 &&
|
|
ha[i + 1][rule.a2] >= 0 && ha[i + 1][rule.a2] !== rule.v2 &&
|
|
ha[i - 1][rule.a2] !== rule.v2) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check left of rules for this house
|
|
for (const rule of leftofs) {
|
|
if (i > 0 && ha[i][rule.a1] >= 0 &&
|
|
((ha[i - 1][rule.a1] === rule.v1 && ha[i][rule.a2] !== rule.v2) ||
|
|
(ha[i - 1][rule.a1] !== rule.v1 && ha[i][rule.a2] === rule.v2))) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function search(used, ha, hno, attr) {
|
|
let nexthno, nextattr;
|
|
if (attr < 4) {
|
|
nextattr = attr + 1;
|
|
nexthno = hno;
|
|
} else {
|
|
nextattr = 0;
|
|
nexthno = hno + 1;
|
|
}
|
|
|
|
if (ha[hno][attr] !== -1) {
|
|
search(used, ha, nexthno, nextattr);
|
|
} else {
|
|
for (let i = 0; i < 5; i++) {
|
|
if (used[attr][i]) continue;
|
|
used[attr][i] = true;
|
|
ha[hno][attr] = i;
|
|
|
|
if (!invalid(ha)) {
|
|
if (hno === 4 && attr === 4) {
|
|
printHouses(ha);
|
|
} else {
|
|
search(used, ha, nexthno, nextattr);
|
|
}
|
|
}
|
|
|
|
used[attr][i] = false;
|
|
ha[hno][attr] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
// Initialize arrays
|
|
const used = Array(5).fill().map(() => Array(5).fill(false));
|
|
const ha = Array(5).fill().map(() => Array(5).fill(-1));
|
|
|
|
// Apply house number specific rules
|
|
for (const rule of housenos) {
|
|
ha[rule.houseno][rule.a] = rule.v;
|
|
used[rule.a][rule.v] = true;
|
|
}
|
|
|
|
// Start the search
|
|
search(used, ha, 0, 0);
|
|
}
|
|
|
|
// Run the program
|
|
main();
|