// L'enigme d'Einstein : 5 maisons, 5 attributs, 15 indices.
// Encodage par position : chaque champ = numero de maison (0..4) ou la valeur apparait.
public class Einstein
{
// Nationalites
public int Brit = 0, Swede = 0, Dane = 0, Norwegian = 0, German = 0;
// Couleurs
public int Red = 0, Green = 0, White = 0, Yellow = 0, Blue = 0;
// Boissons
public int Tea = 0, Coffee = 0, Milk = 0, Water = 0, Beer = 0;
// Cigarettes
public int PallMall = 0, Dunhill = 0, Blend = 0, BlueMaster = 0, Prince = 0;
// Animaux
public int Dog = 0, Bird = 0, Cat = 0, Horse = 0, Fish = 0;
}
using (var ctx = new Z3Context())
{
var th = ctx.NewTheorem<Einstein>();
// (1) Domaine 0..4 pour les 25 variables
th = th.Where(t =>
t.Brit>=0&&t.Brit<=4 && t.Swede>=0&&t.Swede<=4 && t.Dane>=0&&t.Dane<=4 && t.Norwegian>=0&&t.Norwegian<=4 && t.German>=0&&t.German<=4 &&
t.Red>=0&&t.Red<=4 && t.Green>=0&&t.Green<=4 && t.White>=0&&t.White<=4 && t.Yellow>=0&&t.Yellow<=4 && t.Blue>=0&&t.Blue<=4 &&
t.Tea>=0&&t.Tea<=4 && t.Coffee>=0&&t.Coffee<=4 && t.Milk>=0&&t.Milk<=4 && t.Water>=0&&t.Water<=4 && t.Beer>=0&&t.Beer<=4 &&
t.PallMall>=0&&t.PallMall<=4 && t.Dunhill>=0&&t.Dunhill<=4 && t.Blend>=0&&t.Blend<=4 && t.BlueMaster>=0&&t.BlueMaster<=4 && t.Prince>=0&&t.Prince<=4 &&
t.Dog>=0&&t.Dog<=4 && t.Bird>=0&&t.Bird<=4 && t.Cat>=0&&t.Cat<=4 && t.Horse>=0&&t.Horse<=4 && t.Fish>=0&&t.Fish<=4);
// (2) Permutation : 5 groupes Distinct (chaque attribut occupe les 5 maisons)
th = th.Where(t => Z3Methods.Distinct(t.Brit, t.Swede, t.Dane, t.Norwegian, t.German));
th = th.Where(t => Z3Methods.Distinct(t.Red, t.Green, t.White, t.Yellow, t.Blue));
th = th.Where(t => Z3Methods.Distinct(t.Tea, t.Coffee, t.Milk, t.Water, t.Beer));
th = th.Where(t => Z3Methods.Distinct(t.PallMall, t.Dunhill, t.Blend, t.BlueMaster, t.Prince));
th = th.Where(t => Z3Methods.Distinct(t.Dog, t.Bird, t.Cat, t.Horse, t.Fish));
// (3) Les 15 indices
th = th.Where(t => t.Brit == t.Red); // 1. Le Britannique vit dans la maison rouge
th = th.Where(t => t.Swede == t.Dog); // 2. le Suedois eleve des chiens
th = th.Where(t => t.Dane == t.Tea); // 3. le Danois boit du the
th = th.Where(t => t.Green == t.White - 1); // 4. la verte est juste a gauche de la blanche
th = th.Where(t => t.Green == t.Coffee); // 5. le proprietaire de la verte boit du cafe
th = th.Where(t => t.PallMall == t.Bird); // 6. fumeur de Pall Mall eleve des oiseaux
th = th.Where(t => t.Yellow == t.Dunhill); // 7. la jaune fume du Dunhill
th = th.Where(t => t.Milk == 2); // 8. la maison du milieu boit du lait
th = th.Where(t => t.Norwegian == 0); // 9. le Norvegien vit dans la 1ere maison
th = th.Where(t => (t.Blend - t.Cat == 1) || (t.Cat - t.Blend == 1)); // 10. Blend voisin du Chat
th = th.Where(t => (t.Horse - t.Dunhill == 1) || (t.Dunhill - t.Horse == 1)); // 11. Cheval voisin du Dunhill
th = th.Where(t => t.BlueMaster == t.Beer); // 12. fumeur de BlueMaster boit de la biere
th = th.Where(t => t.German == t.Prince); // 13. l'Allemand fume du Prince
th = th.Where(t => (t.Norwegian - t.Blue == 1) || (t.Blue - t.Norwegian == 1)); // 14. Norvegien voisin de la bleue
th = th.Where(t => (t.Blend - t.Water == 1) || (t.Water - t.Blend == 1)); // 15. Blend voisin de l'Eau
var sol = th.Solve();
if (sol == null) {
Console.WriteLine("UNSAT : aucune solution (inattendu pour cette enigme)");
} else {
// Inversion : pour chaque maison h, quelle valeur de chaque attribut y est ?
var nat = new[]{("Britannique",sol.Brit),("Suedois",sol.Swede),("Danois",sol.Dane),("Norvegien",sol.Norwegian),("Allemand",sol.German)};
var col = new[]{("Rouge",sol.Red),("Verte",sol.Green),("Blanche",sol.White),("Jaune",sol.Yellow),("Bleue",sol.Blue)};
var drk = new[]{("The",sol.Tea),("Cafe",sol.Coffee),("Lait",sol.Milk),("Eau",sol.Water),("Biere",sol.Beer)};
var smk = new[]{("Pall Mall",sol.PallMall),("Dunhill",sol.Dunhill),("Blend",sol.Blend),("BlueMaster",sol.BlueMaster),("Prince",sol.Prince)};
var pet = new[]{("Chien",sol.Dog),("Oiseau",sol.Bird),("Chat",sol.Cat),("Cheval",sol.Horse),("Poisson",sol.Fish)};
string Val((string,int)[] arr, int h) => arr.First(p => p.Item2 == h).Item1;
Console.WriteLine($"{"Maison",-10}{"Nationalite",-14}{"Couleur",-10}{"Boisson",-10}{"Cigarette",-14}{"Animal",-10}");
Console.WriteLine(new string('-', 68));
for (int h = 0; h < 5; h++) {
Console.WriteLine($"{h+1,-10}{Val(nat,h),-14}{Val(col,h),-10}{Val(drk,h),-10}{Val(smk,h),-14}{Val(pet,h),-10}");
}
Console.WriteLine();
Console.WriteLine($">>> Reponse : le {Val(nat, sol.Fish)} possede le Poisson (maison {sol.Fish+1}).");
}
}