<div class="notebook"> <div class="nb-cell program" name="p1"> puzzle(Table) :- Table = [row(_, 0, canary), % The canary owner lives on floor 0. row(_, 1, snake), % The snake owner lives on floor 1. row(_, 2, dog), % The dog owner lives on floor 2. row(_, 3, hamster), % The hamster owner lives on floor 3. row(_, 4, fish), % The owner of the fish lives on floor 4. row(_, 5, cat), % The cat owner lives on floor 5. row(_, 6, parrot)], % The owner of the parrot lives on floor 6. memberchk(row('Frank', LFrank, AFrank), Table), memberchk(row('Albert', LAlbert, AAlbert), Table), memberchk(row('Robert', LRobert, ARobert), Table), memberchk(row('Stefanie', LStefanie, AStefanie), Table), memberchk(row('Simon', LSimon, ASimon), Table), memberchk(row('Jarek', LJarek, AJarek), Table), memberchk(row('Marcin', LMarcin, AMarcin), Table), % Frank has no snake. % Frank doesn’t have a dog. % Frank doesn’t have a hamster. % Franek has no fish. % Frank doesn’t have a cat. % Franek doesn’t have a parrot. \+ memberchk(AFrank, [snake, dog, hamster, fish, cat, parrot]), % Albert doesn’t have a canary. % Albert doesn’t have a dog. % Albert doesn’t have a hamster. % Albert has no fish. % Albert doesn’t have a cat. % Albert doesn’t have a parrot. \+ memberchk(AAlbert, [canary, dog, hamster, fish, cat, parrot]), % Robert has no hamsters. % Robert has no fish. % Robert doesn’t have a cat. \+ memberchk(ARobert, [hamster, fish, cat]), % Stefan doesn’t have a canary. % Stefan has no snake. % Stefan doesn’t have a dog. % Stefan has no fish. % Stefan doesn’t have a cat. % Stefan doesn’t have a parrot. \+ memberchk(AStefanie, [canary, snake, dog, fish, cat, parrot]), % Simon doesn’t have a canary. % Simon has no snake. % Simon doesn’t have a dog. % Simon doesn’t have a hamster. % Simon doesn’t have a cat. % Simon doesn’t have a parrot. \+ memberchk(ASimon, [canary, snake, dog, hamster, cat, parrot]), % Jarek doesn’t have a dog. % Jarek doesn’t have a parrot. \+ memberchk(AJarek, [dog, parrot]), % Marcin doesn’t have a snake. % Marcin doesn’t have a dog. % Marcin has no fish. \+ memberchk(AMarcin, [snake, dog, fish]), LFrank < LAlbert, % Frank lives lower than Albert. LFrank < LRobert, % Franek lives lower than Robert. LFrank < LStefanie, % Stefan lives higher than Franek. LFrank < LSimon, % Franek lives lower than Szymon. LFrank < LJarek, % Jarek lives higher than Franek. LFrank < LMarcin, % Franek lives lower than Marcin. LAlbert < LRobert, % Robert lives higher than Albert. LAlbert < LStefanie, % Albert lives lower than Stefan. LAlbert < LSimon, % Simon lives higher than Albert. LAlbert < LJarek, % Jarek lives higher than Albert. LAlbert < LMarcin, % Marcin lives higher than Albert. LRobert < LStefanie, % Robert lives lower than Stefan. LRobert < LSimon, % Robert lives lower than Simon. LRobert < LJarek, % Jarek lives higher than Robert. LRobert < LMarcin, % Marcin lives higher than Robert. LStefanie < LSimon, % Szymon lives higher than Stefan. LStefanie < LJarek, % Stefan lives lower than Jarek. LStefanie < LMarcin, % Stefan lives lower than Marcin. LSimon < LJarek, % Szymon lives lower than Jarek. LSimon < LMarcin, % Szymon lives lower than Marcin. LJarek < LMarcin. % Marcin lives higher than Jarek. </div> <div class="nb-cell query" data-chunk="10" data-tabled="true" name="q1"> puzzle(_Table), member(row(Name, Floor, Pet), _Table). </div> <div class="nb-cell markdown" name="md1"> To illustrate [freeze(+Var, :Goal)](https://www.swi-prolog.org/pldoc/doc_for?object=freeze/2), which is one of Prolog's [coroutining](https://www.swi-prolog.org/pldoc/man?section=coroutining) clauses, here's a way of putting the negated memberchks before their variables have been set: </div> <div class="nb-cell program" name="p2"> puzzle(Table) :- freeze(AFrank, \+ memberchk(AFrank, [snake, dog, hamster, fish, cat, parrot])), freeze(AAlbert, \+ memberchk(AAlbert, [canary, dog, hamster, fish, cat, parrot])), freeze(ARobert, \+ memberchk(ARobert, [hamster, fish, cat])), freeze(AStefanie, \+ memberchk(AStefanie, [canary, snake, dog, fish, cat, parrot])), freeze(ASimon, \+ memberchk(ASimon, [canary, snake, dog, hamster, cat, parrot])), freeze(AJarek, \+ memberchk(AJarek, [dog, parrot])), freeze(AMarcin, \+ memberchk(AMarcin, [snake, dog, fish])), Table = [row(_, 0, canary), % The canary owner lives on floor 0. row(_, 1, snake), % The snake owner lives on floor 1. row(_, 2, dog), % The dog owner lives on floor 2. row(_, 3, hamster), % The hamster owner lives on floor 3. row(_, 4, fish), % The owner of the fish lives on floor 4. row(_, 5, cat), % The cat owner lives on floor 5. row(_, 6, parrot)], % The owner of the parrot lives on floor 6. memberchk(row('Frank', LFrank, AFrank), Table), memberchk(row('Albert', LAlbert, AAlbert), Table), memberchk(row('Robert', LRobert, ARobert), Table), memberchk(row('Stefanie', LStefanie, AStefanie), Table), memberchk(row('Simon', LSimon, ASimon), Table), memberchk(row('Jarek', LJarek, AJarek), Table), memberchk(row('Marcin', LMarcin, AMarcin), Table), LFrank < LAlbert, % Frank lives lower than Albert. LFrank < LRobert, % Franek lives lower than Robert. LFrank < LStefanie, % Stefan lives higher than Franek. LFrank < LSimon, % Franek lives lower than Szymon. LFrank < LJarek, % Jarek lives higher than Franek. LFrank < LMarcin, % Franek lives lower than Marcin. LAlbert < LRobert, % Robert lives higher than Albert. LAlbert < LStefanie, % Albert lives lower than Stefan. LAlbert < LSimon, % Simon lives higher than Albert. LAlbert < LJarek, % Jarek lives higher than Albert. LAlbert < LMarcin, % Marcin lives higher than Albert. LRobert < LStefanie, % Robert lives lower than Stefan. LRobert < LSimon, % Robert lives lower than Simon. LRobert < LJarek, % Jarek lives higher than Robert. LRobert < LMarcin, % Marcin lives higher than Robert. LStefanie < LSimon, % Szymon lives higher than Stefan. LStefanie < LJarek, % Stefan lives lower than Jarek. LStefanie < LMarcin, % Stefan lives lower than Marcin. LSimon < LJarek, % Szymon lives lower than Jarek. LSimon < LMarcin, % Szymon lives lower than Marcin. LJarek < LMarcin. % Marcin lives higher than Jarek. </div> <div class="nb-cell query" data-chunk="7" data-tabled="true" name="q2"> puzzle(_Table), member(row(Name, Floor, Pet), _Table). </div> <div class="nb-cell markdown" name="md2"> Coroutining the inequality tests can prune the search space significantly, according to this [SWI-Prolog discourse post](https://swi-prolog.discourse.group/t/different-version-of-einstein-riddle/5880/10). Getting this to work introduced me to the [when(@Condition, :Goal)](https://www.swi-prolog.org/pldoc/doc_for?object=when/2) clause. I initially tried to do this using ```prolog freeze([LFrank, LAlbert], LFrank < LAlbert) ``` but thanks to [this post](https://swi-prolog.discourse.group/t/different-version-of-einstein-riddle/5880/10) discovered grouping variables in the first argument of freeze/2 can't be done, but can with when/2 and [ground(@Term)](https://www.swi-prolog.org/pldoc/doc_for?object=ground/1) </div> <div class="nb-cell program" name="p3"> puzzle(Table) :- when(ground([LFrank, LAlbert]), LFrank < LAlbert), % Frank lives lower than Albert. when(ground([LFrank, LRobert]),LFrank < LRobert), % Franek lives lower than Robert. when(ground([LFrank, LStefanie]),LFrank < LStefanie), % Stefan lives higher than Franek. when(ground([LFrank, LSimon]),LFrank < LSimon), % Franek lives lower than Szymon. when(ground([LFrank, LJarek]),LFrank < LJarek), % Jarek lives higher than Franek. when(ground([LFrank, LMarcin]),LFrank < LMarcin), % Franek lives lower than Marcin. when(ground([LAlbert, LRobert]),LAlbert < LRobert), % Robert lives higher than Albert. when(ground([LAlbert, LStefanie]),LAlbert < LStefanie), % Albert lives lower than Stefan. when(ground([LAlbert, LSimon]),LAlbert < LSimon), % Simon lives higher than Albert. when(ground([LAlbert, LJarek]),LAlbert < LJarek), % Jarek lives higher than Albert. when(ground([LAlbert, LMarcin]),LAlbert < LMarcin), % Marcin lives higher than Albert. when(ground([LRobert, LStefanie]),LRobert < LStefanie), % Robert lives lower than Stefan. when(ground([LRobert, LSimon]),LRobert < LSimon), % Robert lives lower than Simon. when(ground([LRobert, LJarek]),LRobert < LJarek), % Jarek lives higher than Robert. when(ground([LRobert, LMarcin]),LRobert < LMarcin), % Marcin lives higher than Robert. when(ground([LStefanie, LSimon]),LStefanie < LSimon), % Szymon lives higher than Stefan. when(ground([LStefanie, LJarek]),LStefanie < LJarek), % Stefan lives lower than Jarek. when(ground([LStefanie, LMarcin]),LStefanie < LMarcin), % Stefan lives lower than Marcin. when(ground([LSimon, LJarek]),LSimon < LJarek), % Szymon lives lower than Jarek. when(ground([LSimon, LMarcin]),LSimon < LMarcin), % Szymon lives lower than Marcin. when(ground([LJarek, LMarcin]),LJarek < LMarcin), % Marcin lives higher than Jarek. freeze(AFrank, \+ memberchk(AFrank, [snake, dog, hamster, fish, cat, parrot])), freeze(AAlbert, \+ memberchk(AAlbert, [canary, dog, hamster, fish, cat, parrot])), freeze(ARobert, \+ memberchk(ARobert, [hamster, fish, cat])), freeze(AStefanie, \+ memberchk(AStefanie, [canary, snake, dog, fish, cat, parrot])), freeze(ASimon, \+ memberchk(ASimon, [canary, snake, dog, hamster, cat, parrot])), freeze(AJarek, \+ memberchk(AJarek, [dog, parrot])), freeze(AMarcin, \+ memberchk(AMarcin, [snake, dog, fish])), Table = [row(_, 0, canary), % The canary owner lives on floor 0. row(_, 1, snake), % The snake owner lives on floor 1. row(_, 2, dog), % The dog owner lives on floor 2. row(_, 3, hamster), % The hamster owner lives on floor 3. row(_, 4, fish), % The owner of the fish lives on floor 4. row(_, 5, cat), % The cat owner lives on floor 5. row(_, 6, parrot)], % The owner of the parrot lives on floor 6. memberchk(row('Frank', LFrank, AFrank), Table), memberchk(row('Albert', LAlbert, AAlbert), Table), memberchk(row('Robert', LRobert, ARobert), Table), memberchk(row('Stefanie', LStefanie, AStefanie), Table), memberchk(row('Simon', LSimon, ASimon), Table), memberchk(row('Jarek', LJarek, AJarek), Table), memberchk(row('Marcin', LMarcin, AMarcin), Table). </div> <div class="nb-cell query" data-chunk="7" data-tabled="true" name="q3"> puzzle(_Table), member(row(Name, Floor, Pet), _Table). </div> </div>