Zebra puzzle: Difference between revisions

277,856 bytes added ,  10 days ago
Added Uiua solution
(added J)
(Added Uiua solution)
 
(326 intermediate revisions by 70 users not shown)
Line 1:
[[File:zebra.png|right]]
{{task|Logic puzzles}}
{{task|Puzzles}}
The [[wp:Zebra puzzle|Zebra puzzle]], a.k.a. Einstein's Riddle, is a logic puzzle which is to be solved programmatically. It has several variants, one of them this:
[[Category:CHR]]
[[Category:Puzzles]]
 
The [[wp:Zebra puzzle|Zebra puzzle]], a.k.a. Einstein's Riddle,
#There are five houses.
is a logic puzzle which is to be solved programmatically.
#The English man lives in the red house.
#The Swede has a dog.
#The Dane drinks tea.
#The green house is immediately to the left of the white house.
#They drink coffee in the green house.
#The man who smokes Pall Mall has birds.
#In the yellow house they smoke Dunhill.
#In the middle house they drink milk.
#The Norwegian lives in the first house.
#The man who smokes Blend lives in the house next to the house with cats.
#In a house next to the house where they have a horse, they smoke Dunhill.
#The man who smokes Blue Master drinks beer.
#The German smokes Prince.
#The Norwegian lives next to the blue house.
#They drink water in a house next to the house where they smoke Blend.
 
The question is, who owns the zebra?
 
It has several variants, one of them this:
Additionally, list the solution for all the houses. Optionally, show the solution is unique.
:#   There are five houses.
:#   The English man lives in the red house.
:#   The Swede has a dog.
:#   The Dane drinks tea.
:#   The green house is immediately to the left of the white house.
:#   They drink coffee in the green house.
:#   The man who smokes Pall Mall has a bird.
:#   In the yellow house they smoke Dunhill.
:#   In the middle house they drink milk.
:#   The Norwegian lives in the first house.
:#   The Blend-smoker lives in the house next to the house with a cat.
:#   In a house next to the house with a horse, they smoke Dunhill.
:#   The man who smokes Blue Master drinks beer.
:#   The German smokes Prince.
:#   The Norwegian lives next to the blue house.
:#   They drink water in a house next to the house where they smoke Blend.
 
<br>The question is, who owns the zebra? For clarity, each of the five houses is painted a different color, and their inhabitants are of different nationalities, own different pets, drink different beverages and smoke different brands of cigarettes.
cf. [[Dinesman's multiple-dwelling problem]]
 
Additionally, list the solution for all the houses.
<br>Optionally, show the solution is unique.
 
 
;Related tasks:
* &nbsp; [[Dinesman's multiple-dwelling problem]]
* &nbsp; [[Twelve statements]]
<br><br>
 
=={{header|Ada}}==
Not the prettiest Ada, but itsit's simple and very fast. Similar to my Dinesman's code,; uses enums to keep things readable.
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO; use Ada.Text_IO;
procedure Zebra is
type Content is (Beer, Coffee, Milk, Tea, Water,
Line 132 ⟶ 144:
end loop; end loop;
Solve (myAlley, 0, 5); -- start at test 0 with 5 options
end Zebra;</langsyntaxhighlight>
{{out}}
<pre>ONE: DRINK=WATER PERSON=NORWEGIAN COLOR=YELLOW SMOKE=DUNHILL PET=CAT
Line 139 ⟶ 151:
FOUR: DRINK=COFFEE PERSON=GERMAN COLOR=GREEN SMOKE=PRINCE PET=ZEBRA
FIVE: DRINK=BEER PERSON=SWEDISH COLOR=WHITE SMOKE=BLUEMASTER PET=DOG</pre>
 
=={{header|ALGOL 68}}==
Attempts to find solutions using the rules.
<syntaxhighlight lang="algol68">BEGIN
# attempt to solve Einstein's Riddle - the Zebra puzzle #
INT unknown = 0, same = -1;
INT english = 1, swede = 2, dane = 3, norwegian = 4, german = 5;
INT dog = 1, birds = 2, cats = 3, horse = 4, zebra = 5;
INT red = 1, green = 2, white = 3, yellow = 4, blue = 5;
INT tea = 1, coffee = 2, milk = 3, beer = 4, water = 5;
INT pall mall = 1, dunhill = 2, blend = 3, blue master = 4, prince = 5;
[]STRING nationality = ( "unknown", "english", "swede", "dane", "norwegian", "german" );
[]STRING animal = ( "unknown", "dog", "birds", "cats", "horse", "ZEBRA" );
[]STRING colour = ( "unknown", "red", "green", "white", "yellow", "blue" );
[]STRING drink = ( "unknown", "tea", "coffee", "milk", "beer", "water" );
[]STRING smoke = ( "unknown", "pall mall", "dunhill", "blend", "blue master", "prince" );
MODE HOUSE = STRUCT( INT nationality, animal, colour, drink, smoke );
# returns TRUE if a field in a house could be set to value, FALSE otherwise #
PROC can set = ( INT field, INT value )BOOL: field = unknown OR value = same;
# returns TRUE if the fields of house h could be set to those of #
# suggestion s, FALSE otherwise #
OP XOR = ( HOUSE h, HOUSE s )BOOL:
( can set( nationality OF h, nationality OF s ) AND can set( animal OF h, animal OF s )
AND can set( colour OF h, colour OF s ) AND can set( drink OF h, drink OF s )
AND can set( smoke OF h, smoke OF s )
) # XOR # ;
# sets a field in a house to value if it is unknown #
PROC set = ( REF INT field, INT value )VOID: IF field = unknown AND value /= same THEN field := value FI;
# sets the unknown fields in house h to the non-same fields of suggestion s #
OP +:= = ( REF HOUSE h, HOUSE s )VOID:
( set( nationality OF h, nationality OF s ); set( animal OF h, animal OF s )
; set( colour OF h, colour OF s ); set( drink OF h, drink OF s )
; set( smoke OF h, smoke OF s )
) # +:= # ;
# sets a field in a house to unknown if the value is not same #
PROC reset = ( REF INT field, INT value )VOID: IF value /= same THEN field := unknown FI;
# sets fields in house h to unknown if the suggestion s is not same #
OP -:= = ( REF HOUSE h, HOUSE s )VOID:
( reset( nationality OF h, nationality OF s ); reset( animal OF h, animal OF s )
; reset( colour OF h, colour OF s ); reset( drink OF h, drink OF s )
; reset( smoke OF h, smoke OF s )
) # -:= # ;
# attempts a partial solution for the house at pos #
PROC try = ( INT pos, HOUSE suggestion, PROC VOID continue )VOID:
IF pos >= LWB house AND pos <= UPB house THEN
IF house[ pos ] XOR suggestion THEN
house[ pos ] +:= suggestion; continue; house[ pos ] -:= suggestion
FI
FI # try # ;
# attempts a partial solution for the neighbours of a house #
PROC left or right = ( INT pos, BOOL left, BOOL right, HOUSE neighbour suggestion
, PROC VOID continue )VOID:
( IF left THEN try( pos - 1, neighbour suggestion, continue ) FI
; IF right THEN try( pos + 1, neighbour suggestion, continue ) FI
) # left or right # ;
# attempts a partial solution for all houses and possibly their neighbours #
PROC any2 = ( REF INT number, HOUSE suggestion
, BOOL left, BOOL right, HOUSE neighbour suggestion
, PROC VOID continue )VOID:
FOR pos TO UPB house DO
IF house[ pos ] XOR suggestion THEN
number := pos;
house[ number ] +:= suggestion;
IF NOT left AND NOT right THEN # neighbours not involved #
continue
ELSE # try one or both neighbours #
left or right( pos, left, right, neighbour suggestion, continue )
FI;
house[ number ] -:= suggestion
FI
OD # any2 # ;
# attempts a partial solution for all houses #
PROC any = ( HOUSE suggestion, PROC VOID continue )VOID:
any2( LOC INT, suggestion, FALSE, FALSE, SKIP, continue );
# find solution(s) #
INT blend pos;
INT solutions := 0;
# There are five houses. #
[ 1 : 5 ]HOUSE house;
FOR h TO UPB house DO house[ h ] := ( unknown, unknown, unknown, unknown, unknown ) OD;
# In the middle house they drink milk. #
drink OF house[ 3 ] := milk;
# The Norwegian lives in the first house. #
nationality OF house[ 1 ] := norwegian;
# The Norwegian lives next to the blue house. #
colour OF house[ 2 ] := blue;
# They drink coffee in the green house. #
# The green house is immediately to the left of the white house. #
any2( LOC INT, ( same, same, green, coffee, same )
, FALSE, TRUE, ( same, same, white, same, same ), VOID:
# In a house next to the house where they have a horse, #
# they smoke Dunhill. #
# In the yellow house they smoke Dunhill. #
any2( LOC INT, ( same, horse, same, same, same )
, TRUE, TRUE, ( same, same, yellow, same, dunhill ), VOID:
# The English man lives in the red house. #
any( ( english, same, red, same, same ), VOID:
# The man who smokes Blend lives in the house next to the #
# house with cats. #
any2( blend pos, ( same, same, same, same, blend )
, TRUE, TRUE, ( same, cats, same, same, same ), VOID:
# They drink water in a house next to the house where #
# they smoke Blend. #
left or right( blend pos, TRUE, TRUE, ( same, same, same, water, same ), VOID:
# The Dane drinks tea. #
any( ( dane, same, same, tea, same ), VOID:
# The man who smokes Blue Master drinks beer. #
any( ( same, same, same, beer, blue master ), VOID:
# The Swede has a dog. #
any( ( swede, dog, same, same, same ), VOID:
# The German smokes Prince. #
any( ( german, same, same, same, prince ), VOID:
# The man who smokes Pall Mall has birds. #
any( ( same, birds, same, same, pall mall ), VOID:
# if we can place the zebra, we have a solution #
any( ( same, zebra, same, same, same ), VOID:
( solutions +:= 1;
FOR h TO UPB house DO
print( ( whole( h, 0 )
, " ", nationality[ 1 + nationality OF house[ h ] ]
, ", ", animal [ 1 + animal OF house[ h ] ]
, ", ", colour [ 1 + colour OF house[ h ] ]
, ", ", drink [ 1 + drink OF house[ h ] ]
, ", ", smoke [ 1 + smoke OF house[ h ] ]
, newline
)
)
OD;
print( ( newline ) )
)
) # zebra #
) # pall mall #
) # german #
) # swede #
) # beer #
) # dane #
) # blend L/R #
) # blend #
) # red #
) # horse #
) # green # ;
print( ( "solutions: ", whole( solutions, 0 ), newline ) )
END
</syntaxhighlight>
{{out}}
<pre>
1 norwegian, cats, yellow, water, dunhill
2 dane, horse, blue, tea, blend
3 english, birds, red, milk, pall mall
4 german, ZEBRA, green, coffee, prince
5 swede, dog, white, beer, blue master
 
solutions: 1
</pre>
 
=={{header|AppleScript}}==
<syntaxhighlight lang="applescript">on zebraPuzzle()
-- From statement 10, the Norwegian lives in the first house,
-- so from statement 15, the blue house must be the second one.
-- From these and statements 5, 6, and 9, the green and white houses can only be the 4th & 5th,
-- and the Englishman's red house (statement 2) must be the middle one, where (9) they drink
-- milk. This only leaves the first house to claim the yellow colour and the Dunhill smokers
-- (statement 8), which means the second house must have the the horse (statement 12).
-- Initialise the house data accordingly.
set mv to missing value
set streetTemplate to {¬
{resident:"Norwegian", colour:"yellow", pet:mv, drink:mv, smoke:"Dunhill"}, ¬
{resident:mv, colour:"blue", pet:"horse", drink:mv, smoke:mv}, ¬
{resident:"Englishman", colour:"red", pet:mv, drink:"milk", smoke:mv}, ¬
{resident:mv, colour:"green", pet:mv, drink:"coffee", smoke:mv}, ¬
{resident:mv, colour:"white", pet:mv, drink:mv, smoke:mv} ¬
}
-- Test all permutations of the remaining values.
set solutions to {}
set drinkPermutations to {{"beer", "water"}, {"water", "beer"}}
set residentPermutations to {{"Swede", "Dane", "German"}, {"Swede", "German", "Dane"}, ¬
{"Dane", "German", "Swede"}, {"Dane", "Swede", "German"}, ¬
{"German", "Swede", "Dane"}, {"German", "Dane", "Swede"}}
set petPermutations to {{"birds", "cats", "ZEBRA"}, {"birds", "ZEBRA", "cats"}, ¬
{"cats", "ZEBRA", "birds"}, {"cats", "birds", "ZEBRA"}, ¬
{"ZEBRA", "birds", "cats"}, {"ZEBRA", "cats", "birds"}}
set smokePermutations to {{"Pall Mall", "Blend", "Blue Master"}, {"Pall Mall", "Blue Master", "Blend"}, ¬
{"Blend", "Blue Master", "Pall Mall"}, {"Blend", "Pall Mall", "Blue Master"}, ¬
{"Blue Master", "Pall Mall", "Blend"}, {"Blue Master", "Blend", "Pall Mall"}}
repeat with residentPerm in residentPermutations
-- Properties associated with resident.
copy streetTemplate to sTemplate2
set {r, OK} to {0, true}
repeat with h in {2, 4, 5} -- House numbers with unknown residents.
set thisHouse to sTemplate2's item h
set r to r + 1
set thisResident to residentPerm's item r
if (thisResident is "Swede") then
if (thisHouse's pet is not mv) then
set OK to false
exit repeat
end if
set thisHouse's pet to "dog"
else if (thisResident is "Dane") then
if (thisHouse's drink is not mv) then
set OK to false
exit repeat
end if
set thisHouse's drink to "tea"
else
set thisHouse's smoke to "Prince"
end if
set thisHouse's resident to thisResident
end repeat
-- Properties associated with cigarette brand.
if (OK) then
repeat with smokePerm in smokePermutations
-- Fit in this permutation of smokes.
copy sTemplate2 to sTemplate3
set s to 0
repeat with thisHouse in sTemplate3
if (thisHouse's smoke is mv) then
set s to s + 1
set thisHouse's smoke to smokePerm's item s
end if
end repeat
repeat with drinkPerm in drinkPermutations
-- Try to fit this permutation of drinks.
copy sTemplate3 to sTemplate4
set {d, OK} to {0, true}
repeat with h from 1 to 5
set thisHouse to sTemplate4's item h
if (thisHouse's drink is mv) then
set d to d + 1
set thisDrink to drinkPerm's item d
if (((thisDrink is "beer") and (thisHouse's smoke is not "Blue Master")) or ¬
((thisDrink is "water") and not ¬
(((h > 1) and (sTemplate4's item (h - 1)'s smoke is "Blend")) or ¬
((h < 5) and (sTemplate4's item (h + 1)'s smoke is "Blend"))))) then
set OK to false
exit repeat
end if
set thisHouse's drink to thisDrink
end if
end repeat
if (OK) then
repeat with petPerm in petPermutations
-- Try to fit this permutation of pets.
copy sTemplate4 to sTemplate5
set {p, OK} to {0, true}
repeat with h from 1 to 5
set thisHouse to sTemplate5's item h
if (thisHouse's pet is mv) then
set p to p + 1
set thisPet to petPerm's item p
if ((thisPet is "birds") and (thisHouse's smoke is not "Pall Mall")) or ¬
((thisPet is "cats") and not ¬
(((h > 1) and (sTemplate5's item (h - 1)'s smoke is "Blend")) or ¬
((h < 5) and (sTemplate5's item (h + 1)'s smoke is "Blend")))) then
set OK to false
exit repeat
end if
set thisHouse's pet to thisPet
end if
end repeat
if (OK) then set end of solutions to sTemplate5
end repeat
end if
end repeat
end repeat
end if
end repeat
set solutionCount to (count solutions)
set owners to {}
repeat with thisSolution in solutions
repeat with thisHouse in thisSolution
if (thisHouse's pet is "zebra") then
set owners's end to thisHouse's resident
exit repeat
end if
end repeat
end repeat
return {zebraOwners:owners, numberOfSolutions:solutionCount, solutions:solutions}
end zebraPuzzle
 
zebraPuzzle()</syntaxhighlight>
 
{{output}}
<syntaxhighlight lang="applescript">{zebraOwners:{"German"}, numberOfSolutions:1, solutions:{{{resident:"Norwegian", colour:"yellow", pet:"cats", drink:"water", smoke:"Dunhill"}, {resident:"Dane", colour:"blue", pet:"horse", drink:"tea", smoke:"Blend"}, {resident:"Englishman", colour:"red", pet:"birds", drink:"milk", smoke:"Pall Mall"}, {resident:"German", colour:"green", pet:"ZEBRA", drink:"coffee", smoke:"Prince"}, {resident:"Swede", colour:"white", pet:"dog", drink:"beer", smoke:"Blue Master"}}}}</syntaxhighlight>
 
=={{header|AutoHotkey}}==
See [[Dinesman's multiple-dwelling problem/AutoHotkey]].
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<syntaxhighlight lang="bbcbasic"> REM The names (only used for printing the results):
DIM Drink$(4), Nation$(4), Colr$(4), Smoke$(4), Animal$(4)
Drink$() = "Beer", "Coffee", "Milk", "Tea", "Water"
Nation$() = "Denmark", "England", "Germany", "Norway", "Sweden"
Colr$() = "Blue", "Green", "Red", "White", "Yellow"
Smoke$() = "Blend", "BlueMaster", "Dunhill", "PallMall", "Prince"
Animal$() = "Birds", "Cats", "Dog", "Horse", "Zebra"
REM Some single-character tags:
a$ = "A" : b$ = "B" : c$ = "C" : d$ = "D" : e$ = "E"
REM BBC BASIC Doesn't have enumerations!
Beer$=a$ : Coffee$=b$ : Milk$=c$ : Tea$=d$ : Water$=e$
Denmark$=a$ : England$=b$ : Germany$=c$ : Norway$=d$ : Sweden$=e$
Blue$=a$ : Green$=b$ : Red$=c$ : White$=d$ : Yellow$=e$
Blend$=a$ : BlueMaster$=b$ : Dunhill$=c$ : PallMall$=d$ : Prince$=e$
Birds$=a$ : Cats$=b$ : Dog$=c$ : Horse$=d$ : Zebra$=e$
REM Create the 120 permutations of 5 objects:
DIM perm$(120), x$(4) : x$() = a$, b$, c$, d$, e$
REPEAT
p% += 1
perm$(p%) = x$(0)+x$(1)+x$(2)+x$(3)+x$(4)
UNTIL NOT FNperm(x$())
REM Express the statements as conditional expressions:
ex2$ = "INSTR(Nation$,England$) = INSTR(Colr$,Red$)"
ex3$ = "INSTR(Nation$,Sweden$) = INSTR(Animal$,Dog$)"
ex4$ = "INSTR(Nation$,Denmark$) = INSTR(Drink$,Tea$)"
ex5$ = "INSTR(Colr$,Green$+White$) <> 0"
ex6$ = "INSTR(Drink$,Coffee$) = INSTR(Colr$,Green$)"
ex7$ = "INSTR(Smoke$,PallMall$) = INSTR(Animal$,Birds$)"
ex8$ = "INSTR(Smoke$,Dunhill$) = INSTR(Colr$,Yellow$)"
ex9$ = "MID$(Drink$,3,1) = Milk$"
ex10$ = "LEFT$(Nation$,1) = Norway$"
ex11$ = "ABS(INSTR(Smoke$,Blend$)-INSTR(Animal$,Cats$)) = 1"
ex12$ = "ABS(INSTR(Smoke$,Dunhill$)-INSTR(Animal$,Horse$)) = 1"
ex13$ = "INSTR(Smoke$,BlueMaster$) = INSTR(Drink$,Beer$)"
ex14$ = "INSTR(Nation$,Germany$) = INSTR(Smoke$,Prince$)"
ex15$ = "ABS(INSTR(Nation$,Norway$)-INSTR(Colr$,Blue$)) = 1"
ex16$ = "ABS(INSTR(Smoke$,Blend$)-INSTR(Drink$,Water$)) = 1"
REM Solve:
solutions% = 0
TIME = 0
FOR nation% = 1 TO 120
Nation$ = perm$(nation%)
IF EVAL(ex10$) THEN
FOR colr% = 1 TO 120
Colr$ = perm$(colr%)
IF EVAL(ex5$) IF EVAL(ex2$) IF EVAL(ex15$) THEN
FOR drink% = 1 TO 120
Drink$ = perm$(drink%)
IF EVAL(ex9$) IF EVAL(ex4$) IF EVAL(ex6$) THEN
FOR smoke% = 1 TO 120
Smoke$ = perm$(smoke%)
IF EVAL(ex14$) IF EVAL(ex13$) IF EVAL(ex16$) IF EVAL(ex8$) THEN
FOR animal% = 1 TO 120
Animal$ = perm$(animal%)
IF EVAL(ex3$) IF EVAL(ex7$) IF EVAL(ex11$) IF EVAL(ex12$) THEN
PRINT "House Drink Nation Colour Smoke Animal"
FOR house% = 1 TO 5
PRINT ; house% ,;
PRINT Drink$(ASCMID$(Drink$,house%)-65),;
PRINT Nation$(ASCMID$(Nation$,house%)-65),;
PRINT Colr$(ASCMID$(Colr$,house%)-65),;
PRINT Smoke$(ASCMID$(Smoke$,house%)-65),;
PRINT Animal$(ASCMID$(Animal$,house%)-65)
NEXT
solutions% += 1
ENDIF
NEXT animal%
ENDIF
NEXT smoke%
ENDIF
NEXT drink%
ENDIF
NEXT colr%
ENDIF
NEXT nation%
PRINT '"Number of solutions = "; solutions%
PRINT "Solved in " ; TIME/100 " seconds"
END
DEF FNperm(x$())
LOCAL i%, j%
FOR i% = DIM(x$(),1)-1 TO 0 STEP -1
IF x$(i%) < x$(i%+1) EXIT FOR
NEXT
IF i% < 0 THEN = FALSE
j% = DIM(x$(),1)
WHILE x$(j%) <= x$(i%) j% -= 1 : ENDWHILE
SWAP x$(i%), x$(j%)
i% += 1
j% = DIM(x$(),1)
WHILE i% < j%
SWAP x$(i%), x$(j%)
i% += 1
j% -= 1
ENDWHILE
= TRUE</syntaxhighlight>
'''Output:'''
<pre>
House Drink Nation Colour Smoke Animal
1 Water Norway Yellow Dunhill Cats
2 Tea Denmark Blue Blend Horse
3 Milk England Red PallMall Birds
4 Coffee Germany Green Prince Zebra
5 Beer Sweden White BlueMasterDog
 
Number of solutions = 1
Solved in 0.12 seconds
</pre>
 
=={{header|Bracmat}}==
<syntaxhighlight lang="bracmat">( (English Swede Dane Norwegian German,)
(red green white yellow blue,(red.English.))
(dog birds cats horse zebra,(dog.?.Swede.))
( tea coffee milk beer water
, (tea.?.?.Dane.) (coffee.?.green.?.)
)
( "Pall Mall" Dunhill Blend "Blue Master" Prince
, ("Blue Master".beer.?.?.?.)
("Pall Mall".?.birds.?.?.)
(Dunhill.?.?.yellow.?.)
(Prince.?.?.?.German.)
)
( 1 2 3 4 5
, (3.?.milk.?.?.?.) (1.?.?.?.?.Norwegian.)
)
: ?properties
& ( relations
= next leftOf
. ( next
= a b A B
. !arg:(?S,?A,?B)
& !S:? (?a.!A) ?:? (?b.!B) ?
& (!a+1:!b|!b+1:!a)
)
& ( leftOf
= a b A B
. !arg:(?S,?A,?B)
& !S:? (?a.!A) ?:? (?b.!B) ?
& !a+1:!b
)
& leftOf
$ (!arg,(?.?.?.green.?.),(?.?.?.white.?.))
& next$(!arg,(Blend.?.?.?.?.),(?.?.cats.?.?.))
& next
$ (!arg,(?.?.horse.?.?.),(Dunhill.?.?.?.?.))
& next
$ (!arg,(?.?.?.?.Norwegian.),(?.?.?.blue.?.))
& next$(!arg,(?.water.?.?.?.),(Blend.?.?.?.?.))
)
& ( props
= a constraint constraints house houses
, remainingToDo shavedToDo toDo value values z
. !arg:(?toDo.?shavedToDo.?house.?houses)
& ( !toDo:(?values,?constraints) ?remainingToDo
& !values
: ( ?a
( %@?value
& !constraints
: ( ?
( !value
. ?constraint
& !house:!constraint
)
?
| ~( ?
( ?
. ?constraint
& !house:!constraint
)
?
| ? (!value.?) ?
)
)
)
( ?z
& props
$ ( !remainingToDo
. !shavedToDo (!a !z,!constraints)
. (!value.!house)
. !houses
)
)
|
& relations$!houses
& out$(Solution !houses)
)
| !toDo:
& props$(!shavedToDo...!house !houses)
)
)
& props$(!properties...)
& done
);</syntaxhighlight>
Output:
<pre> Solution
(4.Prince.coffee.zebra.green.German.)
(1.Dunhill.water.cats.yellow.Norwegian.)
(2.Blend.tea.horse.blue.Dane.)
(5.Blue Master.beer.dog.white.Swede.)
(3.Pall Mall.milk.birds.red.English.)
{!} done</pre>
 
=={{header|C}}==
<syntaxhighlight lang="c">#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;
}</syntaxhighlight>
{{out}}
<pre>% gcc -Wall -O3 -std=c99 zebra.c -o zebra && time ./zebra
House Color Man Drink Animal Smoke
0 Yellow Norwegian Water Cats Dunhill
1 Blue Dane Tea Horse Blend
2 Red English Milk Birds PallMall
3 Green German Coffee Zebra Prince
4 White Swede Beer Dog BlueMaster
./zebra 0.00s user 0.00s system 0% cpu 0.002 total</pre>
The execution time is too small to be reliably measured on my machine.
===C Generated from Perl===
 
I'll be the first to admit the following doesn't quite look like a C program. It's in fact in Perl, which outputs a C source, which in turn solves the puzzle. If you think this is long, wait till you see the C it writes.
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
 
use utf8;
Line 158 ⟶ 918:
 
$" = '", "';
print "const char *string_$p [] = { \"###\", \"@s\" };\n\n";
}
print "#define FIND_BY(p) \\
Line 317 ⟶ 1,077:
 
# write C code. If it's ugly to you: I didn't write; Perl did.
make_c;</langsyntaxhighlight>
output (ran as <code>perl test.pl | gcc -Wall -x c -; ./a.out</code>):<pre>
0 dunhill cats yellow water Norske
Line 327 ⟶ 1,087:
 
=={{header|C sharp|C#}}==
=== "Manual" solution (Norvig-style) ===
<lang csharp>
{{works with|C sharp|C#|7+ (but easy to adapt to lower versions)}}
// Solve Zebra Puzzle
<!-- By Martin Freedman, 17/01/2018 -->
//
This is adapted from a solution to a similar problem by Peter Norvig in his [https://www.udacity.com/course/design-of-computer-programs--cs212 Udacity course CS212], originally written in Python. This is translated from [https://github.com/exercism/python/blob/master/exercises/zebra-puzzle/example.py example python solution on exercism]. This is a Generate-and-Prune Constraint Programming algorithm written with Linq. (See Benchmarks below)
// Nigel Galloway. May 26th., 2012
<syntaxhighlight lang="csharp">using System;
//
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static System.Console;
 
public enum Colour { Red, Green, White, Yellow, Blue }
public enum Nationality { Englishman, Swede, Dane, Norwegian,German }
public enum Pet { Dog, Birds, Cats, Horse, Zebra }
public enum Drink { Coffee, Tea, Milk, Beer, Water }
public enum Smoke { PallMall, Dunhill, Blend, BlueMaster, Prince}
 
public static class ZebraPuzzle
{
private static (Colour[] colours, Drink[] drinks, Smoke[] smokes, Pet[] pets, Nationality[] nations) _solved;
 
static ZebraPuzzle()
{
var solve = from colours in Permute<Colour>() //r1 5 range
where (colours,Colour.White).IsRightOf(colours, Colour.Green) // r5
from nations in Permute<Nationality>()
where nations[0] == Nationality.Norwegian // r10
where (nations, Nationality.Englishman).IsSameIndex(colours, Colour.Red) //r2
where (nations,Nationality.Norwegian).IsNextTo(colours,Colour.Blue) // r15
from drinks in Permute<Drink>()
where drinks[2] == Drink.Milk //r9
where (drinks, Drink.Coffee).IsSameIndex(colours, Colour.Green) // r6
where (drinks, Drink.Tea).IsSameIndex(nations, Nationality.Dane) //r4
from pets in Permute<Pet>()
where (pets, Pet.Dog).IsSameIndex(nations, Nationality.Swede) // r3
from smokes in Permute<Smoke>()
where (smokes, Smoke.PallMall).IsSameIndex(pets, Pet.Birds) // r7
where (smokes, Smoke.Dunhill).IsSameIndex(colours, Colour.Yellow) // r8
where (smokes, Smoke.Blend).IsNextTo(pets, Pet.Cats) // r11
where (smokes, Smoke.Dunhill).IsNextTo(pets, Pet.Horse) //r12
where (smokes, Smoke.BlueMaster).IsSameIndex(drinks, Drink.Beer) //r13
where (smokes, Smoke.Prince).IsSameIndex(nations, Nationality.German) // r14
where (drinks,Drink.Water).IsNextTo(smokes,Smoke.Blend) // r16
select (colours, drinks, smokes, pets, nations);
 
_solved = solve.First();
}
private static int IndexOf<T>(this T[] arr, T obj) => Array.IndexOf(arr, obj);
 
private static bool IsRightOf<T, U>(this (T[] a, T v) right, U[] a, U v) => right.a.IndexOf(right.v) == a.IndexOf(v) + 1;
 
private static bool IsSameIndex<T, U>(this (T[] a, T v)x, U[] a, U v) => x.a.IndexOf(x.v) == a.IndexOf(v);
 
private static bool IsNextTo<T, U>(this (T[] a, T v)x, U[] a, U v) => (x.a,x.v).IsRightOf(a, v) || (a,v).IsRightOf(x.a,x.v);
 
// made more generic from https://codereview.stackexchange.com/questions/91808/permutations-in-c
public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> values)
{
if (values.Count() == 1)
return values.ToSingleton();
 
return values.SelectMany(v => Permutations(values.Except(v.ToSingleton())),(v, p) => p.Prepend(v));
}
 
public static IEnumerable<T[]> Permute<T>() => ToEnumerable<T>().Permutations().Select(p=>p.ToArray());
 
private static IEnumerable<T> ToSingleton<T>(this T item){ yield return item; }
 
private static IEnumerable<T> ToEnumerable<T>() => Enum.GetValues(typeof(T)).Cast<T>();
 
public static new String ToString()
{
var sb = new StringBuilder();
sb.AppendLine("House Colour Drink Nationality Smokes Pet");
sb.AppendLine("───── ────── ──────── ─────────── ────────── ─────");
var (colours, drinks, smokes, pets, nations) = _solved;
for (var i = 0; i < 5; i++)
sb.AppendLine($"{i+1,5} {colours[i],-6} {drinks[i],-8} {nations[i],-11} {smokes[i],-10} {pets[i],-10}");
return sb.ToString();
}
 
public static void Main(string[] arguments)
{
var owner = _solved.nations[_solved.pets.IndexOf(Pet.Zebra)];
WriteLine($"The zebra owner is {owner}");
Write(ToString());
Read();
}
}</syntaxhighlight>
Produces:
<pre>
The zebra owner is German
House Colour Drink Nationality Smokes Pet
───── ────── ──────── ─────────── ────────── ─────
1 Yellow Water Norwegian Dunhill Cats
2 Blue Tea Dane Blend Horse
3 Red Milk Englishman PallMall Birds
4 Green Coffee German Prince Zebra
5 White Beer Swede BlueMaster Dog
</pre>
=== "Manual" solution (Combining Houses) ===
{{works with|C sharp|C#|7+ }}
{{trans|Scala}}
<!-- By Martin Freedman, 19/01/2018 -->
This is similar to the Scala solution although there are differences in how the rules are calculated and it keeps all the original constraints/rules rather than does any simplification of them.
 
This is a different type of generate-and-prune compared to Norvig. The Norvig solution generates each attribute for 5 houses, then prunes and repeats with the next attribute. Here all houses with possible attributes are first generated and pruned to 78 candidates. The second phase proceeds over the combination of 5 houses from that 78, generating and pruning 1 house at a time. (See Benchmarks below)
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
using static System.Console;
 
namespace ZebraPuzzleSolver
{
public enum Colour { Red, Green, White, Yellow, Blue }
public enum Nationality { Englishman, Swede, Dane, Norwegian, German }
public enum Pet { Dog, Birds, Cats, Horse, Zebra }
public enum Drink { Coffee, Tea, Milk, Beer, Water }
public enum Smoke { PallMall, Dunhill, Blend, BlueMaster, Prince }
 
public struct House
{
public Drink D { get; }
public Colour C { get; }
public Pet P { get; }
public Nationality N { get; }
public Smoke S { get; }
 
House(Drink d, Colour c, Pet p, Nationality n, Smoke s) => (D, C, P, N, S) = (d, c, p, n, s);
 
public static House Create(Drink d, Colour c, Pet p, Nationality n, Smoke s) => new House(d, c, p, n, s);
 
public bool AllUnequal(House other) => D != other.D && C != other.C && P != other.P && N != other.N && S != other.S;
 
public override string ToString() =>$"{C,-6} {D,-8} {N,-11} {S,-10} {P,-10}";
}
 
public static class LinqNoPerm
{
public static IEnumerable<T> ToEnumerable<T>() => Enum.GetValues(typeof(T)).Cast<T>();
 
public static IEnumerable<House> FreeCandidates(this IEnumerable<House> houses, IEnumerable<House> picked) =>
houses.Where(house => picked.All(house.AllUnequal));
 
static Dictionary<Type, Func<House, dynamic, bool>> _eFn = new Dictionary<Type, Func<House, dynamic, bool>>
{ {typeof(Drink),(h,e)=>h.D==e},
{typeof(Nationality),(h,e)=>h.N==e},
{typeof(Colour),(h,e)=>h.C==e},
{typeof(Pet),(h,e)=>h.P==e},
{typeof(Smoke),(h, e)=>h.S==e}
};
 
public static bool IsNextTo<T, U>(this IEnumerable<House> hs,T t, U u) => hs.IsLeftOf(t,u) || hs.IsLeftOf(u, t);
 
public static bool IsLeftOf<T, U>(this IEnumerable<House> hs, T left, U right) =>
hs.Zip(hs.Skip(1), (l, r) => (_eFn[left.GetType()](l, left) && _eFn[right.GetType()](r, right))).Any(l => l);
 
static House[] _solved;
 
static LinqNoPerm()
{
var candidates =
from colours in ToEnumerable<Colour>()
from nations in ToEnumerable<Nationality>()
from drinks in ToEnumerable<Drink>()
from pets in ToEnumerable<Pet>()
from smokes in ToEnumerable<Smoke>()
where (colours == Colour.Red) == (nations == Nationality.Englishman) //r2
where (nations == Nationality.Swede) == (pets == Pet.Dog) //r3
where (nations == Nationality.Dane) == (drinks == Drink.Tea) //r4
where (colours == Colour.Green) == (drinks == Drink.Coffee) //r6
where (smokes == Smoke.PallMall) == (pets == Pet.Birds) //r7
where (smokes == Smoke.Dunhill) == (colours == Colour.Yellow) // r8
where (smokes == Smoke.BlueMaster) == (drinks == Drink.Beer) //r13
where (smokes == Smoke.Prince) == (nations == Nationality.German) // r14
select House.Create(drinks,colours,pets,nations, smokes);
var members =
from h1 in candidates
where h1.N == Nationality.Norwegian //r10
from h3 in candidates.FreeCandidates(new[] { h1 })
where h3.D == Drink.Milk //r9
from h2 in candidates.FreeCandidates(new[] { h1, h3 })
let h123 = new[] { h1, h2, h3 }
where h123.IsNextTo(Nationality.Norwegian, Colour.Blue) //r15
where h123.IsNextTo(Smoke.Blend, Pet.Cats)//r11
where h123.IsNextTo(Smoke.Dunhill, Pet.Horse) //r12
from h4 in candidates.FreeCandidates(h123)
from h5 in candidates.FreeCandidates(new[] { h1, h3, h2, h4 })
let houses = new[] { h1, h2, h3, h4, h5 }
where houses.IsLeftOf(Colour.Green, Colour.White) //r5
select houses;
_solved = members.First();
}
 
public static new String ToString()
{
var sb = new StringBuilder();
 
sb.AppendLine("House Colour Drink Nationality Smokes Pet");
sb.AppendLine("───── ────── ──────── ─────────── ────────── ─────");
for (var i = 0; i < 5; i++)
sb.AppendLine($"{i + 1,5} {_solved[i].ToString()}");
return sb.ToString();
}
 
public static void Main(string[] arguments)
{
var owner = _solved.Where(h=>h.P==Pet.Zebra).Single().N;
WriteLine($"The zebra owner is {owner}");
Write(ToString());
Read();
}
}
}</syntaxhighlight>
Produces
<pre>The zebra owner is German
House Colour Drink Nationality Smokes Pet
───── ────── ──────── ─────────── ────────── ─────
1 Yellow Water Norwegian Dunhill Cats
2 Blue Tea Dane Blend Horse
3 Red Milk Englishman PallMall Birds
4 Green Coffee German Prince Zebra
5 White Beer Swede BlueMaster Dog
</pre>
 
=== "Amb" solution ===
This uses the second version of the [https://rosettacode.org/wiki/Amb#C.23 Amb C# class] in the Amb challenge
{{works with|C sharp|C#|7.1}}
<!-- By Martin Freedman, 9/02/2018 -->
<syntaxhighlight lang="csharp">using Amb;
using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console;
 
static class ZebraProgram
{
public static void Main()
{
var amb = new Amb.Amb();
 
var domain = new[] { 1, 2, 3, 4, 5 };
var terms = new Dictionary<IValue<int>, string>();
IValue<int> Term(string name)
{
var x = amb.Choose(domain);
terms.Add(x, name);
return x;
};
 
void IsUnequal(params IValue<int>[] values) =>amb.Require(() => values.Select(v => v.Value).Distinct().Count() == 5);
void IsSame(IValue<int> left, IValue<int> right) => amb.Require(() => left.Value == right.Value);
void IsLeftOf(IValue<int> left, IValue<int> right) => amb.Require(() => right.Value - left.Value == 1);
void IsIn(IValue<int> attrib, int house) => amb.Require(() => attrib.Value == house);
void IsNextTo(IValue<int> left, IValue<int> right) => amb.Require(() => Math.Abs(left.Value - right.Value) == 1);
 
IValue<int> english = Term("Englishman"), swede = Term("Swede"), dane = Term("Dane"), norwegian = Term("Norwegian"), german = Term("German");
IsIn(norwegian, 1);
IsUnequal(english, swede, german, dane, norwegian);
 
IValue<int> red = Term("red"), green = Term("green"), white = Term("white"), blue = Term("blue"), yellow = Term("yellow");
IsUnequal(red, green, white, blue, yellow);
IsNextTo(norwegian, blue);
IsLeftOf(green, white);
IsSame(english, red);
 
IValue<int> tea = Term("tea"), coffee = Term("coffee"), milk = Term("milk"), beer = Term("beer"), water = Term("water");
IsIn(milk, 3);
IsUnequal(tea, coffee, milk, beer, water);
IsSame(dane, tea);
IsSame(green, coffee);
 
IValue<int> dog = Term("dog"), birds = Term("birds"), cats = Term("cats"), horse = Term("horse"), zebra = Term("zebra");
IsUnequal(dog, cats, birds, horse, zebra);
IsSame(swede, dog);
 
IValue<int> pallmall = Term("pallmall"), dunhill = Term("dunhill"), blend = Term("blend"), bluemaster = Term("bluemaster"),prince = Term("prince");
IsUnequal(pallmall, dunhill, bluemaster, prince, blend);
IsSame(pallmall, birds);
IsSame(dunhill, yellow);
IsNextTo(blend, cats);
IsNextTo(horse, dunhill);
IsSame(bluemaster, beer);
IsSame(german, prince);
IsNextTo(water, blend);
 
if (!amb.Disambiguate())
{
WriteLine("No solution found.");
Read();
return;
}
 
var h = new List<string>[5];
for (int i = 0; i < 5; i++)
h[i] = new List<string>();
 
foreach (var (key, value) in terms.Select(kvp => (kvp.Key, kvp.Value)))
{
h[key.Value - 1].Add(value);
}
 
var owner = String.Concat(h.Where(l => l.Contains("zebra")).Select(l => l[0]));
WriteLine($"The {owner} owns the zebra");
 
foreach (var house in h)
{
Write("|");
foreach (var attrib in house)
Write($"{attrib,-10}|");
Write("\n");
}
Read();
}
}</syntaxhighlight>
Produces
<pre>The zebra owner is German
House Colour Drink Nationality Smokes Pet
───── ────── ──────── ─────────── ────────── ─────
1 Yellow Water Norwegian Dunhill Cats
2 Blue Tea Dane Blend Horse
3 Red Milk Englishman PallMall Birds
4 Green Coffee German Prince Zebra
5 White Beer Swede BlueMaster Dog
</pre>
 
=== "Automatic" solution ===
{{works with|C sharp|C#|7}}
{{libheader|Microsoft Solver Foundation}}
<!-- By Martin Freedman, 19/01/2018 based on MS example code-->
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SolverFoundation.Solvers;
 
using static System.Console;
namespace Zebra
 
static class ZebraProgram
{
static ConstraintSystem _solver;
class Zebra
 
static CspTerm IsLeftOf(this CspTerm left, CspTerm right) => _solver.Equal(1, right - left);
static CspTerm IsInSameHouseAs(this CspTerm left, CspTerm right) => _solver.Equal(left, right);
static CspTerm IsNextTo(this CspTerm left, CspTerm right) => _solver.Equal(1,_solver.Abs(left-right));
static CspTerm IsInHouse(this CspTerm @this, int i) => _solver.Equal(i, @this);
 
static (ConstraintSystem, Dictionary<CspTerm, string>) BuildSolver()
{
var solver = ConstraintSystem.CreateSolver();
static readonly int[] Houses = new int[] {0,1,2,3,4};
_solver = solver;
enum Colour { Blue, Green, White, Red, Yellow };
enumvar Drinkterms {= Beer,new CoffeeDictionary<CspTerm, Milk, Tea, Water }string>();
enum Nationality { English, Danish, German, Norwegian, Swedish };
CspTerm Term(string name)
enum Smoke { Blend, BlueMaster, Dunhill, PallMall, Prince };
enum Pet { Bird, Cat, Dog, Horse, Zebra };
static CspTerm[][] U(ConstraintSystem S)
{
CspTerm[][] retx = Ssolver.CreateBooleanArrayCreateVariable(new objectsolver.CreateIntegerInterval()1, Houses.Length5), Houses.Lengthname);
for terms.Add(intx, i = 0name); i < Zebra.Houses.Length; i++)
{return x;
};
CspTerm[] r = S.CreateBooleanVector(new object(), Houses.Length); ;
 
CspTerm[] c = S.CreateBooleanVector(new object(), Houses.Length); ;
CspTerm red = Term("red"), green = Term("green"), white = Term("white"), blue = Term("blue"), yellow = Term("yellow");
for (int j = 0; j < Houses.Length; j++)
CspTerm tea = Term("tea"), coffee = Term("coffee"), milk = Term("milk"), beer = Term("beer"), water = Term("water");
{
CspTerm english = Term("Englishman"), swede = Term("Swede"), dane = Term("Dane"), norwegian = Term("Norwegian"),
r[j] = ret[i][j];
c[j]german = ret[j][i]Term("German");
CspTerm dog = Term("dog"), birds = Term("birds"), cats = Term("cats"), horse = Term("horse"), zebra = Term("zebra");
}
CspTerm pallmall = Term("pallmall"), dunhill = Term("dunhill"), blend = Term("blend"), bluemaster = Term("bluemaster"),
S.AddConstraints(S.Equal(1, S.Sum(r)));
prince = S.AddConstraints(S.Equal(1, S.SumTerm(c))"prince");
 
}
return ret;solver.AddConstraints(
solver.Unequal(english, swede, german, dane, norwegian),
solver.Unequal(red, green, white, blue, yellow),
solver.Unequal(dog, cats, birds, horse, zebra),
solver.Unequal(pallmall, dunhill, bluemaster, prince, blend),
solver.Unequal(tea, coffee, milk, beer, water),
 
english.IsInSameHouseAs(red), //r2
swede.IsInSameHouseAs(dog), //r3
dane.IsInSameHouseAs(tea), //r4
green.IsLeftOf(white), //r5
green.IsInSameHouseAs(coffee), //r6
pallmall.IsInSameHouseAs(birds), //r7
dunhill.IsInSameHouseAs(yellow), //r8
milk.IsInHouse(3), //r9
norwegian.IsInHouse(1), //r10
blend.IsNextTo(cats), //r11
horse.IsNextTo(dunhill),// r12
bluemaster.IsInSameHouseAs(beer), // r13
german.IsInSameHouseAs(prince), // r14
norwegian.IsNextTo(blue), //r15
water.IsNextTo(blend) //r16
);
return (solver, terms);
}
 
static List<string>[] TermsToString(ConstraintSolverSolution solved, Dictionary<CspTerm, string> terms)
{
var h = new List<string>[5];
for (int i = 0; i < 5; i++)
h[i] = new List<string>();
 
foreach (var (key, value) in terms.Select(kvp => (kvp.Key, kvp.Value)))
{
if (!solved.TryGetValue(key, out object house))
throw new InvalidProgramException("Can't find a term - {value} - in the solution");
h[(int)house - 1].Add(value);
}
 
static int P(ConstraintSolverSolution soln, CspTerm[][] x, int house)
return h;
}
 
static new string ToString(List<string>[] houses)
{
var sb = new StringBuilder();
foreach (var house in houses)
{
object hsb.Append("|");
foreach (intvar iattrib in Houseshouse)
sb.Append($"{attrib,-10}|");
solnsb.TryGetValueAppend(x[house][i], out h"\n");
if ((int)h == 1)
{
return i;
}
}
return 0;
}
staticreturn void Mainsb.ToString(string[] args);
}
 
public static void Main()
{
var (solver, terms) = BuildSolver();
var solved = solver.Solve();
 
if (solved.HasFoundSolution)
{
ConstraintSystemvar Kh = ConstraintSystem.CreateSolverTermsToString(solved, terms);
 
CspTerm[][] colour = U(K);
CspTerm[][]var drinkowner = String.Concat(h.Where(l => l.Contains("zebra")).Select(l => U(Kl[2]));
CspTerm[][]WriteLine($"The nationality{owner} =owns U(Kthe zebra");
CspTerm[][] smoke = UWriteLine(K);
CspTerm[][] pet = UWrite(KToString(h));
K.AddConstraints(}
else
K.Equal(colour[1][(int)Colour.White], colour[0][(int)Colour.Green]),
WriteLine("No solution K.Equal(0, colour[0][(int)Colourfound.White]"),;
Read();
K.Equal(1, drink[2][(int)Drink.Milk]),
}
K.Equal(1, nationality[0][(int)Nationality.Norwegian]),
}</syntaxhighlight>
K.Greater(1, K.Sum(smoke[0][(int)Smoke.Blend], pet[0][(int)Pet.Cat]) - K.Sum(smoke[1][(int)Smoke.Blend], pet[1][(int)Pet.Cat])),
Produces:
K.Greater(1, K.Sum(smoke[4][(int)Smoke.Blend], pet[4][(int)Pet.Cat]) - K.Sum(smoke[3][(int)Smoke.Blend], pet[3][(int)Pet.Cat])),
<pre>
K.Greater(1, K.Sum(smoke[0][(int)Smoke.Blend], drink[0][(int)Drink.Water]) - K.Sum(smoke[1][(int)Smoke.Blend], drink[1][(int)Drink.Water])),
The German owns the zebra
K.Greater(1, K.Sum(smoke[4][(int)Smoke.Blend], drink[4][(int)Drink.Water]) - K.Sum(smoke[3][(int)Smoke.Blend], drink[3][(int)Drink.Water])),
 
K.Greater(1, K.Sum(smoke[0][(int)Smoke.Dunhill], pet[0][(int)Pet.Horse]) - K.Sum(smoke[1][(int)Smoke.Dunhill], pet[1][(int)Pet.Horse])),
|yellow |water |Norwegian |cats |dunhill |
K.Greater(1, K.Sum(smoke[4][(int)Smoke.Dunhill], pet[4][(int)Pet.Horse]) - K.Sum(smoke[3][(int)Smoke.Dunhill], pet[3][(int)Pet.Horse])),
|blue |tea |Dane |horse |blend |
K.Greater(1, K.Sum(nationality[0][(int)Nationality.Norwegian], colour[0][(int)Colour.Blue]) - K.Sum(nationality[1][(int)Nationality.Norwegian], colour[1][(int)Colour.Blue])),
|red |milk |Englishman|birds |pallmall |
K.Greater(1, K.Sum(nationality[4][(int)Nationality.Norwegian], colour[4][(int)Colour.Blue]) - K.Sum(nationality[3][(int)Nationality.Norwegian], colour[3][(int)Colour.Blue]))
|green |coffee |German |zebra ); |prince |
|white |beer |Swede for (int h = 1;|dog h < 4; h++) |bluemaster|
</pre>
{
===Benchmarking the 3 solutions: ===
K.AddConstraints(
<pre>
K.Equal(colour[h+1][(int)Colour.White], colour[h][(int)Colour.Green]),
BenchmarkDotNet=v0.10.12, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.192)
K.Greater(1, K.Sum(smoke[h][(int)Smoke.Blend], pet[h][(int)Pet.Cat]) -
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical cores and 2 physical cores
K.Sum(smoke[h - 1][(int)Smoke.Blend], smoke[h + 1][(int)Smoke.Blend], pet[h - 1][(int)Pet.Cat], pet[h + 1][(int)Pet.Cat])),
Frequency=2835943 Hz, Resolution=352.6164 ns, Timer=TSC
K.Greater(1, K.Sum(smoke[h][(int)Smoke.Dunhill], pet[h][(int)Pet.Horse]) -
DefaultJob : .NET Framework 4.6.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2600.0
K.Sum(smoke[h - 1][(int)Smoke.Dunhill], smoke[h + 1][(int)Smoke.Dunhill], pet[h - 1][(int)Pet.Horse], pet[h + 1][(int)Pet.Horse])),
 
K.Greater(1, K.Sum(smoke[h][(int)Smoke.Blend], drink[h][(int)Drink.Water]) -
Method Mean Error StdDev
K.Sum(smoke[h - 1][(int)Smoke.Blend], smoke[h + 1][(int)Smoke.Blend], drink[h - 1][(int)Drink.Water], drink[h+1][(int)Drink.Water])),
Norvig 65.32 ms 1.241 ms 1.328 ms
K.Greater(1, K.Sum(nationality[h][(int)Nationality.Norwegian], colour[h][(int)Colour.Blue]) -
Combin 93.62 ms 1.792 ms 1.918 ms
K.Sum(nationality[h-1][(int)Nationality.Norwegian], nationality[h+1][(int)Nationality.Norwegian], colour[h-1][(int)Colour.Blue], colour[h+1][(int)Colour.Blue]))
Solver 148.7 us 2.962 us 6.248 us
);
</pre>
I think that it is Enums (not the use of ''dynamic'' in a dictionary, which is only called 8 times in Combine), and Linq query comprehensions (versus for loops) slow down the 2 non_solver solutions. A non-type-safe non-Enum int version of Combine (not posted here) runs at ~21ms, which is a nearly 5x speed up for that algo. (Not tried with Norvig). Regardless, learning and using the Solver class (and that solution already uses ints rather than enums) provides a dramatic x 100 + performance increase compared to the best manual solutions.
 
=={{header|C++}}==
 
This is a modification of the C submission that uses rule classes and reduces the number of permutations evaluated.
 
<syntaxhighlight lang="cpp">
#include <stdio.h>
#include <string.h>
 
#define defenum(name, val0, val1, val2, val3, val4) \
enum name { val0, val1, val2, val3, val4 }; \
const char *name ## _str[] = { # val0, # val1, # val2, # val3, # val4 }
 
defenum( Attrib, Color, Man, Drink, Animal, Smoke );
defenum( Colors, Red, Green, White, Yellow, Blue );
defenum( Mans, English, Swede, Dane, German, Norwegian );
defenum( Drinks, Tea, Coffee, Milk, Beer, Water );
defenum( Animals, Dog, Birds, Cats, Horse, Zebra );
defenum( Smokes, PallMall, Dunhill, Blend, BlueMaster, Prince );
 
void printHouses(int ha[5][5]) {
const char **attr_names[5] = {Colors_str, Mans_str, Drinks_str, Animals_str, Smokes_str};
 
printf("%-10s", "House");
for (const char *name : Attrib_str) printf("%-10s", name);
printf("\n");
 
for (int i = 0; i < 5; i++) {
printf("%-10d", i);
for (int j = 0; j < 5; j++) printf("%-10s", attr_names[j][ha[i][j]]);
printf("\n");
}
}
 
struct HouseNoRule {
int houseno;
Attrib a; int v;
} housenos[] = {
{2, Drink, Milk}, // Cond 9: In the middle house they drink milk.
{0, Man, Norwegian} // Cond 10: The Norwegian lives in the first house.
};
 
struct AttrPairRule {
Attrib a1; int v1;
Attrib a2; int v2;
 
bool invalid(int ha[5][5], int i) {
return (ha[i][a1] >= 0 && ha[i][a2] >= 0) &&
((ha[i][a1] == v1 && ha[i][a2] != v2) ||
(ha[i][a1] != v1 && ha[i][a2] == v2));
}
} pairs[] = {
{Man, English, Color, Red}, // Cond 2: The English man lives in the red house.
{Man, Swede, Animal, Dog}, // Cond 3: The Swede has a dog.
{Man, Dane, Drink, Tea}, // Cond 4: The Dane drinks tea.
{Color, Green, Drink, Coffee}, // Cond 6: drink coffee in the green house.
{Smoke, PallMall, Animal, Birds}, // Cond 7: The man who smokes Pall Mall has birds.
{Smoke, Dunhill, Color, Yellow}, // Cond 8: In the yellow house they smoke Dunhill.
{Smoke, BlueMaster, Drink, Beer}, // Cond 13: The man who smokes Blue Master drinks beer.
{Man, German, Smoke, Prince} // Cond 14: The German smokes Prince
};
 
struct NextToRule {
Attrib a1; int v1;
Attrib a2; int v2;
 
bool invalid(int ha[5][5], int i) {
return (ha[i][a1] == v1) &&
((i == 0 && ha[i + 1][a2] >= 0 && ha[i + 1][a2] != v2) ||
(i == 4 && ha[i - 1][a2] != v2) ||
(ha[i + 1][a2] >= 0 && ha[i + 1][a2] != v2 && ha[i - 1][a2] != v2));
}
} nexttos[] = {
{Smoke, Blend, Animal, Cats}, // Cond 11: The man who smokes Blend lives in the house next to the house with cats.
{Smoke, Dunhill, Animal, Horse}, // Cond 12: In a house next to the house where they have a horse, they smoke Dunhill.
{Man, Norwegian, Color, Blue}, // Cond 15: The Norwegian lives next to the blue house.
{Smoke, Blend, Drink, Water} // Cond 16: They drink water in a house next to the house where they smoke Blend.
};
 
struct LeftOfRule {
Attrib a1; int v1;
Attrib a2; int v2;
 
bool invalid(int ha[5][5]) {
return (ha[0][a2] == v2) || (ha[4][a1] == v1);
}
 
bool invalid(int ha[5][5], int i) {
return ((i > 0 && ha[i][a1] >= 0) &&
((ha[i - 1][a1] == v1 && ha[i][a2] != v2) ||
(ha[i - 1][a1] != v1 && ha[i][a2] == v2)));
}
} leftofs[] = {
{Color, Green, Color, White} // Cond 5: The green house is immediately to the left of the white house.
};
 
bool invalid(int ha[5][5]) {
for (auto &rule : leftofs) if (rule.invalid(ha)) return true;
 
for (int i = 0; i < 5; i++) {
#define eval_rules(rules) for (auto &rule : rules) if (rule.invalid(ha, i)) return true;
eval_rules(pairs);
eval_rules(nexttos);
eval_rules(leftofs);
}
return false;
}
 
void search(bool used[5][5], int ha[5][5], const int hno, const int attr) {
int 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 (int 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);
}
}
 
foreach (int h in Houses)
{used[attr][i] = false;
K.AddConstraints(
K.Equal(colour[h][(int)Colour.Red], nationality[h][(int)Nationality.English]),
K.Equal(pet[h][(int)Pet.Dog], nationality[h][(int)Nationality.Swedish]),
K.Equal(drink[h][(int)Drink.Tea], nationality[h][(int)Nationality.Danish]),
K.Equal(drink[h][(int)Drink.Coffee], colour[h][(int)Colour.Green]),
K.Equal(smoke[h][(int)Smoke.PallMall], pet[h][(int)Pet.Bird]),
K.Equal(smoke[h][(int)Smoke.Dunhill], colour[h][(int)Colour.Yellow]),
K.Equal(smoke[h][(int)Smoke.BlueMaster], drink[h][(int)Drink.Beer]),
K.Equal(smoke[h][(int)Smoke.Prince], nationality[h][(int)Nationality.German])
);
}
ConstraintSolverSolution soln = K.Solve(new ConstraintSolverParams());
System.Console.WriteLine("House Colour Drink Nationality Smokes Pet");
System.Console.WriteLine("_____ ______ _____ ___________ ______ ___");
foreach (int h in Houses)
{
System.Console.WriteLine("{0,5} {1,-6} {2,-6} {3,-11} {4,-10} {5,-10}",
h+1, (Colour)P(soln, colour, h), (Drink)P(soln, drink, h), (Nationality)P(soln, nationality, h), (Smoke)P(soln, smoke, h), (Pet)P(soln, pet, h));
}
System.Console.ReadLine();
}
ha[hno][attr] = -1;
}
}
 
</lang>
int main() {
Produces:
bool used[5][5] = {};
int ha[5][5]; memset(ha, -1, sizeof(ha));
 
for (auto &rule : housenos) {
ha[rule.houseno][rule.a] = rule.v;
used[rule.a][rule.v] = true;
}
 
search(used, ha, 0, 0);
 
return 0;
}
</syntaxhighlight>
{{out}}
<pre>
$ g++ -O3 -std=c++11 zebra.cpp -o zebracpp && time ./zebracpp
House Colour Drink Nationality Smokes Pet
House Color Man Drink Animal Smoke
_____ ______ _____ ___________ ______ ___
0 1 Yellow Water Norwegian Water Dunhill Cats Dunhill Cat
1 2 Blue Tea Dane Danish Tea Blend Horse Blend
2 3 Red Milk English Milk PallMall Bird Birds PallMall
3 4 Green Coffee German Coffee Prince Zebra Prince Zebra
4 5 White Beer SwedishSwede Beer BlueMaster Dog BlueMaster
 
real 0m0.003s
user 0m0.000s
sys 0m0.000s
</pre>
 
My measured time is slower than that posted for the original C code, but on my machine this C++ code is faster than the original C code.
 
=={{header|Clojure}}==
This solution uses the contributed package ''clojure.core.logic'' (with ''clojure.tools.macro''), a mini-Kanren based logic solver. The solution is basically the one in [http://github.com/swannodette/logic-tutorial Swannodette's logic tutorial], adapted to the problem statement here.
<syntaxhighlight lang="clojure">(ns zebra.core
(:refer-clojure :exclude [==])
(:use [clojure.core.logic]
[clojure.tools.macro :as macro]))
 
(defne lefto [x y l]
([_ _ [x y . ?r]])
([_ _ [_ . ?r]] (lefto x y ?r)))
 
(defn nexto [x y l]
(conde
((lefto x y l))
((lefto y x l))))
 
(defn zebrao [hs]
(macro/symbol-macrolet [_ (lvar)]
(all
(== [_ _ _ _ _] hs)
(membero ['englishman _ _ _ 'red] hs)
(membero ['swede _ _ 'dog _] hs)
(membero ['dane _ 'tea _ _] hs)
(lefto [_ _ _ _ 'green] [_ _ _ _ 'white] hs)
(membero [_ _ 'coffee _ 'green] hs)
(membero [_ 'pallmall _ 'birds _] hs)
(membero [_ 'dunhill _ _ 'yellow] hs)
(== [_ _ [_ _ 'milk _ _] _ _ ] hs)
(firsto hs ['norwegian _ _ _ _])
(nexto [_ 'blend _ _ _] [_ _ _ 'cats _ ] hs)
(nexto [_ _ _ 'horse _] [_ 'dunhill _ _ _] hs)
(membero [_ 'bluemaster 'beer _ _] hs)
(membero ['german 'prince _ _ _] hs)
(nexto ['norwegian _ _ _ _] [_ _ _ _ 'blue] hs)
(nexto [_ _ 'water _ _] [_ 'blend _ _ _] hs)
(membero [_ _ _ 'zebra _] hs))))
 
(let [solns (run* [q] (zebrao q))
soln (first solns)
zebra-owner (->> soln (filter #(= 'zebra (% 3))) first (#(% 0)))]
(println "solution count:" (count solns))
(println "zebra owner is the" zebra-owner)
(println "full solution (in house order):")
(doseq [h soln] (println " " h)))
</syntaxhighlight>
{{output}}
<pre>solution count: 1
zebra owner is the german
full solution (in house order):
[norwegian dunhill water cats yellow]
[dane blend tea horse blue]
[englishman pallmall milk birds red]
[german prince coffee zebra green]
[swede bluemaster beer dog white]
</pre>
 
 
=== Alternate solution (Norvig-style) ===
{{libheader|clojure.math.combinatorics}}
 
This is adapted from a solution to a similar problem by Peter Norvig in his [https://www.udacity.com/course/design-of-computer-programs--cs212 Udacity course CS212], originally written in Python but equally applicable in any language with for-comprehensions.
 
<syntaxhighlight lang="clojure">(ns zebra
(:require [clojure.math.combinatorics :as c]))
 
(defn solve []
(let [arrangements (c/permutations (range 5))
before? #(= (inc %1) %2)
after? #(= (dec %1) %2)
next-to? #(or (before? %1 %2) (after? %1 %2))]
(for [[english swede dane norwegian german :as persons] arrangements
:when (zero? norwegian)
[red green white yellow blue :as colors] arrangements
:when (before? green white)
:when (= english red)
:when (after? blue norwegian)
[tea coffee milk beer water :as drinks] arrangements
:when (= 2 milk)
:when (= dane tea)
:when (= coffee green)
[pall-mall dunhill blend blue-master prince :as cigs] arrangements
:when (= german prince)
:when (= yellow dunhill)
:when (= blue-master beer)
:when (after? blend water)
[dog birds cats horse zebra :as pets] arrangements
:when (= swede dog)
:when (= pall-mall birds)
:when (next-to? blend cats)
:when (after? horse dunhill)]
(->> [[:english :swede :dane :norwegian :german]
[:red :green :white :yellow :blue]
[:tea :coffee :milk :beer :water]
[:pall-mall :dunhill :blend :blue-master :prince]
[:dog :birds :cats :horse :zebra]]
(map zipmap [persons colors drinks cigs pets])))))
 
 
(defn -main [& _]
(doseq [[[persons _ _ _ pets :as solution] i]
(map vector (solve) (iterate inc 1))
:let [zebra-house (some #(when (= :zebra (val %)) (key %)) pets)]]
(println "solution" i)
(println "The" (persons zebra-house) "owns the zebra.")
(println "house nationality color drink cig pet")
(println "----- ----------- ------- ------- ------------ ------")
(dotimes [i 5]
(println (apply format "%5s %-11s %-7s %-7s %-12s %-6s"
(map #(% i) (cons inc solution)))))))
</syntaxhighlight>
{{output}}
<pre>user=> (time (zebra/-main))
solution 1
The :german owns the zebra.
house nationality color drink cig pet
----- ----------- ------- ------- ------------ ------
1 :norwegian :yellow :water :dunhill :cats
2 :dane :blue :tea :blend :horse
3 :english :red :milk :pall-mall :birds
4 :german :green :coffee :prince :zebra
5 :swede :white :beer :blue-master :dog
"Elapsed time: 10.555482 msecs"
nil
</pre>
 
=={{header|Crystal}}==
{{trans|Ruby}}
<syntaxhighlight lang="ruby">CONTENT = {House: [""],
Nationality: %i[English Swedish Danish Norwegian German],
Colour: %i[Red Green White Blue Yellow],
Pet: %i[Dog Birds Cats Horse Zebra],
Drink: %i[Tea Coffee Milk Beer Water],
Smoke: %i[PallMall Dunhill BlueMaster Prince Blend]}
 
def adjacent?(n, i, g, e)
(0..3).any? { |x| (n[x] == i && g[x + 1] == e) || (n[x + 1] == i && g[x] == e) }
end
 
def leftof?(n, i, g, e)
(0..3).any? { |x| n[x] == i && g[x + 1] == e }
end
 
def coincident?(n, i, g, e)
n.each_index.any? { |x| n[x] == i && g[x] == e }
end
 
def solve_zebra_puzzle
CONTENT[:Nationality].each_permutation { |nation|
next unless nation.first == :Norwegian # 10
CONTENT[:Colour].each_permutation { |colour|
next unless leftof?(colour, :Green, colour, :White) # 5
next unless coincident?(nation, :English, colour, :Red) # 2
next unless adjacent?(nation, :Norwegian, colour, :Blue) # 15
CONTENT[:Pet].each_permutation { |pet|
next unless coincident?(nation, :Swedish, pet, :Dog) # 3
CONTENT[:Drink].each_permutation { |drink|
next unless drink[2] == :Milk # 9
next unless coincident?(nation, :Danish, drink, :Tea) # 4
next unless coincident?(colour, :Green, drink, :Coffee) # 6
CONTENT[:Smoke].each_permutation { |smoke|
next unless coincident?(smoke, :PallMall, pet, :Birds) # 7
next unless coincident?(smoke, :Dunhill, colour, :Yellow) # 8
next unless coincident?(smoke, :BlueMaster, drink, :Beer) # 13
next unless coincident?(smoke, :Prince, nation, :German) # 14
next unless adjacent?(smoke, :Blend, pet, :Cats) # 11
next unless adjacent?(smoke, :Blend, drink, :Water) # 16
next unless adjacent?(smoke, :Dunhill, pet, :Horse) # 12
print_out(nation, colour, pet, drink, smoke)
}
}
}
}
}
end
 
def print_out(nation, colour, pet, drink, smoke)
width = CONTENT.map { |k, v| {k.to_s.size, v.max_of { |y| y.to_s.size }}.max }
fmt = width.map { |w| "%-#{w}s" }.join(" ")
national = nation[pet.index(:Zebra).not_nil!]
puts "The Zebra is owned by the man who is #{national}", ""
puts fmt % CONTENT.keys, fmt % width.map { |w| "-" * w }
[nation, colour, pet, drink, smoke].transpose.each.with_index(1) { |x, n| puts fmt % ([n] + x) }
end
 
solve_zebra_puzzle</syntaxhighlight>
 
=={{header|Curry}}==
{{Works with|PAKCS}}
<syntaxhighlight lang="curry">import Constraint (allC, anyC)
import Findall (findall)
 
 
data House = H Color Man Pet Drink Smoke
 
data Color = Red | Green | Blue | Yellow | White
data Man = Eng | Swe | Dan | Nor | Ger
data Pet = Dog | Birds | Cats | Horse | Zebra
data Drink = Coffee | Tea | Milk | Beer | Water
data Smoke = PM | DH | Blend | BM | Prince
 
 
houses :: [House] -> Success
houses hs@[H1,_,H3,_,_] = -- 1
H _ _ _ Milk _ =:= H3 -- 9
& H _ Nor _ _ _ =:= H1 -- 10
& allC (`member` hs)
[ H Red Eng _ _ _ -- 2
, H _ Swe Dog _ _ -- 3
, H _ Dan _ Tea _ -- 4
, H Green _ _ Coffee _ -- 6
, H _ _ Birds _ PM -- 7
, H Yellow _ _ _ DH -- 8
, H _ _ _ Beer BM -- 13
, H _ Ger _ _ Prince -- 14
]
& H Green _ _ _ _ `leftTo` H White _ _ _ _ -- 5
& H _ _ _ _ Blend `nextTo` H _ _ Cats _ _ -- 11
& H _ _ Horse _ _ `nextTo` H _ _ _ _ DH -- 12
& H _ Nor _ _ _ `nextTo` H Blue _ _ _ _ -- 15
& H _ _ _ Water _ `nextTo` H _ _ _ _ Blend -- 16
where
x `leftTo` y = _ ++ [x,y] ++ _ =:= hs
x `nextTo` y = x `leftTo` y
? y `leftTo` x
 
 
member :: a -> [a] -> Success
member = anyC . (=:=)
 
 
main = findall $ \(hs,who) -> houses hs & H _ who Zebra _ _ `member` hs</syntaxhighlight>
{{Output}} Using [http://www-ps.informatik.uni-kiel.de/~pakcs/webpakcs/main.cgi web interface].
<pre>Execution time: 180 msec. / elapsed: 180 msec.
[([H Yellow Nor Cats Water DH,H Blue Dan Horse Tea Blend,H Red Eng Birds Milk PM,H Green Ger Zebra Coffee Prince,H White Swe Dog Beer BM],Ger)]</pre>
 
=={{header|D}}==
{{trans|Ada}}
Most foreach loops in this program are static.
<langsyntaxhighlight lang="d">import std.stdio, std.traits, std.algorithm, std.math;
 
enum Content { Beer, Coffee, Milk, Tea, Water,
Line 458 ⟶ 1,972:
Bird, Cat, Dog, Horse, Zebra }
enum Test { Drink, Person, Color, Smoke, Pet }
enum House { One, Two, Three, Four, Five };
 
alias TM = Content[EnumMembers!Test.length][EnumMembers!House.length] TM;
 
bool finalChecks(in ref TM M) pure nothrow @safe @nogc {
int diff(in Content a, in Content b, in Test ca, in Test cb)
nothrow @safe @nogc {
foreach (immutable h1; EnumMembers!House)
foreach (immutable h2; EnumMembers!House)
if (M[ca][h1] == a && M[cb][h2] == b)
return h1 - h2;
assert(0); // Useless but required.
}
 
Line 480 ⟶ 1,994:
}
 
bool constrained(in ref TM M, in Test atest) pure nothrow @safe @nogc {
with (Content) with (Test) with (House)
final switch (atest) {
Line 486 ⟶ 2,000:
return M[Drink][Three] == Milk;
case Person:
foreach (immutable h; EnumMembers!House)
if ((M[Person][h] == Norwegian && h != One) ||
(M[Person][h] == Danish && M[Drink][h] != Tea))
Line 492 ⟶ 2,006:
return true;
case Color:
foreach (immutable h; EnumMembers!House)
if ((M[Person][h] == English && M[Color][h] != Red) ||
(M[Drink][h] == Coffee && M[Color][h] != Green))
Line 498 ⟶ 2,012:
return true;
case Smoke:
foreach (immutable h; EnumMembers!House)
if ((M[Color][h] == Yellow && M[Smoke][h] != Dunhill) ||
(M[Smoke][h] == BlueMaster && M[Drink][h] != Beer) ||
Line 505 ⟶ 2,019:
return true;
case Pet:
foreach (immutable h; EnumMembers!House)
if ((M[Person][h] == Swedish && M[Pet][h] != Dog) ||
(M[Smoke][h] == PallMall && M[Pet][h] != Bird))
Line 516 ⟶ 2,030:
foreach (h; EnumMembers!House) {
writef("%5s: ", h);
foreach (immutable t; EnumMembers!Test)
writef("%10s ", M[t][h]);
writeln();
}
}
Line 531 ⟶ 2,045:
}
}
foreach (immutable i; 0 .. n) {
solve(M, t, n - 1);
swap(M[t][n % 2 ? 0 : i], M[t][n - 1]);
Line 539 ⟶ 2,053:
void main() {
TM M;
foreach (immutable t; EnumMembers!Test)
foreach (immutable h; EnumMembers!House)
M[t][h] = EnumMembers!Content[t * 5 + h];
 
solve(M, Test.Drink, 5);
}</langsyntaxhighlight>
{{out}}
<pre> One: Water Norwegian Yellow Dunhill Cat
Line 551 ⟶ 2,065:
Four: Coffee German Green Prince Zebra
Five: Beer Swedish White BlueMaster Dog </pre>
Run-time about 0.0604 seconds or less.
 
===Alternative Version===
{{trans|Python}}
This requires the module of the first D entry from the Permutations Task.
<lang d>import std.stdio, std.math, std.traits, std.typetuple;
<syntaxhighlight lang="d">import std.stdio, std.math, std.traits, std.typecons, std.typetuple, permutations1;
 
const(T[N][])uint permutationsFixedfactorial(T,in size_tuint Nn)(in T[N] items)pure nothrow{ @nogc @safe
in {
const(T[N])[] result;
assert(n <= 12);
T[N] row;
} body {
uint result = 1;
foreach (immutable i; 1 .. n + 1)
result *= i;
return result;
}
 
enum Number { One, Two, Three, Four, Five }
void perms(in T[] s, in T[] prefix=[]) nothrow {
enum Color { Red, Green, Blue, White, Yellow }
if (s.length)
enum Drink { Milk, Coffee, Water, Beer, Tea }
foreach (i, c; s)
enum Smoke { PallMall, Dunhill, Blend, BlueMaster, Prince }
perms(s[0 .. i] ~ s[i+1 .. $], prefix ~ c);
enum Pet { Dog, Cat, Zebra, Horse, Bird }
else {
enum Nation { British, Swedish, Danish, Norvegian, German }
row[] = prefix[];
result ~= row;
}
}
 
enum size_t M = EnumMembers!Number.length;
perms(items);
return result;
}
 
auto nullableRef(T)(ref T item) pure nothrow @nogc {
enum Number : uint {One, Two, Three, Four, Five };
return NullableRef!T(&item);
enum Color : uint {Red, Green, Blue, White, Yellow};
}
enum Drink : uint {Milk, Coffee, Water, Beer, Tea };
enum Smoke : uint {PallMall, Dunhill, Blend, BlueMaster, Prince};
enum Pet : uint {Dog, Cat, Zebra, Horse, Bird };
enum Nation : uint {British, Swedish, Danish, Norvegian, German};
 
bool isPossible(immutableNullableRef!(immutable Number[5M])* number,
immutableNullableRef!(immutable Color[5M])* color=null,
immutableNullableRef!(immutable Drink[5M])* drink=null,
immutableNullableRef!(immutable Smoke[5M])* smoke=null,
immutableNullableRef!(immutable Pet[5M])* pet=null) pure nothrow @safe @nogc {
if ((!number.isNull && number[Nation.Norvegian] != Number.One) ||
) pure nothrow {
if ((number!color.isNull && (*number)color[Nation.NorvegianBritish] != NumberColor.OneRed) ||
(color!drink.isNull && (*color)drink[Nation.BritishDanish] != ColorDrink.RedTea) ||
(drink!smoke.isNull && (*drink)smoke[Nation.DanishGerman] != DrinkSmoke.TeaPrince) ||
(smoke!pet.isNull && (*smoke)pet[Nation.GermanSwedish] != SmokePet.PrinceDog)) ||
(pet && (*pet)[Nation.Swedish] != Pet.Dog))
return false;
 
if (!number.isNull || !color.isNull || !drink.isNull || !smoke.isNull || !pet)
pet.isNull)
return true;
 
foreach (immutable i; 0 .. 5M) {
if (((*color)[i] == Color.Green && (*drink)[i] != Drink.Coffee) ||
((*smoke)[i] == Smoke.PallMall && (*pet)[i] != Pet.Bird) ||
((*color)[i] == Color.Yellow && (*smoke)[i] != Smoke.Dunhill) ||
((*number)[i] == Number.Three && (*drink)[i] != Drink.Milk) ||
((*smoke)[i] == Smoke.BlueMaster && (*drink)[i] != Drink.Beer)||
((*color)[i] == Color.Blue && (*number)[i] != Number.Two))
return false;
 
foreach (immutable j; 0 .. 5M) {
if ((*color)[i] == Color.Green && (*color)[j] == Color.White &&
(*number)[j] - (*number)[i] != 1)
return false;
 
immutable int diff = abs((*number)[i] - (*number)[j]);
if (((*smoke)[i] == Smoke.Blend && pet[j] == Pet.Cat && diff != 1) ||
(*pet)[ji] == Pet.CatHorse && smoke[j] == Smoke.Dunhill && diff != 1) ||
((*pet)smoke[i] == PetSmoke.HorseBlend && drink[j] == Drink.Water && diff != 1))
(*smoke)[j] == Smoke.Dunhill && diff != 1) ||
((*smoke)[i] == Smoke.Blend &&
(*drink)[j] == Drink.Water && diff != 1))
return false;
}
Line 624 ⟶ 2,135:
return true;
}
 
alias N = nullableRef; // At module level scope to be used with UFCS.
 
void main() {
enum size_t FM = M.factorial;
static immutable perms = permutationsFixed!(uint, 5)([0,1,2,3,4]);
static permsNumber = cast(immutable(Number[5][]))perms;
static permsColor = cast(immutable(Color[5][]))perms;
static permsDrink = cast(immutable(Drink[5][]))perms;
static permsSmoke = cast(immutable(Smoke[5][]))perms;
static permsPet = cast(immutable(Pet[5][]))perms;
immutable nation = [EnumMembers!Nation];
 
static immutable Number[M][FM] numberPerms = [EnumMembers!Number].permutations;
foreach (ref number; permsNumber)
static immutable Color[M][FM] colorPerms = [EnumMembers!Color].permutations;
if (isPossible(&number))
static immutable Drink[M][FM] drinkPerms = [EnumMembers!Drink].permutations;
foreach (ref color; permsColor)
static immutable Smoke[M][FM] smokePerms = [EnumMembers!Smoke].permutations;
if (isPossible(&number, &color))
static immutable Pet[M][FM] petPerms = [EnumMembers!Pet].permutations;
foreach (ref drink; permsDrink)
 
if (isPossible(&number, &color, &drink))
// You can reduce the compile-time computations using four casts like this:
foreach (ref smoke; permsSmoke)
// static colorPerms = cast(immutable Color[M][FM])numberPerms;
if (isPossible(&number, &color, &drink, &smoke))
 
foreach (ref pet; permsPet)
static immutable Nation[M] nation = [EnumMembers!Nation];
if (isPossible(&number,&color,&drink,&smoke,&pet)) {
 
foreach (immutable ref number; numberPerms)
if (isPossible(number.N))
foreach (immutable ref color; colorPerms)
if (isPossible(number.N, color.N))
foreach (immutable ref drink; drinkPerms)
if (isPossible(number.N, color.N, drink.N))
foreach (immutable ref smoke; smokePerms)
if (isPossible(number.N, color.N, drink.N, smoke.N))
foreach (immutable ref pet; petPerms)
if (isPossible(number.N, color.N, drink.N, smoke.N, pet.N)) {
writeln("Found a solution:");
foreach (x; TypeTuple!(nation, number, color, drink, smoke, pet))
drink, smoke, pet))
writefln("%6s: %12s%12s%12s%12s%12s",
(Unqual!(typeof(x[0]))).stringof,
x[0], x[1], x[2], x[3], x[4]);
writeln();
}
}</langsyntaxhighlight>
{{out}}
<pre>Found a solution:
Line 662 ⟶ 2,179:
Pet: Bird Dog Horse Cat Zebra
</pre>
Run-time about 0.76 seconds with the dmd compiler.
 
===Short Version===
{{trans|PicoLisp}}
This requires the module of the second D entry from the Permutations Task.
<syntaxhighlight lang="d">void main() {
import std.stdio, std.algorithm, permutations2;
 
enum E { Red, Green, Blue, White, Yellow,
Milk, Coffee, Water, Beer, Tea,
PallMall, Dunhill, Blend, BlueMaster, Prince,
Dog, Cat, Zebra, Horse, Birds,
British, Swedish, Danish, Norvegian, German }
 
enum has = (E[] a, E x, E[] b, E y) => a.countUntil(x) == b.countUntil(y);
enum leftOf = (E[] a, E x, E[] b, E y) => a.countUntil(x) == b.countUntil(y) + 1;
enum nextTo = (E[] a, E x, E[] b, E y) => leftOf(a, x, b, y) || leftOf(b, y, a, x);
 
with (E) foreach (houses; [Red, Blue, Green, Yellow, White].permutations)
if (leftOf(houses, White, houses, Green))
foreach (persons; [Norvegian, British, Swedish, German, Danish].permutations)
if (has(persons, British, houses, Red) && persons[0] == Norvegian &&
nextTo(persons, Norvegian, houses, Blue))
foreach (drinks; [Tea, Coffee, Milk, Beer, Water].permutations)
if (has(drinks, Tea, persons, Danish) &&
has(drinks, Coffee, houses, Green) && drinks[$ / 2] == Milk)
foreach (pets; [Dog, Birds, Cat, Horse, Zebra].permutations)
if (has(pets, Dog, persons, Swedish))
foreach (smokes; [PallMall, Dunhill, Blend, BlueMaster, Prince].permutations)
if (has(smokes, PallMall, pets, Birds) &&
has(smokes, Dunhill, houses, Yellow) &&
nextTo(smokes, Blend, pets, Cat) &&
nextTo(smokes, Dunhill, pets, Horse) &&
has(smokes, BlueMaster, drinks, Beer) &&
has(smokes, Prince, persons, German) &&
nextTo(drinks, Water, smokes, Blend))
writefln("%(%10s\n%)\n", [houses, persons, drinks, pets, smokes]);
}</syntaxhighlight>
{{out}}
<pre>[ Yellow, Blue, Red, Green, White]
[ Norvegian, Danish, British, German, Swedish]
[ Water, Tea, Milk, Coffee, Beer]
[ Cat, Horse, Birds, Zebra, Dog]
[ Dunhill, Blend, PallMall, Prince, BlueMaster]</pre>
The run-time is 0.03 seconds or less.
 
=={{header|EchoLisp}}==
We use the '''amb''' library to solve the puzzle. The number of tries - calls to zebra-puzzle - is only 1900, before finding all solutions. Note that there are no declarations for things (cats, tea, ..) or categories (animals, drinks, ..) which are discovered when reading the constraints.
<syntaxhighlight lang="scheme">
(lib 'hash)
(lib 'amb)
 
;; return #f or house# for thing/category
;; houses := (0 1 2 3 4)
(define (house-get H category thing houses)
(for/or ((i houses)) #:continue (!equal? (hash-ref (vector-ref H i) category) thing)
i))
;; return house # for thing (eg cat) in category (eq animals)
;; add thing if not already here
(define-syntax-rule (house-set thing category)
(or
(house-get H 'category 'thing houses)
(dispatch H 'category 'thing context houses )))
;; we know that thing/category is in a given house
(define-syntax-rule (house-force thing category house)
(dispatch H 'category 'thing context houses house))
;; return house# or fail if impossible
(define (dispatch H category thing context houses (forced #f))
(define house (or forced (amb context houses))) ;; get a house number
(when (hash-ref (vector-ref H house) category) (amb-fail)) ;; fail if occupied
(hash-set (vector-ref H house) category thing) ;; else remember house contents
house)
(define (house-next h1 h2)
(amb-require (or (= h1 (1+ h2)) (= h1 (1- h2)))))
(define (zebra-puzzle context houses )
(define H (build-vector 5 make-hash)) ;; house[i] := hash(category) -> thing
; In the middle house they drink milk.
(house-force milk drinks 2)
;The Norwegian lives in the first house.
(house-force norvegian people 0)
; The English man lives in the red house.
(house-force red colors(house-set english people))
; The Swede has a dog.
(house-force dog animals (house-set swede people))
; The Dane drinks tea.
(house-force tea drinks (house-set dane people))
; The green house is immediately to the left of the white house.
(amb-require (= (house-set green colors) (1- (house-set white colors))))
; They drink coffee in the green house.
(house-force coffee drinks (house-set green colors))
; The man who smokes Pall Mall has birds.
(house-force birds animals (house-set pallmall smoke))
; In the yellow house they smoke Dunhill.
(house-force dunhill smoke (house-set yellow colors))
; The Norwegian lives next to the blue house.
(house-next (house-set norvegian people) (house-set blue colors))
; The man who smokes Blend lives in the house next to the house with cats.
(house-next (house-set blend smoke) (house-set cats animals))
; In a house next to the house where they have a horse, they smoke Dunhill.
(house-next (house-set horse animals) (house-set dunhill smoke))
; The man who smokes Blue Master drinks beer.
(house-force beer drinks (house-set bluemaster smoke))
; The German smokes Prince.
(house-force prince smoke (house-set german people))
; They drink water in a house next to the house where they smoke Blend.
(house-next (house-set water drinks) (house-set blend smoke))
 
;; Finally .... the zebra 🐴
(house-set 🐴 animals)
(for ((i houses))
(writeln i (hash-values (vector-ref H i))))
(writeln '----------)
(amb-fail) ;; will ensure ALL solutions are printed
)
</syntaxhighlight>
{{out}}
<syntaxhighlight lang="scheme">
(define (task)
(amb-run zebra-puzzle (amb-make-context) (iota 5)))
 
(task)
0 (norvegian yellow dunhill cats water)
1 (dane tea blue blend horse)
2 (milk english red pallmall birds)
3 (green coffee german prince 🐴)
4 (swede dog white bluemaster beer)
----------
→ #f
 
</syntaxhighlight>
 
=={{header|Elixir}}==
{{trans|Ruby}}
<syntaxhighlight lang="elixir">defmodule ZebraPuzzle do
defp adjacent?(n,i,g,e) do
Enum.any?(0..3, fn x ->
(Enum.at(n,x)==i and Enum.at(g,x+1)==e) or (Enum.at(n,x+1)==i and Enum.at(g,x)==e)
end)
end
defp leftof?(n,i,g,e) do
Enum.any?(0..3, fn x -> Enum.at(n,x)==i and Enum.at(g,x+1)==e end)
end
defp coincident?(n,i,g,e) do
Enum.with_index(n) |> Enum.any?(fn {x,idx} -> x==i and Enum.at(g,idx)==e end)
end
def solve(content) do
colours = permutation(content[:Colour])
pets = permutation(content[:Pet])
drinks = permutation(content[:Drink])
smokes = permutation(content[:Smoke])
Enum.each(permutation(content[:Nationality]), fn nation ->
if hd(nation) == :Norwegian, do: # 10
Enum.each(colours, fn colour ->
if leftof?(colour, :Green, colour, :White) and # 5
coincident?(nation, :English, colour, :Red) and # 2
adjacent?(nation, :Norwegian, colour, :Blue), do: # 15
Enum.each(pets, fn pet ->
if coincident?(nation, :Swedish, pet, :Dog), do: # 3
Enum.each(drinks, fn drink ->
if Enum.at(drink,2) == :Milk and # 9
coincident?(nation, :Danish, drink, :Tea) and # 4
coincident?(colour, :Green, drink, :Coffee), do: # 6
Enum.each(smokes, fn smoke ->
if coincident?(smoke, :PallMall, pet, :Birds) and # 7
coincident?(smoke, :Dunhill, colour, :Yellow) and # 8
coincident?(smoke, :BlueMaster, drink, :Beer) and # 13
coincident?(smoke, :Prince, nation, :German) and # 14
adjacent?(smoke, :Blend, pet, :Cats) and # 11
adjacent?(smoke, :Blend, drink, :Water) and # 16
adjacent?(smoke, :Dunhill, pet, :Horse), do: # 12
print_out(content, transpose([nation, colour, pet, drink, smoke]))
end)end)end)end)end)
end
defp permutation([]), do: [[]]
defp permutation(list) do
for x <- list, y <- permutation(list -- [x]), do: [x|y]
end
defp transpose(lists) do
List.zip(lists) |> Enum.map(&Tuple.to_list/1)
end
defp print_out(content, result) do
width = for {k,v}<-content, do: Enum.map([k|v], &length(to_char_list &1)) |> Enum.max
fmt = Enum.map_join(width, " ", fn w -> "~-#{w}s" end) <> "~n"
nation = Enum.find(result, fn x -> :Zebra in x end) |> hd
IO.puts "The Zebra is owned by the man who is #{nation}\n"
:io.format fmt, Keyword.keys(content)
:io.format fmt, Enum.map(width, fn w -> String.duplicate("-", w) end)
fmt2 = String.replace(fmt, "s", "w", global: false)
Enum.with_index(result)
|> Enum.each(fn {x,i} -> :io.format fmt2, [i+1 | x] end)
end
end
 
content = [ House: '',
Nationality: ~w[English Swedish Danish Norwegian German]a,
Colour: ~w[Red Green White Blue Yellow]a,
Pet: ~w[Dog Birds Cats Horse Zebra]a,
Drink: ~w[Tea Coffee Milk Beer Water]a,
Smoke: ~w[PallMall Dunhill BlueMaster Prince Blend]a ]
 
ZebraPuzzle.solve(content)</syntaxhighlight>
 
{{out}}
<pre>
The Zebra is owned by the man who is German
 
House Nationality Colour Pet Drink Smoke
----- ----------- ------ ----- ------ ----------
1 Norwegian Yellow Cats Water Dunhill
2 Danish Blue Horse Tea Blend
3 English Red Birds Milk PallMall
4 German Green Zebra Coffee Prince
5 Swedish White Dog Beer BlueMaster
</pre>
 
=={{header|Erlang}}==
This solution generates all houses that fits the rules for single houses, then it checks multi-house rules. It would be faster to check multi-house rules while generating the houses. I have not added this complexity since the current program takes just a few seconds.
<syntaxhighlight lang="erlang">
-module( zebra_puzzle ).
 
-export( [task/0] ).
 
-record( house, {colour, drink, nationality, number, pet, smoke} ).
-record( sorted_houses, {house_1s=[], house_2s=[], house_3s=[], house_4s=[], house_5s=[]} ).
 
task() ->
Houses = [#house{colour=C, drink=D, nationality=N, number=Nr, pet=P, smoke=S} || C <- all_colours(), D <- all_drinks(), N <- all_nationalities(), Nr <- all_numbers(), P <- all_pets(), S <- all_smokes(), is_all_single_house_rules_ok(C, D, N, Nr, P, S)],
Sorted_houses = lists:foldl( fun house_number_sort/2, #sorted_houses{}, Houses ),
Streets = [[H1, H2, H3, H4, H5] || H1 <- Sorted_houses#sorted_houses.house_1s, H2 <- Sorted_houses#sorted_houses.house_2s, H3 <- Sorted_houses#sorted_houses.house_3s, H4 <- Sorted_houses#sorted_houses.house_4s, H5 <- Sorted_houses#sorted_houses.house_5s, is_all_multi_house_rules_ok(H1, H2, H3, H4, H5)],
[Nationality] = [N || #house{nationality=N, pet=zebra} <- lists:flatten(Streets)],
io:fwrite( "~p owns the zebra~n", [Nationality] ),
io:fwrite( "All solutions ~p~n", [Streets] ),
io:fwrite( "Number of solutions ~p~n", [erlang:length(Streets)] ).
 
 
 
all_colours() -> [blue, green, red, white, yellow].
 
all_drinks() -> [beer, coffe, milk, tea, water].
 
all_nationalities() -> [danish, english, german, norveigan, swedish].
 
all_numbers() -> [1, 2, 3, 4, 5].
 
all_pets() -> [birds, cats, dog, horse, zebra].
 
all_smokes() -> [blend, 'blue master', dunhill, 'pall mall', prince].
 
house_number_sort( #house{number=1}=House, #sorted_houses{house_1s=Houses_1s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_1s=[House | Houses_1s]};
house_number_sort( #house{number=2}=House, #sorted_houses{house_2s=Houses_2s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_2s=[House | Houses_2s]};
house_number_sort( #house{number=3}=House, #sorted_houses{house_3s=Houses_3s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_3s=[House | Houses_3s]};
house_number_sort( #house{number=4}=House, #sorted_houses{house_4s=Houses_4s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_4s=[House | Houses_4s]};
house_number_sort( #house{number=5}=House, #sorted_houses{house_5s=Houses_5s}=Sorted_houses ) -> Sorted_houses#sorted_houses{house_5s=[House | Houses_5s]}.
 
is_all_different( [_H] ) -> true;
is_all_different( [H | T] ) -> not lists:member( H, T ) andalso is_all_different( T ).
 
is_all_multi_house_rules_ok( House1, House2, House3, House4, House5 ) ->
is_rule_1_ok( House1, House2, House3, House4, House5 )
andalso is_rule_5_ok( House1, House2, House3, House4, House5 )
andalso is_rule_11_ok( House1, House2, House3, House4, House5 )
andalso is_rule_12_ok( House1, House2, House3, House4, House5 )
andalso is_rule_15_ok( House1, House2, House3, House4, House5 )
andalso is_rule_16_ok( House1, House2, House3, House4, House5 ).
 
is_all_single_house_rules_ok( Colour, Drink, Nationality, Number, Pet, Smoke ) ->
is_rule_ok( {rule_number, 2}, {Nationality, english}, {Colour, red})
andalso is_rule_ok( {rule_number, 3}, {Nationality, swedish}, {Pet, dog})
andalso is_rule_ok( {rule_number, 4}, {Nationality, danish}, {Drink, tea})
andalso is_rule_ok( {rule_number, 6}, {Drink, coffe}, {Colour, green})
andalso is_rule_ok( {rule_number, 7}, {Smoke, 'pall mall'}, {Pet, birds})
andalso is_rule_ok( {rule_number, 8}, {Colour, yellow}, {Smoke, dunhill})
andalso is_rule_ok( {rule_number, 9}, {Number, 3}, {Drink, milk})
andalso is_rule_ok( {rule_number, 10}, {Nationality, norveigan}, {Number, 1})
andalso is_rule_ok( {rule_number, 13}, {Smoke, 'blue master'}, {Drink, beer})
andalso is_rule_ok( {rule_number, 14}, {Nationality, german}, {Smoke, prince}).
 
is_rule_ok( _Rule_number, {A, A}, {B, B} ) -> true;
is_rule_ok( _Rule_number, _A, {B, B} ) -> false;
is_rule_ok( _Rule_number, {A, A}, _B ) -> false;
is_rule_ok( _Rule_number, _A, _B ) -> true.
 
is_rule_1_ok( #house{number=1}=H1, #house{number=2}=H2, #house{number=3}=H3, #house{number=4}=H4, #house{number=5}=H5 ) ->
is_all_different( [H1#house.colour, H2#house.colour, H3#house.colour, H4#house.colour, H5#house.colour] )
andalso is_all_different( [H1#house.drink, H2#house.drink, H3#house.drink, H4#house.drink, H5#house.drink] )
andalso is_all_different( [H1#house.nationality, H2#house.nationality, H3#house.nationality, H4#house.nationality, H5#house.nationality] )
andalso is_all_different( [H1#house.pet, H2#house.pet, H3#house.pet, H4#house.pet, H5#house.pet] )
andalso is_all_different( [H1#house.smoke, H2#house.smoke, H3#house.smoke, H4#house.smoke, H5#house.smoke] );
is_rule_1_ok( _House1, _House2, _House3, _House4, _House5 ) -> false.
 
is_rule_5_ok( #house{colour=green}, #house{colour=white}, _House3, _House4, _House5 ) -> true;
is_rule_5_ok( _House1, #house{colour=green}, #house{colour=white}, _House4, _House5 ) -> true;
is_rule_5_ok( _House1, _House2, #house{colour=green}, #house{colour=white}, _House5 ) -> true;
is_rule_5_ok( _House1, _House2, _House3, #house{colour=green}, #house{colour=white} ) -> true;
is_rule_5_ok( _House1, _House2, _House3, _House4, _House5 ) -> false.
 
is_rule_11_ok( #house{smoke=blend}, #house{pet=cats}, _House3, _House4, _House5 ) -> true;
is_rule_11_ok( _House1, #house{smoke=blend}, #house{pet=cats}, _House4, _House5 ) -> true;
is_rule_11_ok( _House1, _House2, #house{smoke=blend}, #house{pet=cats}, _House5 ) -> true;
is_rule_11_ok( _House1, _House2, _House3, #house{smoke=blend}, #house{pet=cats} ) -> true;
is_rule_11_ok( #house{pet=cats}, #house{smoke=blend}, _House3, _House4, _House5 ) -> true;
is_rule_11_ok( _House1, #house{pet=cats}, #house{smoke=blend}, _House4, _House5 ) -> true;
is_rule_11_ok( _House1, _House2, #house{pet=cats}, #house{smoke=blend}, _House5 ) -> true;
is_rule_11_ok( _House1, _House2, _House3, #house{pet=cats}, #house{smoke=blend} ) -> true;
is_rule_11_ok( _House1, _House2, _House3, _House4, _House5 ) -> false.
 
is_rule_12_ok( #house{smoke=dunhill}, #house{pet=horse}, _House3, _House4, _House5 ) -> true;
is_rule_12_ok( _House1, #house{smoke=dunhill}, #house{pet=horse}, _House4, _House5 ) -> true;
is_rule_12_ok( _House1, _House2, #house{smoke=dunhill}, #house{pet=horse}, _House5 ) -> true;
is_rule_12_ok( _House1, _House2, _House3, #house{smoke=dunhill}, #house{pet=horse} ) -> true;
is_rule_12_ok( #house{pet=horse}, #house{smoke=dunhill}, _House3, _House4, _House5 ) -> true;
is_rule_12_ok( _House1, #house{pet=horse}, #house{smoke=dunhill}, _House4, _House5 ) -> true;
is_rule_12_ok( _House1, _House2, #house{pet=horse}, #house{smoke=dunhill}, _House5 ) -> true;
is_rule_12_ok( _House1, _House2, _House3, #house{pet=horse}, #house{smoke=dunhill} ) -> true;
is_rule_12_ok( _House1, _House2, _House3, _House4, _House5 ) -> false.
 
is_rule_15_ok( #house{nationality=norveigan}, #house{colour=blue}, _House3, _House4, _House5 ) -> true;
is_rule_15_ok( _House1, #house{nationality=norveigan}, #house{colour=blue}, _House4, _House5 ) -> true;
is_rule_15_ok( _House1, _House2, #house{nationality=norveigan}, #house{colour=blue}, _House5 ) -> true;
is_rule_15_ok( _House1, _House2, _House3, #house{nationality=norveigan}, #house{colour=blue} ) -> true;
is_rule_15_ok( #house{colour=blue}, #house{nationality=norveigan}, _House3, _House4, _House5 ) -> true;
is_rule_15_ok( _House1, #house{colour=blue}, #house{nationality=norveigan}, _House4, _House5 ) -> true;
is_rule_15_ok( _House1, _House2, #house{drink=water}, #house{nationality=norveigan}, _House5 ) -> true;
is_rule_15_ok( _House1, _House2, _House3, #house{drink=water}, #house{nationality=norveigan} ) -> true;
is_rule_15_ok( _House1, _House2, _House3, _House4, _House5 ) -> false.
 
is_rule_16_ok( #house{smoke=blend}, #house{drink=water}, _House3, _House4, _House5 ) -> true;
is_rule_16_ok( _House1, #house{smoke=blend}, #house{drink=water}, _House4, _House5 ) -> true;
is_rule_16_ok( _House1, _House2, #house{smoke=blend}, #house{drink=water}, _House5 ) -> true;
is_rule_16_ok( _House1, _House2, _House3, #house{smoke=blend}, #house{drink=water} ) -> true;
is_rule_16_ok( #house{drink=water}, #house{smoke=blend}, _House3, _House4, _House5 ) -> true;
is_rule_16_ok( _House1, #house{drink=water}, #house{smoke=blend}, _House4, _House5 ) -> true;
is_rule_16_ok( _House1, _House2, #house{drink=water}, #house{smoke=blend}, _House5 ) -> true;
is_rule_16_ok( _House1, _House2, _House3, #house{drink=water}, #house{smoke=blend} ) -> true;
is_rule_16_ok( _House1, _House2, _House3, _House4, _House5 ) -> false.
</syntaxhighlight>
{{out}}
<pre>
10> zebra_puzzle:task().
german owns the zebra
All solutions [[{house,yellow,water,norveigan,1,cats,dunhill},
{house,blue,tea,danish,2,horse,blend},
{house,red,milk,english,3,birds,'pall mall'},
{house,green,coffe,german,4,zebra,prince},
{house,white,beer,swedish,5,dog,'blue master'}]]
Number of solutions: 1
</pre>
 
=={{header|ERRE}}==
<syntaxhighlight lang="erre">
PROGRAM ZEBRA_PUZZLE
 
DIM DRINK$[4],NATION$[4],COLR$[4],SMOKE$[4],ANIMAL$[4]
DIM PERM$[120],X$[4]
 
PROCEDURE PERMUTATION(X$[]->X$[],OK)
LOCAL I%,J%
FOR I%=UBOUND(X$,1)-1 TO 0 STEP -1 DO
EXIT IF X$[I%]<X$[I%+1]
END FOR
IF I%<0 THEN OK=FALSE EXIT PROCEDURE END IF
J%=UBOUND(X$,1)
WHILE X$[J%]<=X$[I%] DO
J%=J%-1
END WHILE
SWAP(X$[I%],X$[J%])
I%=I%+1
J%=UBOUND(X$,1)
WHILE I%<J% DO
SWAP(X$[I%],X$[J%])
I%=I%+1
J%=J%-1
END WHILE
OK=TRUE
END PROCEDURE
 
BEGIN
 
! The names (only used for printing the results)
 
DATA("Beer","Coffee","Milk","Tea","Water")
DATA("Denmark","England","Germany","Norway","Sweden")
DATA("Blue","Green","Red","White","Yellow")
DATA("Blend","BlueMaster","Dunhill","PallMall","Prince")
DATA("Birds","Cats","Dog","Horse","Zebra")
 
FOR I%=0 TO 4 DO READ(DRINK$[I%]) END FOR
FOR I%=0 TO 4 DO READ(NATION$[I%]) END FOR
FOR I%=0 TO 4 DO READ(COLR$[I%]) END FOR
FOR I%=0 TO 4 DO READ(SMOKE$[I%]) END FOR
FOR I%=0 TO 4 DO READ(ANIMAL$[I%]) END FOR
 
! Some single-character tags:
A$="A" B$="B" c$="C" d$="D" e$="E"
 
! ERRE doesn't have enumerations!
Beer$=A$ Coffee$=B$ Milk$=c$ TeA$=d$ Water$=e$
Denmark$=A$ England$=B$ Germany$=c$ Norway$=d$ Sweden$=e$
Blue$=A$ Green$=B$ Red$=c$ White$=d$ Yellow$=e$
Blend$=A$ BlueMaster$=B$ Dunhill$=c$ PallMall$=d$ Prince$=e$
Birds$=A$ Cats$=B$ Dog$=c$ Horse$=d$ ZebrA$=e$
 
PRINT(CHR$(12);)
 
! Create the 120 permutations of 5 objects:
 
X$[0]=A$ X$[1]=B$ X$[2]=C$ X$[3]=D$ X$[4]=E$
 
REPEAT
P%=P%+1
PERM$[P%]=X$[0]+X$[1]+X$[2]+X$[3]+X$[4]
PERMUTATION(X$[]->X$[],OK)
UNTIL NOT OK
 
! Solve:
SOLUTIONS%=0
T1=TIMER
FOR NATION%=1 TO 120 DO
NATION$=PERM$[NATION%]
IF LEFT$(NATION$,1)=Norway$ THEN
FOR COLR%=1 TO 120 DO
COLR$=PERM$[COLR%]
IF INSTR(COLR$,Green$+White$)<>0 AND INSTR(NATION$,England$)=INSTR(COLR$,Red$) AND ABS(INSTR(NATION$,Norway$)-INSTR(COLR$,Blue$))=1 THEN
FOR DRINK%=1 TO 120 DO
DRINK$=PERM$[DRINK%]
IF MID$(DRINK$,3,1)=Milk$ AND INSTR(NATION$,Denmark$)=INSTR(DRINK$,TeA$) AND INSTR(DRINK$,Coffee$)=INSTR(COLR$,Green$) THEN
FOR SmOKe%=1 TO 120 DO
SmOKe$=PERM$[SMOKE%]
IF INSTR(NATION$,Germany$)=INSTR(SmOKe$,Prince$) AND INSTR(SmOKe$,BlueMaster$)=INSTR(DRINK$,Beer$) AND ABS(INSTR(SmOKe$,Blend$)-INSTR(DRINK$,Water$))=1 AND INSTR(SmOKe$,Dunhill$)=INSTR(COLR$,Yellow$) THEN
FOR ANIMAL%=1 TO 120 DO
ANIMAL$=PERM$[ANIMAL%]
IF INSTR(NATION$,Sweden$)=INSTR(ANIMAL$,Dog$) AND INSTR(SmOKe$,PallMall$)=INSTR(ANIMAL$,Birds$) AND ABS(INSTR(SmOKe$,Blend$)-INSTR(ANIMAL$,Cats$))=1 AND ABS(INSTR(SmOKe$,Dunhill$)-INSTR(ANIMAL$,Horse$))=1 THEN
PRINT("House Drink Nation Colour Smoke Animal")
PRINT("---------------------------------------------------------------------------")
FOR house%=1 TO 5 DO
PRINT(house%;)
PRINT(TAB(10);DRINK$[ASC(MID$(DRINK$,house%))-65];)
PRINT(TAB(25);NATION$[ASC(MID$(NATION$,house%))-65];)
PRINT(TAB(40);COLR$[ASC(MID$(COLR$,house%))-65];)
PRINT(TAB(55);SMOKE$[ASC(MID$(SmOKe$,house%))-65];)
PRINT(TAB(70);ANIMAL$[ASC(MID$(ANIMAL$,house%))-65])
END FOR
SOLUTIONS%=SOLUTIONS%+1
END IF
END FOR ! ANIMAL%
END IF
END FOR ! SmOKe%
END IF
END FOR ! DRINK%
END IF
END FOR ! COLR%
END IF
END FOR ! NATION%
PRINT("Number of solutions=";SOLUTIONS%)
PRINT("Solved in ";TIMER-T1;" seconds")
END PROGRAM</syntaxhighlight>
{{out}}
<pre>
House Drink Nation Colour Smoke Animal
---------------------------------------------------------------------------
1 Water Norway Yellow Dunhill Cats
2 Tea Denmark Blue Blend Horse
3 Milk England Red PallMall Birds
4 Coffee Germany Green Prince Zebra
5 Beer Sweden White BlueMaster Dog
Number of solutions= 1
Solved in .109375 seconds</pre>
 
=={{header|F_Sharp|F#}}==
This task uses [[Permutations_by_swapping#F.23]]
<syntaxhighlight lang="fsharp">
(*Here I solve the Zebra puzzle using Plain Changes, definitely a challenge to some campanoligist to solve it using Grandsire Doubles.
Nigel Galloway: January 27th., 2017 *)
type N = |English=0 |Swedish=1|Danish=2 |German=3|Norwegian=4
type I = |Tea=0 |Coffee=1 |Milk=2 |Beer=3 |Water=4
type G = |Dog=0 |Birds=1 |Cats=2 |Horse=3 |Zebra=4
type E = |Red=0 |Green=1 |White=2 |Blue=3 |Yellow=4
type L = |PallMall=0|Dunhill=1|BlueMaster=2|Prince=3|Blend=4
type NIGELz={Nz:N[];Iz:I[];Gz:G[];Ez:E[];Lz:L[]}
let fn (i:'n[]) g (e:'g[]) l = //coincident?
let rec _fn = function
|5 -> false
|ig when (i.[ig]=g && e.[ig]=l) -> true
|ig -> _fn (ig+1)
_fn 0
let fi (i:'n[]) g (e:'g[]) l = //leftof?
let rec _fn = function
|4 -> false
|ig when (i.[ig]=g && e.[ig+1]=l) -> true
|ig -> _fn (ig+1)
_fn 0
let fg (i:'n[]) g (e:'g[]) l = (fi i g e l || fi e l i g) //adjacent?
let n = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<N>)->n:?>N|]|>Seq.filter(fun n->n.[0]=N.Norwegian) //#10
let i = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<I>)->n:?>I|]|>Seq.filter(fun n->n.[2]=I.Milk) //# 9
let g = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<G>)->n:?>G|]
let e = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<E>)->n:?>E|]|>Seq.filter(fun n->fi n E.Green n E.White) //# 5
let l = Ring.PlainChanges [|for n in System.Enum.GetValues(typeof<L>)->n:?>L|]
match n|>Seq.map(fun n->{Nz=n;Iz=[||];Gz=[||];Ez=[||];Lz=[||]})
|>Seq.collect(fun n->i|>Seq.map(fun i->{n with Iz=i}))|>Seq.filter(fun n-> fn n.Nz N.Danish n.Iz I.Tea) //# 4
|>Seq.collect(fun n->g|>Seq.map(fun i->{n with Gz=i}))|>Seq.filter(fun n-> fn n.Nz N.Swedish n.Gz G.Dog) //# 3
|>Seq.collect(fun n->e|>Seq.map(fun i->{n with Ez=i}))|>Seq.filter(fun n-> fn n.Nz N.English n.Ez E.Red && //# 2
fn n.Ez E.Green n.Iz I.Coffee&& //# 6
fg n.Nz N.Norwegian n.Ez E.Blue) //#15
|>Seq.collect(fun n->l|>Seq.map(fun i->{n with Lz=i}))|>Seq.tryFind(fun n->fn n.Lz L.PallMall n.Gz G.Birds && //# 7
fg n.Lz L.Blend n.Gz G.Cats && //#11
fn n.Lz L.Prince n.Nz N.German&& //#14
fg n.Lz L.Blend n.Iz I.Water && //#16
fg n.Lz L.Dunhill n.Gz G.Horse && //#12
fn n.Lz L.Dunhill n.Ez E.Yellow&& //# 8
fn n.Iz I.Beer n.Lz L.BlueMaster) with //#13
|Some(nn) -> nn.Gz |> Array.iteri(fun n g -> if (g = G.Zebra) then printfn "\nThe man who owns a zebra is %A\n" nn.Nz.[n]); printfn "%A" nn
|None -> printfn "No solution found"
</syntaxhighlight>
{{out}}
<pre>
The man who owns a zebra is German
{Nz = [|Norwegian; Danish; English; German; Swedish|];
Iz = [|Water; Tea; Milk; Coffee; Beer|];
Gz = [|Cats; Horse; Birds; Zebra; Dog|];
Ez = [|Yellow; Blue; Red; Green; White|];
Lz = [|Dunhill; Blend; PallMall; Prince; BlueMaster|];}
</pre>
 
=={{header|FormulaOne}}==
<syntaxhighlight lang="formulaone">
// First, let's give some type-variables some values:
Nationality = Englishman | Swede | Dane | Norwegian | German
Colour = Red | Green | Yellow | Blue | White
Cigarette = PallMall | Dunhill | BlueMaster | Blend | Prince
Domestic = Dog | Bird | Cat | Zebra | Horse
Beverage = Tea | Coffee | Milk | Beer | Water
HouseRow = First | Second | Third | Fourth | Fifth
{
We use injections to make the array-elements unique.
Example: 'Pet' is an array of unique elements of type 'Domestic', indexed by 'Nationality'.
In the predicate 'Zebra', we use this injection 'Pet' to define the array-variable 'pet'
as a parameter of the 'Zebra'-predicate.
The symbol used is the '->>'. 'Nationality->>Domestic' can be read as 'Domestic(Nationality)'
in "plain array-speak";
the difference being that the elements are by definition unique (cf. 'injective function').
So, in FormulaOne we use a formula like: 'pet(Swede) = Dog', which simply means that the 'Swede'
(type 'Nationality') has a 'pet' (type 'Pet', of type 'Domestic', indexed by 'Nationality'),
which appears to be a 'Dog' (type 'Domestic').
Or, one could say that the 'Swede' has been mapped to the 'Dog' (Oh, well...).
}
Pet = Nationality->>Domestic
Drink = Nationality->>Beverage
HouseColour = Nationality->>Colour
Smoke = Nationality->>Cigarette
HouseOrder = HouseRow->>Nationality
pred Zebra(house_olour::HouseColour, pet::Pet, smoke::Smoke, drink::Drink, house_order::HouseOrder) iff
// For convenience sake, some temporary place_holder variables are used.
// An underscore distinguishes them:
 
house_colour(green_house) = Green &
house_colour(white_house) = White &
house_colour(yellow_house) = Yellow &
smoke(pallmall_smoker) = PallMall &
smoke(blend_smoker) = Blend &
smoke(dunhill_smoker) = Dunhill &
smoke(bluemaster_smoker) = BlueMaster &
pet(cat_keeper) = Cat &
pet(neighbour_dunhill_smoker) = Horse &
 
{ 2. The English man lives in the red house: }
house_colour(Englishman) = Red &
{ 3. The Swede has a dog: }
pet(Swede) = Dog &
{ 4. The Dane drinks tea: }
drink(Dane) = Tea &
{ 'smoke' and 'drink' are both nouns, like the other variables.
One could read the formulas like: 'the colour of the Englishman's house is Red' ->
'the Swede's pet is a dog' -> 'the Dane's drink is tea'.
}
{ 5. The green house is immediately to the left of the white house.
The local predicate 'LeftOf' (see below) determines the house order: }
LeftOf(green_house, white_house, house_order) &
{ 6. They drink coffee in the green house: }
drink(green_house) = Coffee &
{ 7. The man who smokes Pall Mall has birds: }
pet(pallmall_smoker) = Bird &
{ 8. In the yellow house they smoke Dunhill: }
smoke(yellow_house) = Dunhill &
{ 9. In the middle house (third in the row) they drink milk: }
drink(house_order(Third)) = Milk &
{10. The Norwegian lives in the first house: }
house_order(First) = Norwegian &
{11. The man who smokes Blend lives in the house next to the house with cats.
Another local predicate 'Neighbour' makes them neighbours: }
Neighbour(blend_smoker, cat_keeper, house_order) &
{12. In a house next to the house where they have a horse, they smoke Dunhill: }
Neighbour(dunhill_smoker, neighbour_dunhill_smoker, house_order) &
{13. The man who smokes Blue Master drinks beer: }
drink(bluemaster_smoker) = Beer &
{14. The German smokes Prince: }
smoke(German) = Prince &
{15. The Norwegian lives next to the blue house
Cf. 10. "The Norwegian lives in the first house", so the blue house is the second house: }
house_colour(house_order(Second)) = Blue &
{16. They drink water in a house next to the house where they smoke Blend: }
drink(neighbour_blend_smoker) = Water &
Neighbour(blend_smoker, neighbour_blend_smoker, house_order)
{ A simplified solution would number the houses 1, 2, 3, 4, 5
which makes it easier to order the houses.
'right in the center' would become 3; 'in the first house', 1
But we stick to the original puzzle and use some local predicates.
}
local pred Neighbour(neighbour1::Nationality, neighbour2::Nationality, house_order::HouseOrder)iff
neighbour1 <> neighbour2 &
house_order(house1) = neighbour1 &
house_order(house2) = neighbour2 &
( house1 = house2 + 1 |
house1 = house2 - 1 )
local pred LeftOf(neighbour1::Nationality, neighbour2::Nationality, house_order::HouseOrder) iff
neighbour1 <> neighbour2 &
house_order(house1) = neighbour1 &
house_order(house2) = neighbour2 &
house1 = house2 - 1
{
The 'all'-query in FormulaOne:
all Zebra(house_colour, pet, smokes, drinks, house_order)
gives, of course, only one solution, so it can be replaced by:
one Zebra(house_colour, pet, smokes, drinks, house_order)
}
// The compacted version:
Nationality = Englishman | Swede | Dane | Norwegian | German
Colour = Red | Green | Yellow | Blue | White
Cigarette = PallMall | Dunhill | BlueMaster | Blend | Prince
Domestic = Dog | Bird | Cat | Zebra | Horse
Beverage = Tea | Coffee | Milk | Beer | Water
HouseRow = First | Second | Third | Fourth | Fifth
Pet = Nationality->>Domestic
Drink = Nationality->>Beverage
HouseColour = Nationality->>Colour
Smoke = Nationality->>Cigarette
HouseOrder = HouseRow->>Nationality
 
pred Zebra(house_colour::HouseColour, pet::Pet, smoke::Smoke, drink::Drink, house_order::HouseOrder) iff
 
house-colour(green_house) = Green &
house-colour(white_house) = White &
house-colour(yellow_house) = Yellow &
smoke(pallmall_smoker) = PallMall &
smoke(blend_smoker) = Blend &
smoke(dunhill_smoker) = Dunhill &
smoke(bluemaster_smoker) = BlueMaster &
pet(cat_keeper) = Cat &
pet(neighbour_dunhill_smoker) = Horse &
house_colour(Englishman) = Red &
pet(Swede) = Dog &
drink(Dane) = Tea &
LeftOf(green_house, white_house, house_order) &
drink(green_house) = Coffee &
pet(pallmall_smoker) = Bird &
smoke(yellow_house) = Dunhill &
drink(house_order(Third)) = Milk &
house_order(First) = Norwegian &
Neighbour(blend_smoker, cat_keeper, house_order) &
Neighbour(dunhill_smoker, neighbour_dunhill_smoker, house_order) &
drink(bluemaster_smoker) = Beer &
smoke(German) = Prince &
house_colour(house_order(Second)) = Blue &
drink(neighbour_blend_smoker) = Water &
Neighbour(blend_smoker, neighbour_blend_smoker, house_order)
local pred Neighbour(neighbour1::Nationality, neighbour2::Nationality, house_order::HouseOrder)iff
neighbour1 <> neighbour2 &
house_order(house1) = neighbour1 & house_order(house2) = neighbour2 &
( house1 = house2 + 1 | house1 = house2 - 1 )
local pred LeftOf(neighbour1::Nationality, neighbour2::Nationality, house_::HouseOrder) iff
neighbour1 <> neighbour2 &
house_order(house1) = neighbour1 & house_order(house2) = neighbour2 &
house1 = house2 - 1
</syntaxhighlight>
{{out}}
<pre>
house_colour = [ {Englishman} Red, {Swede} White, {Dane} Blue, {Norwegian} Yellow, {German} Green ]
pet = [ {Englishman} Birds, {Swede} Dog, {Dane} Horse, {Norwegian} Cats, {German} Zebra ]
smokes = [ {Englishman} PallMall, {Swede} BlueMaster, {Dane} Blend, {Norwegian} Dunhill, {German} Prince ]
drinks = [ {Englishman} Milk, {Swede} Beer, {Dane} Tea, {Norwegian} Water, {German} Coffee ]
house_order = [ {First} Norwegian, {Second} Dane, {Third} Englishman, {Fourth} German, {Fifth}, Swede ]
</pre>
 
=={{header|GAP}}==
<syntaxhighlight lang="gap">leftOf :=function(setA, vA, setB, vB)
local i;
for i in [1..4] do
if ( setA[i] = vA) and (setB[i+1] = vB) then return true ;fi;
od;
return false;
end;
 
nextTo :=function(setA, vA, setB, vB)
local i;
for i in [1..4] do
if ( setA[i] = vA) and (setB[i+1] = vB) then return true ;fi;
if ( setB[i] = vB) and (setA[i+1] = vA) then return true ;fi;
od;
return false;
end;
 
 
requires := function(setA, vA, setB, vB)
local i;
for i in [1..5] do
if ( setA[i] = vA) and (setB[i] = vB) then return true ;fi;
od;
return false;
end;
 
 
pcolors :=PermutationsList(["white" ,"yellow" ,"blue" ,"red" ,"green"]);
pcigars :=PermutationsList(["blends", "pall_mall", "prince", "bluemasters", "dunhill"]);
pnats:=PermutationsList(["german", "swedish", "british", "norwegian", "danish"]);
pdrinks :=PermutationsList(["beer", "water", "tea", "milk", "coffee"]);
ppets :=PermutationsList(["birds", "cats", "horses", "fish", "dogs"]);
 
 
for colors in pcolors do
if not (leftOf(colors,"green",colors,"white")) then continue ;fi;
for nats in pnats do
if not (requires(nats,"british",colors,"red")) then continue ;fi;
if not (nats[1]="norwegian") then continue ;fi;
if not (nextTo(nats,"norwegian",colors,"blue")) then continue ;fi;
for pets in ppets do
if not (requires(nats,"swedish",pets,"dogs")) then continue ;fi;
for drinks in pdrinks do
if not (drinks[3]="milk") then continue ;fi;
if not (requires(colors,"green",drinks,"coffee")) then continue ;fi;
if not (requires(nats,"danish",drinks,"tea")) then continue ;fi;
for cigars in pcigars do
if not (nextTo(pets,"horses",cigars,"dunhill")) then continue ;fi;
if not (requires(cigars,"pall_mall",pets,"birds")) then continue ;fi;
if not (nextTo(cigars,"blends",drinks,"water")) then continue ;fi;
if not (nextTo(cigars,"blends",pets,"cats")) then continue ;fi;
if not (requires(nats,"german",cigars,"prince")) then continue ;fi;
if not (requires(colors,"yellow",cigars,"dunhill")) then continue ;fi;
if not (requires(cigars,"bluemasters",drinks,"beer")) then continue ;fi;
Print(colors,"\n");
Print(nats,"\n");
Print(drinks,"\n");
Print(pets,"\n");
Print(cigars,"\n");
od;od;od;od;od;
</syntaxhighlight>
 
=={{header|Go}}==
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"log"
"strings"
)
 
// Define some types
 
type HouseSet [5]*House
type House struct {
n Nationality
c Colour
a Animal
d Drink
s Smoke
}
type Nationality int8
type Colour int8
type Animal int8
type Drink int8
type Smoke int8
 
// Define the possible values
 
const (
English Nationality = iota
Swede
Dane
Norwegian
German
)
const (
Red Colour = iota
Green
White
Yellow
Blue
)
const (
Dog Animal = iota
Birds
Cats
Horse
Zebra
)
const (
Tea Drink = iota
Coffee
Milk
Beer
Water
)
const (
PallMall Smoke = iota
Dunhill
Blend
BlueMaster
Prince
)
 
// And how to print them
 
var nationalities = [...]string{"English", "Swede", "Dane", "Norwegian", "German"}
var colours = [...]string{"red", "green", "white", "yellow", "blue"}
var animals = [...]string{"dog", "birds", "cats", "horse", "zebra"}
var drinks = [...]string{"tea", "coffee", "milk", "beer", "water"}
var smokes = [...]string{"Pall Mall", "Dunhill", "Blend", "Blue Master", "Prince"}
 
func (n Nationality) String() string { return nationalities[n] }
func (c Colour) String() string { return colours[c] }
func (a Animal) String() string { return animals[a] }
func (d Drink) String() string { return drinks[d] }
func (s Smoke) String() string { return smokes[s] }
func (h House) String() string {
return fmt.Sprintf("%-9s %-6s %-5s %-6s %s", h.n, h.c, h.a, h.d, h.s)
}
func (hs HouseSet) String() string {
lines := make([]string, 0, len(hs))
for i, h := range hs {
s := fmt.Sprintf("%d %s", i, h)
lines = append(lines, s)
}
return strings.Join(lines, "\n")
}
 
// Simple brute force solution
 
func simpleBruteForce() (int, HouseSet) {
var v []House
for n := range nationalities {
for c := range colours {
for a := range animals {
for d := range drinks {
for s := range smokes {
h := House{
n: Nationality(n),
c: Colour(c),
a: Animal(a),
d: Drink(d),
s: Smoke(s),
}
if !h.Valid() {
continue
}
v = append(v, h)
}
}
}
}
}
n := len(v)
log.Println("Generated", n, "valid houses")
 
combos := 0
first := 0
valid := 0
var validSet HouseSet
for a := 0; a < n; a++ {
if v[a].n != Norwegian { // Condition 10:
continue
}
for b := 0; b < n; b++ {
if b == a {
continue
}
if v[b].anyDups(&v[a]) {
continue
}
for c := 0; c < n; c++ {
if c == b || c == a {
continue
}
if v[c].d != Milk { // Condition 9:
continue
}
if v[c].anyDups(&v[b], &v[a]) {
continue
}
for d := 0; d < n; d++ {
if d == c || d == b || d == a {
continue
}
if v[d].anyDups(&v[c], &v[b], &v[a]) {
continue
}
for e := 0; e < n; e++ {
if e == d || e == c || e == b || e == a {
continue
}
if v[e].anyDups(&v[d], &v[c], &v[b], &v[a]) {
continue
}
combos++
set := HouseSet{&v[a], &v[b], &v[c], &v[d], &v[e]}
if set.Valid() {
valid++
if valid == 1 {
first = combos
}
validSet = set
//return set
}
}
}
}
}
}
log.Println("Tested", first, "different combinations of valid houses before finding solution")
log.Println("Tested", combos, "different combinations of valid houses in total")
return valid, validSet
}
 
// anyDups returns true if h as any duplicate attributes with any of the specified houses
func (h *House) anyDups(list ...*House) bool {
for _, b := range list {
if h.n == b.n || h.c == b.c || h.a == b.a || h.d == b.d || h.s == b.s {
return true
}
}
return false
}
 
func (h *House) Valid() bool {
// Condition 2:
if h.n == English && h.c != Red || h.n != English && h.c == Red {
return false
}
// Condition 3:
if h.n == Swede && h.a != Dog || h.n != Swede && h.a == Dog {
return false
}
// Condition 4:
if h.n == Dane && h.d != Tea || h.n != Dane && h.d == Tea {
return false
}
// Condition 6:
if h.c == Green && h.d != Coffee || h.c != Green && h.d == Coffee {
return false
}
// Condition 7:
if h.a == Birds && h.s != PallMall || h.a != Birds && h.s == PallMall {
return false
}
// Condition 8:
if h.c == Yellow && h.s != Dunhill || h.c != Yellow && h.s == Dunhill {
return false
}
// Condition 11:
if h.a == Cats && h.s == Blend {
return false
}
// Condition 12:
if h.a == Horse && h.s == Dunhill {
return false
}
// Condition 13:
if h.d == Beer && h.s != BlueMaster || h.d != Beer && h.s == BlueMaster {
return false
}
// Condition 14:
if h.n == German && h.s != Prince || h.n != German && h.s == Prince {
return false
}
// Condition 15:
if h.n == Norwegian && h.c == Blue {
return false
}
// Condition 16:
if h.d == Water && h.s == Blend {
return false
}
return true
}
 
func (hs *HouseSet) Valid() bool {
ni := make(map[Nationality]int, 5)
ci := make(map[Colour]int, 5)
ai := make(map[Animal]int, 5)
di := make(map[Drink]int, 5)
si := make(map[Smoke]int, 5)
for i, h := range hs {
ni[h.n] = i
ci[h.c] = i
ai[h.a] = i
di[h.d] = i
si[h.s] = i
}
// Condition 5:
if ci[Green]+1 != ci[White] {
return false
}
// Condition 11:
if dist(ai[Cats], si[Blend]) != 1 {
return false
}
// Condition 12:
if dist(ai[Horse], si[Dunhill]) != 1 {
return false
}
// Condition 15:
if dist(ni[Norwegian], ci[Blue]) != 1 {
return false
}
// Condition 16:
if dist(di[Water], si[Blend]) != 1 {
return false
}
 
// Condition 9: (already tested elsewhere)
if hs[2].d != Milk {
return false
}
// Condition 10: (already tested elsewhere)
if hs[0].n != Norwegian {
return false
}
return true
}
 
func dist(a, b int) int {
if a > b {
return a - b
}
return b - a
}
 
func main() {
log.SetFlags(0)
n, sol := simpleBruteForce()
fmt.Println(n, "solution found")
fmt.Println(sol)
}</syntaxhighlight>
{{out}}
<pre>Generated 51 valid houses
Tested 652 different combinations of valid houses before finding solution
Tested 750 different combinations of valid houses in total
1 solution found
0 Norwegian yellow cats water Dunhill
1 Dane blue horse tea Blend
2 English red birds milk Pall Mall
3 German green zebra coffee Prince
4 Swede white dog beer Blue Master
</pre>
Benchmark (not included but just calling simpleBruteForce):
<pre>
BenchmarkBruteForce 1000 2687946 ns/op 550568 B/op 7560 allocs/op
</pre>
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">module Main where
 
import Control.Applicative ((<$>), (<*>))
import Control.Monad (foldM, forM_)
import Data.List ((\\))
 
-- types
data House = House
{ color :: Color -- <trait> :: House -> <Trait>
, man :: Man
, pet :: Pet
, drink :: Drink
, smoke :: Smoke
}
deriving (Eq, Show)
 
data Color = Red | Green | Blue | Yellow | White
deriving (Eq, Show, Enum, Bounded)
 
data Man = Eng | Swe | Dan | Nor | Ger
deriving (Eq, Show, Enum, Bounded)
 
data Pet = Dog | Birds | Cats | Horse | Zebra
deriving (Eq, Show, Enum, Bounded)
 
data Drink = Coffee | Tea | Milk | Beer | Water
deriving (Eq, Show, Enum, Bounded)
 
data Smoke = PallMall | Dunhill | Blend | BlueMaster | Prince
deriving (Eq, Show, Enum, Bounded)
 
type Solution = [House]
 
main :: IO ()
main = do
forM_ solutions $ \sol -> mapM_ print sol
>> putStrLn "----"
putStrLn "No More Solutions"
 
 
solutions :: [Solution]
solutions = filter finalCheck . map reverse $ foldM next [] [1..5]
where
-- NOTE: list of houses is generated in reversed order
next :: Solution -> Int -> [Solution]
next sol pos = [h:sol | h <- newHouses sol, consistent h pos]
 
 
newHouses :: Solution -> Solution
newHouses sol = -- all combinations of traits not yet used
House <$> new color <*> new man <*> new pet <*> new drink <*> new smoke
where
new trait = [minBound ..] \\ map trait sol -- :: [<Trait>]
 
 
consistent :: House -> Int -> Bool
consistent house pos = and -- consistent with the rules:
[ man `is` Eng <=> color `is` Red -- 2
, man `is` Swe <=> pet `is` Dog -- 3
, man `is` Dan <=> drink `is` Tea -- 4
, color `is` Green <=> drink `is` Coffee -- 6
, pet `is` Birds <=> smoke `is` PallMall -- 7
, color `is` Yellow <=> smoke `is` Dunhill -- 8
, const (pos == 3) <=> drink `is` Milk -- 9
, const (pos == 1) <=> man `is` Nor -- 10
, drink `is` Beer <=> smoke `is` BlueMaster -- 13
, man `is` Ger <=> smoke `is` Prince -- 14
]
where
infix 4 <=>
p <=> q = p house == q house -- both True or both False
 
 
is :: Eq a => (House -> a) -> a -> House -> Bool
(trait `is` value) house = trait house == value
 
 
finalCheck :: [House] -> Bool
finalCheck solution = and -- fulfills the rules:
[ (color `is` Green) `leftOf` (color `is` White) -- 5
, (smoke `is` Blend ) `nextTo` (pet `is` Cats ) -- 11
, (smoke `is` Dunhill) `nextTo` (pet `is` Horse) -- 12
, (color `is` Blue ) `nextTo` (man `is` Nor ) -- 15
, (smoke `is` Blend ) `nextTo` (drink `is` Water) -- 16
]
where
nextTo :: (House -> Bool) -> (House -> Bool) -> Bool
nextTo p q = leftOf p q || leftOf q p
leftOf p q
| (_:h:_) <- dropWhile (not . p) solution = q h
| otherwise = False</syntaxhighlight>
{{out}}
<pre>House {color = Yellow, man = Nor, pet = Cats, drink = Water, smoke = Dunhill}
House {color = Blue, man = Dan, pet = Horse, drink = Tea, smoke = Blend}
House {color = Red, man = Eng, pet = Birds, drink = Milk, smoke = PallMall}
House {color = Green, man = Ger, pet = Zebra, drink = Coffee, smoke = Prince}
House {color = White, man = Swe, pet = Dog, drink = Beer, smoke = BlueMaster}
----
No More Solutions</pre>
[http://ideone.com/ZaKfWC Runs in: time: 0.01s.]
 
=== LP-like version ===
 
(a little faster version)
 
<syntaxhighlight lang="haskell">import Control.Monad
import Data.List
 
values :: (Bounded a, Enum a) => [[a]]
values = permutations [minBound..maxBound]
 
data Nation = English | Swede | Dane | Norwegian | German
deriving (Bounded, Enum, Eq, Show)
data Color = Red | Green | White | Yellow | Blue
deriving (Bounded, Enum, Eq, Show)
data Pet = Dog | Birds | Cats | Horse | Zebra
deriving (Bounded, Enum, Eq, Show)
data Drink = Tea | Coffee | Milk | Beer | Water
deriving (Bounded, Enum, Eq, Show)
data Smoke = PallMall | Dunhill | Blend | BlueMaster | Prince
deriving (Bounded, Enum, Eq, Show)
 
answers = do
color <- values
leftOf color Green color White -- 5
 
nation <- values
first nation Norwegian -- 10
same nation English color Red -- 2
nextTo nation Norwegian color Blue -- 15
 
drink <- values
middle drink Milk -- 9
same nation Dane drink Tea -- 4
same drink Coffee color Green -- 6
 
pet <- values
same nation Swede pet Dog -- 3
 
smoke <- values
same smoke PallMall pet Birds -- 7
same color Yellow smoke Dunhill -- 8
nextTo smoke Blend pet Cats -- 11
nextTo pet Horse smoke Dunhill -- 12
same nation German smoke Prince -- 14
same smoke BlueMaster drink Beer -- 13
nextTo drink Water smoke Blend -- 16
 
return $ zip5 nation color pet drink smoke
 
where
same xs x ys y = guard $ (x, y) `elem` zip xs ys
leftOf xs x ys y = same xs x (tail ys) y
nextTo xs x ys y = leftOf xs x ys y `mplus`
leftOf ys y xs x
middle xs x = guard $ xs !! 2 == x
first xs x = guard $ head xs == x
 
main = do
forM_ answers $ (\answer -> -- for answer in answers:
do
mapM_ print answer
print [nation | (nation, _, Zebra, _, _) <- answer]
putStrLn "" )
putStrLn "No more solutions!"</syntaxhighlight>
 
Output:
<pre>(Norwegian,Yellow,Cats,Water,Dunhill)
(Dane,Blue,Horse,Tea,Blend)
(English,Red,Birds,Milk,PallMall)
(German,Green,Zebra,Coffee,Prince)
(Swede,White,Dog,Beer,BlueMaster)
[German]
 
No more solutions!</pre>
 
=={{header|J}}==
 
Propositions 1 .. 16 without 9,10 and15
<langsyntaxhighlight lang="j">ehs=: 5$a:
 
cr=: (('English';'red') 0 3} ehs);<('Dane';'tea') 0 2}ehs
Line 679 ⟶ 3,471:
next=: <((<'Blend') 4 }ehs);<(<'water')2}ehs
next=: next,<((<'Blend') 4 }ehs);<(<'cats')1}ehs
next=: next,<((<'Dunhill') 4}ehs);<(<'horse')1}ehs</langsyntaxhighlight>
'''Example'''
<langsyntaxhighlight lang="j"> lof
┌─────────────────┬───────────┐
│┌┬┬──────┬─────┬┐│┌┬┬┬─────┬┐│
││││coffee│green│││││││white│││
│└┴┴──────┴─────┴┘│└┴┴┴─────┴┘│
└─────────────────┴───────────┘</langsyntaxhighlight>
 
Collections of all variants of the propositions:
<langsyntaxhighlight lang="j">hcr=: (<ehs),. (A.~i.@!@#)cr
hcs=:~. (A.~i.@!@#)cs,2$<ehs
hlof=:(-i.4) |."0 1 lof,3$<ehs
hnext=: ,/((i.4) |."0 1 (3$<ehs)&,)"1 ;(,,:|.)&.> next</langsyntaxhighlight>
 
AWe streetstart the row of houses with fixed properties 9, 10 and 15.
<langsyntaxhighlight lang="j">houses=: ((<'Norwegian') 0}ehs);((<'blue') 3 }ehs);((<'milk') 2}ehs);ehs;<ehs</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="j"> houses
┌───────────────┬──────────┬──────────┬──────┬──────┐
│┌─────────┬┬┬┬┐│┌┬┬┬────┬┐│┌┬┬────┬┬┐│┌┬┬┬┬┐│┌┬┬┬┬┐│
││Norwegian││││││││││blue││││││milk││││││││││││││││││
│└─────────┴┴┴┴┘│└┴┴┴────┴┘│└┴┴────┴┴┘│└┴┴┴┴┘│└┴┴┴┴┘│
└───────────────┴──────────┴──────────┴──────┴──────┘</langsyntaxhighlight>
Set of proposition varaintsvariants:
<langsyntaxhighlight lang="j">constraints=: hcr;hcs;hlof;<hnext</langsyntaxhighlight>
The worker and its helper verbs
<langsyntaxhighlight lang="j">select=: ~.@(,: #~ ,&(0~:#))
filter=: #~*./@:(2>#S:0)"1
compose=: [: filter f. [: ,/ select f. L:0"1"1 _
Line 716 ⟶ 3,508:
z=.(#~1=[:+/"1 (0=#)S:0"1) h=.~. h
end.
)</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="j"> >"0 houses solve constraints
┌─────────┬─────┬──────┬──────┬──────────┐
│Norwegian│cats │water │yellow│Dunhill │
Line 729 ⟶ 3,521:
├─────────┼─────┼──────┼──────┼──────────┤
│Swede │dog │beer │white │BlueMaster│
└─────────┴─────┴──────┴──────┴──────────┘</langsyntaxhighlight>
So, the German owns the zebra.
 
'''Alternative'''
A longer running solver by adding the zebra variants.
<br>A longer running solver by adding the zebra variants.
<syntaxhighlight lang="j">zebra=: (-i.5)|."0 1 (<(<'zebra') 1}ehs),4$<ehs
 
solve3=: 4 :0
<lang j>zebra=: (-i.5)|."0 1 (<(<'zebra') 1}ehs),4$<ehs</lang>
p=. *./@:((0~:#)S:0)
f=. [:~.&.> [: compose&.>~/y&, f.
z=. f^:(3>[:#(#~p"1)&>)^:_ <,:x
>"0 (#~([:*./[:;[:<@({.~:}.)\.;)"1)(#~p"1); z
)</syntaxhighlight>
{{out}}
<syntaxhighlight lang="j"> houses solve3 constraints,<zebra
┌─────────┬─────┬──────┬──────┬──────────┐
│Norwegian│cats │water │yellow│Dunhill │
├─────────┼─────┼──────┼──────┼──────────┤
│Dane │horse│tea │blue │Blend │
├─────────┼─────┼──────┼──────┼──────────┤
│English │birds│milk │red │PallMall │
├─────────┼─────┼──────┼──────┼──────────┤
│German │zebra│coffee│green │Prince │
├─────────┼─────┼──────┼──────┼──────────┤
│Swede │dog │beer │white │BlueMaster│
└─────────┴─────┴──────┴──────┴──────────┘</syntaxhighlight>
 
=={{header|Java}}==
This Java solution includes 4 classes:
* The outer class <tt>Zebra</tt>
* A PossibleLine
* A set of PossibleLines
* The Solver
 
<syntaxhighlight lang="java">package org.rosettacode.zebra;
 
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
 
public class Zebra {
 
private static final int[] orders = {1, 2, 3, 4, 5};
private static final String[] nations = {"English", "Danish", "German", "Swedish", "Norwegian"};
private static final String[] animals = {"Zebra", "Horse", "Birds", "Dog", "Cats"};
private static final String[] drinks = {"Coffee", "Tea", "Beer", "Water", "Milk"};
private static final String[] cigarettes = {"Pall Mall", "Blend", "Blue Master", "Prince", "Dunhill"};
private static final String[] colors = {"Red", "Green", "White", "Blue", "Yellow"};
 
static class Solver {
private final PossibleLines puzzleTable = new PossibleLines();
 
void solve() {
PossibleLines constraints = new PossibleLines();
constraints.add(new PossibleLine(null, "English", "Red", null, null, null));
constraints.add(new PossibleLine(null, "Swedish", null, "Dog", null, null));
constraints.add(new PossibleLine(null, "Danish", null, null, "Tea", null));
constraints.add(new PossibleLine(null, null, "Green", null, "Coffee", null));
constraints.add(new PossibleLine(null, null, null, "Birds", null, "Pall Mall"));
constraints.add(new PossibleLine(null, null, "Yellow", null, null, "Dunhill"));
constraints.add(new PossibleLine(3, null, null, null, "Milk", null));
constraints.add(new PossibleLine(1, "Norwegian", null, null, null, null));
constraints.add(new PossibleLine(null, null, null, null, "Beer", "Blue Master"));
constraints.add(new PossibleLine(null, "German", null, null, null, "Prince"));
constraints.add(new PossibleLine(2, null, "Blue", null, null, null));
 
//Creating all possible combination of a puzzle line.
//The maximum number of lines is 5^^6 (15625).
//Each combination line is checked against a set of knowing facts, thus
//only a small number of line result at the end.
for (Integer orderId : Zebra.orders) {
for (String nation : Zebra.nations) {
for (String color : Zebra.colors) {
for (String animal : Zebra.animals) {
for (String drink : Zebra.drinks) {
for (String cigarette : Zebra.cigarettes) {
addPossibleNeighbors(constraints, orderId, nation, color, animal, drink, cigarette);
}
}
}
}
}
}
 
System.out.println("After general rule set validation, remains " +
puzzleTable.size() + " lines.");
 
for (Iterator<PossibleLine> it = puzzleTable.iterator(); it.hasNext(); ) {
boolean validLine = true;
 
PossibleLine possibleLine = it.next();
 
if (possibleLine.leftNeighbor != null) {
PossibleLine neighbor = possibleLine.leftNeighbor;
if (neighbor.order < 1 || neighbor.order > 5) {
validLine = false;
it.remove();
}
}
if (validLine && possibleLine.rightNeighbor != null) {
PossibleLine neighbor = possibleLine.rightNeighbor;
if (neighbor.order < 1 || neighbor.order > 5) {
it.remove();
}
}
}
 
System.out.println("After removing out of bound neighbors, remains " +
puzzleTable.size() + " lines.");
 
//Setting left and right neighbors
for (PossibleLine puzzleLine : puzzleTable) {
for (PossibleLine leftNeighbor : puzzleLine.neighbors) {
PossibleLine rightNeighbor = leftNeighbor.copy();
 
//make it left neighbor
leftNeighbor.order = puzzleLine.order - 1;
if (puzzleTable.contains(leftNeighbor)) {
if (puzzleLine.leftNeighbor != null)
puzzleLine.leftNeighbor.merge(leftNeighbor);
else
puzzleLine.setLeftNeighbor(leftNeighbor);
}
rightNeighbor.order = puzzleLine.order + 1;
if (puzzleTable.contains(rightNeighbor)) {
if (puzzleLine.rightNeighbor != null)
puzzleLine.rightNeighbor.merge(rightNeighbor);
else
puzzleLine.setRightNeighbor(rightNeighbor);
}
}
}
 
int iteration = 1;
int lastSize = 0;
 
//Recursively validate against neighbor rules
while (puzzleTable.size() > 5 && lastSize != puzzleTable.size()) {
lastSize = puzzleTable.size();
puzzleTable.clearLineCountFlags();
 
recursiveSearch(null, puzzleTable, -1);
 
constraints.clear();
// Assuming we'll get at leas one valid line each iteration, we create
// a set of new rules with lines which have no more then one instance of same OrderId.
for (int i = 1; i < 6; i++) {
if (puzzleTable.getLineCountByOrderId(i) == 1)
constraints.addAll(puzzleTable.getSimilarLines(new PossibleLine(i, null, null, null, null,
null)));
}
 
puzzleTable.removeIf(puzzleLine -> !constraints.accepts(puzzleLine));
 
System.out.println("After " + iteration + " recursive iteration, remains "
+ puzzleTable.size() + " lines");
iteration++;
}
 
// Print the results
System.out.println("-------------------------------------------");
if (puzzleTable.size() == 5) {
for (PossibleLine puzzleLine : puzzleTable) {
System.out.println(puzzleLine.getWholeLine());
}
} else
System.out.println("Sorry, solution not found!");
}
 
private void addPossibleNeighbors(
PossibleLines constraints, Integer orderId, String nation,
String color, String animal, String drink, String cigarette) {
boolean validLine = true;
PossibleLine pzlLine = new PossibleLine(orderId,
nation,
color,
animal,
drink,
cigarette);
// Checking against a set of knowing facts
if (constraints.accepts(pzlLine)) {
// Adding rules of neighbors
if (cigarette.equals("Blend")
&& (animal.equals("Cats") || drink.equals("Water")))
validLine = false;
 
if (cigarette.equals("Dunhill")
&& animal.equals("Horse"))
validLine = false;
 
if (validLine) {
puzzleTable.add(pzlLine);
 
//set neighbors constraints
if (color.equals("Green")) {
pzlLine.setRightNeighbor(
new PossibleLine(null, null, "White", null, null, null));
}
if (color.equals("White")) {
pzlLine.setLeftNeighbor(
new PossibleLine(null, null, "Green", null, null, null));
}
//
if (animal.equals("Cats") && !cigarette.equals("Blend")) {
pzlLine.neighbors.add(new PossibleLine(null, null, null, null, null,
"Blend"));
}
if (cigarette.equals("Blend") && !animal.equals("Cats")) {
pzlLine.neighbors.add(new PossibleLine(null, null, null, "Cats", null
, null));
}
//
if (drink.equals("Water")
&& !animal.equals("Cats")
&& !cigarette.equals("Blend")) {
pzlLine.neighbors.add(new PossibleLine(null, null, null, null, null,
"Blend"));
}
 
if (cigarette.equals("Blend") && !drink.equals("Water")) {
pzlLine.neighbors.add(new PossibleLine(null, null, null, null, "Water"
, null));
}
//
if (animal.equals("Horse") && !cigarette.equals("Dunhill")) {
pzlLine.neighbors.add(new PossibleLine(null, null, null, null, null,
"Dunhill"));
}
if (cigarette.equals("Dunhill") && !animal.equals("Horse")) {
pzlLine.neighbors.add(new PossibleLine(null, null, null, "Horse",
null, null));
}
}
}
}
 
// Recursively checks the input set to ensure each line has right neighbor.
// Neighbors can be of three type, left, right or undefined.
// Direction: -1 left, 0 undefined, 1 right
private boolean recursiveSearch(PossibleLine pzzlNodeLine,
PossibleLines possibleLines, int direction) {
boolean validLeaf = false;
boolean hasNeighbor;
PossibleLines puzzleSubSet;
 
for (Iterator<PossibleLine> it = possibleLines.iterator(); it.hasNext(); ) {
PossibleLine pzzlLeafLine = it.next();
validLeaf = false;
 
hasNeighbor = pzzlLeafLine.hasNeighbor(direction);
 
if (hasNeighbor) {
puzzleSubSet = puzzleTable.getSimilarLines(pzzlLeafLine.getNeighbor(direction));
if (puzzleSubSet != null) {
if (pzzlNodeLine != null)
validLeaf = puzzleSubSet.contains(pzzlNodeLine);
else
validLeaf = recursiveSearch(pzzlLeafLine, puzzleSubSet, -1 * direction);
}
}
 
if (!validLeaf && pzzlLeafLine.hasNeighbor(-1 * direction)) {
hasNeighbor = true;
puzzleSubSet = puzzleTable.getSimilarLines(pzzlLeafLine.getNeighbor(-1 * direction));
if (puzzleSubSet != null) {
if (pzzlNodeLine != null)
validLeaf = puzzleSubSet.contains(pzzlNodeLine);
else
validLeaf = recursiveSearch(pzzlLeafLine, puzzleSubSet, direction);
}
}
 
if (pzzlNodeLine != null && validLeaf)
return true;
 
if (pzzlNodeLine == null && hasNeighbor && !validLeaf) {
it.remove();
}
 
if (pzzlNodeLine == null) {
if (hasNeighbor && validLeaf) {
possibleLines.riseLineCountFlags(pzzlLeafLine.order);
}
if (!hasNeighbor) {
possibleLines.riseLineCountFlags(pzzlLeafLine.order);
}
}
}
return validLeaf;
}
}
 
public static void main(String[] args) {
 
Solver solver = new Solver();
solver.solve();
}
 
static class PossibleLines extends LinkedHashSet<PossibleLine> {
 
private final int[] count = new int[5];
 
public PossibleLine get(int index) {
return ((PossibleLine) toArray()[index]);
}
 
public PossibleLines getSimilarLines(PossibleLine searchLine) {
PossibleLines puzzleSubSet = new PossibleLines();
for (PossibleLine possibleLine : this) {
if (possibleLine.getCommonFactsCount(searchLine) == searchLine.getFactsCount())
puzzleSubSet.add(possibleLine);
}
if (puzzleSubSet.isEmpty())
return null;
 
return puzzleSubSet;
}
 
public boolean contains(PossibleLine searchLine) {
for (PossibleLine puzzleLine : this) {
if (puzzleLine.getCommonFactsCount(searchLine) == searchLine.getFactsCount())
return true;
}
return false;
}
 
public boolean accepts(PossibleLine searchLine) {
int passed = 0;
int notpassed = 0;
 
for (PossibleLine puzzleSetLine : this) {
int lineFactsCnt = puzzleSetLine.getFactsCount();
int comnFactsCnt = puzzleSetLine.getCommonFactsCount(searchLine);
 
if (lineFactsCnt != comnFactsCnt && lineFactsCnt != 0 && comnFactsCnt != 0) {
notpassed++;
}
 
if (lineFactsCnt == comnFactsCnt)
passed++;
}
return passed >= 0 && notpassed == 0;
}
 
public void riseLineCountFlags(int lineOrderId) {
count[lineOrderId - 1]++;
}
 
public void clearLineCountFlags() {
Arrays.fill(count, 0);
}
 
public int getLineCountByOrderId(int lineOrderId) {
return count[lineOrderId - 1];
}
}
 
static class PossibleLine {
 
Integer order;
String nation;
String color;
String animal;
String drink;
String cigarette;
 
PossibleLine rightNeighbor;
PossibleLine leftNeighbor;
Set<PossibleLine> neighbors = new LinkedHashSet<>();
 
public PossibleLine(Integer order, String nation, String color,
String animal, String drink, String cigarette) {
this.animal = animal;
this.cigarette = cigarette;
this.color = color;
this.drink = drink;
this.nation = nation;
this.order = order;
}
 
@Override
public boolean equals(Object obj) {
return obj instanceof PossibleLine
&& getWholeLine().equals(((PossibleLine) obj).getWholeLine());
}
 
public int getFactsCount() {
int facts = 0;
facts += order != null ? 1 : 0;
facts += nation != null ? 1 : 0;
facts += color != null ? 1 : 0;
facts += animal != null ? 1 : 0;
facts += cigarette != null ? 1 : 0;
facts += drink != null ? 1 : 0;
return facts;
}
 
private static int common(Object a, Object b) {
return a != null && Objects.equals(a, b) ? 1 : 0;
}
 
public int getCommonFactsCount(PossibleLine facts) {
return common(order, facts.order)
+ common(nation, facts.nation)
+ common(color, facts.color)
+ common(animal, facts.animal)
+ common(cigarette, facts.cigarette)
+ common(drink, facts.drink);
}
 
public void setLeftNeighbor(PossibleLine leftNeighbor) {
this.leftNeighbor = leftNeighbor;
this.leftNeighbor.order = order - 1;
}
 
public void setRightNeighbor(PossibleLine rightNeighbor) {
this.rightNeighbor = rightNeighbor;
this.rightNeighbor.order = order + 1;
}
 
public boolean hasNeighbor(int direction) {
return getNeighbor(direction) != null;
}
 
public PossibleLine getNeighbor(int direction) {
if (direction < 0)
return leftNeighbor;
else
return rightNeighbor;
}
 
public String getWholeLine() {
return order + " - " +
nation + " - " +
color + " - " +
animal + " - " +
drink + " - " +
cigarette;
}
 
@Override
public int hashCode() {
return Objects.hash(order, nation, color, animal, drink, cigarette);
}
 
public void merge(PossibleLine mergedLine) {
if (order == null) order = mergedLine.order;
if (nation == null) nation = mergedLine.nation;
if (color == null) color = mergedLine.color;
if (animal == null) animal = mergedLine.animal;
if (drink == null) drink = mergedLine.drink;
if (cigarette == null) cigarette = mergedLine.cigarette;
}
 
public PossibleLine copy() {
PossibleLine clone = new PossibleLine(order, nation, color, animal, drink, cigarette);
clone.leftNeighbor = leftNeighbor;
clone.rightNeighbor = rightNeighbor;
clone.neighbors = neighbors; // shallow copy
return clone;
}
}
}</syntaxhighlight>
{{out}}
<pre>
After general rule set validation, remains 60 lines.
After removing out of bound neighbors, remains 52 lines.
After 1 recursive iteration, remains 17 lines
After 2 recursive iteration, remains 6 lines
After 3 recursive iteration, remains 5 lines
-------------------------------------------
1 - Norwegian - Yellow - Cats - Water - Dunhill
2 - Danish - Blue - Horse - Tea - Blend
3 - English - Red - Birds - Milk - Pall Mall
4 - German - Green - Zebra - Coffee - Prince
5 - Swedesh - White - Dog - Beer - Blue Master
</pre>
--[[User:Vvalache|VValache]] ([[User talk:Vvalache|talk]]) 14:14, 3 October 2014 (UTC)
 
=={{header|jq}}==
{{works with|jq|1.4}}
The main function presented here, zebra, generates all possible solutions. By letting it run to
completion, we can see that there is only one solution to the
puzzle. The program is fast because pruning takes place. That is, the program implements a "generate-and-prune" strategy.
 
'''Part 1''': Generic filters for unification and matching
<syntaxhighlight lang="jq">
# Attempt to unify the input object with the specified object
def unify( object ):
# Attempt to unify the input object with the specified tag:value
def unify2(tag; value):
if . == null then null
elif .[tag] == value then .
elif .[tag] == null then .[tag] = value
else null
end;
reduce (object|keys[]) as $key
(.; unify2($key; object[$key]) );
 
# Input: an array
# Output: if the i-th element can be made to satisfy the condition,
# then the updated array, otherwise empty.
def enforce(i; cond):
if 0 <= i and i < length
then
(.[i] | cond) as $ans
| if $ans then .[i] = $ans else empty end
else empty
end ;</syntaxhighlight>
'''Part 2''': Zebra Puzzle
<syntaxhighlight lang="jq"># Each house is a JSON object of the form:
# { "number": _, "nation": _, "owns": _, "color": _, "drinks": _, "smokes": _}
 
# The list of houses is represented by an array of five such objects.
 
# Input: an array of objects representing houses.
# Output: [i, solution] where i is the entity unified with obj
# and solution is the updated array
def solve_with_index( obj ):
. as $Houses
| range(0; length) as $i
| ($Houses[$i] | unify(obj)) as $H
| if $H then $Houses[$i] = $H else empty end
| [ $i, .] ;
 
def solve( object ):
solve_with_index( object )[1];
 
def adjacent( obj1; obj2 ):
solve_with_index(obj1) as $H
| $H[1]
| (enforce( $H[0] - 1; unify(obj2) ),
enforce( $H[0] + 1; unify(obj2) )) ;
 
def left_right( obj1; obj2 ):
solve_with_index(obj1) as $H
| $H[1]
| enforce( $H[0] + 1; unify(obj2) ) ;
 
 
# All solutions by generate-and-test
def zebra:
[range(0;5)] | map({"number": .}) # Five houses
 
| enforce( 0; unify( {"nation": "norwegian"} ) )
| enforce( 2; unify( {"drinks": "milk"} ) )
 
| solve( {"nation": "englishman", "color": "red"} )
| solve( {"nation": "swede", "owns": "dog"} )
| solve( {"nation": "dane", "drinks": "tea"} )
 
| left_right( {"color": "green"}; {"color": "white"})
 
| solve( {"drinks": "coffee", "color": "green"} )
| solve( {"smokes": "Pall Mall", "owns": "birds"} )
| solve( {"color": "yellow", "smokes": "Dunhill"} )
 
| adjacent( {"smokes": "Blend" }; {"owns": "cats"} )
| adjacent( {"owns": "horse"}; {"smokes": "Dunhill"})
 
| solve( {"drinks": "beer", "smokes": "Blue Master"} )
| solve( {"nation": "german", "smokes": "Prince"})
 
| adjacent( {"nation": "norwegian"}; {"color": "blue"})
| adjacent( {"drinks": "water"}; {"smokes": "Blend"})
 
| solve( {"owns": "zebra"} )
;
zebra</syntaxhighlight>
{{Out}}
<div style="overflow:scroll; height:400px;">
<syntaxhighlight lang="sh">$ time jq -n -f zebra.jq
[
{
"number": 0,
"nation": "norwegian",
"color": "yellow",
"smokes": "Dunhill",
"owns": "cats",
"drinks": "water"
},
{
"number": 1,
"drinks": "tea",
"nation": "dane",
"smokes": "Blend",
"owns": "horse",
"color": "blue"
},
{
"number": 2,
"drinks": "milk",
"color": "red",
"nation": "englishman",
"owns": "birds",
"smokes": "Pall Mall"
},
{
"number": 3,
"color": "green",
"drinks": "coffee",
"nation": "german",
"smokes": "Prince",
"owns": "zebra"
},
{
"number": 4,
"nation": "swede",
"owns": "dog",
"color": "white",
"drinks": "beer",
"smokes": "Blue Master"
}
]
 
# Times include compilation:
real 0m0.284s
user 0m0.260s
sys 0m0.005s</syntaxhighlight></div>
 
=={{header|Julia}}==
 
<syntaxhighlight lang="julia">
# Julia 1.0
using Combinatorics
function make(str, test )
filter(test, collect( permutations(split(str))) )
end
 
men = make("danish english german norwegian swedish",
x -> "norwegian" == x[1])
 
drinks = make("beer coffee milk tea water", x -> "milk" == x[3])
 
#Julia 1.0 compatible
colors = make("blue green red white yellow",
x -> 1 == findfirst(c -> c == "white", x) - findfirst(c -> c == "green",x))
 
pets = make("birds cats dog horse zebra")
 
smokes = make("blend blue-master dunhill pall-mall prince")
 
function eq(x, xs, y, ys)
findfirst(xs, x) == findfirst(ys, y)
end
 
function adj(x, xs, y, ys)
1 == abs(findfirst(xs, x) - findfirst(ys, y))
end
 
function print_houses(n, pet, nationality, colors, drink, smokes)
println("$n, $pet, $nationality $colors $drink $smokes")
end
 
for m = men, c = colors
if eq("red",c, "english",m) && adj("norwegian",m, "blue",c)
for d = drinks
if eq("danish",m, "tea",d) && eq("coffee",d,"green",c)
for s = smokes
if eq("yellow",c,"dunhill",s) &&
eq("blue-master",s,"beer",d) &&
eq("german",m,"prince",s)
for p = pets
if eq("birds",p,"pall-mall",s) &&
eq("swedish",m,"dog",p) &&
adj("blend",s,"cats",p) &&
adj("horse",p,"dunhill",s)
println("Zebra is owned by ", m[findfirst(c -> c == "zebra", p)])
println("Houses:")
for house_num in 1:5
print_houses(house_num,p[house_num],m[house_num],c[house_num],d[house_num],s[house_num])
end
end
end
end
end
end
end
end
end
</syntaxhighlight>
 
{{out}}
<pre>
Zebra is owned by german
Houses:
1, cats, norwegian yellow water dunhill
2, horse, danish blue tea blend
3, birds, english red milk pall-mall
4, zebra, german green coffee prince
5, dog, swedish white beer blue-master
</pre>
 
===Constraint Programming Version===
Using the rules from https://github.com/SWI-Prolog/bench/blob/master/programs/zebra.pl
<syntaxhighlight lang="julia"># Julia 1.4
using JuMP
using GLPK
 
c = Dict(s => i for (i, s) in enumerate(split("blue green ivory red yellow")))
n = Dict(s => i for (i, s) in enumerate(split("english japanese norwegian spanish ukrainian")))
p = Dict(s => i for (i, s) in enumerate(split("dog fox horse snails zebra")))
d = Dict(s => i for (i, s) in enumerate(split("coffee milk orangejuice tea water")))
s = Dict(s => i for (i, s) in enumerate(split("chesterfields kools luckystrikes parliaments winstons")))
 
model = Model(GLPK.Optimizer)
 
@variable(model, colors[1:5, 1:5], Bin)
@constraints(model, begin
[h in 1:5], sum(colors[h, :]) == 1
[c in 1:5], sum(colors[:, c]) == 1
end)
 
@variable(model, nations[1:5, 1:5], Bin)
@constraints(model, begin
[h in 1:5], sum(nations[h, :]) == 1
[n in 1:5], sum(nations[:, n]) == 1
end)
 
@variable(model, pets[1:5, 1:5], Bin)
@constraints(model, begin
[h in 1:5], sum(pets[h, :]) == 1
[p in 1:5], sum(pets[:, p]) == 1
end)
 
@variable(model, drinks[1:5, 1:5], Bin)
@constraints(model, begin
[h in 1:5], sum(drinks[h, :]) == 1
[d in 1:5], sum(drinks[:, d]) == 1
end)
 
@variable(model, smokes[1:5, 1:5], Bin)
@constraints(model, begin
[h in 1:5], sum(smokes[h, :]) == 1
[s in 1:5], sum(smokes[:, s]) == 1
end)
 
@constraint(model, [h=1:5], colors[h, c["red"]] == nations[h, n["english"]])
@constraint(model, [h=1:5], nations[h, n["spanish"]] == pets[h, p["dog"]])
@constraint(model, [h=1:5], colors[h, c["green"]] == drinks[h, d["coffee"]])
@constraint(model, [h=1:5], nations[h, n["ukrainian"]] == drinks[h, d["tea"]])
@constraint(model, [h=1:5], colors[h, c["ivory"]] == get(colors, (h+1, c["green"]), 0))
@constraint(model, [h=1:5], pets[h, p["snails"]] == smokes[h, s["winstons"]])
@constraint(model, [h=1:5], colors[h, c["yellow"]] == smokes[h, s["kools"]])
@constraint(model, drinks[3, d["milk"]] == 1)
@constraint(model, nations[1, n["norwegian"]] == 1)
@constraint(model, [h=1:5], (1-pets[h, p["fox"]]) + get(smokes,(h-1, s["chesterfields"]), 0) + get(smokes, (h+1, s["chesterfields"]), 0) >= 1)
@constraint(model, [h=1:5], (1-pets[h, p["horse"]]) + get(smokes,(h-1, s["kools"]), 0) + get(smokes, (h+1, s["kools"]), 0) >= 1)
@constraint(model, [h=1:5], drinks[h, d["orangejuice"]] == smokes[h, s["luckystrikes"]])
@constraint(model, [h=1:5], nations[h, n["japanese"]] == smokes[h, s["parliaments"]])
@constraint(model, [h=1:5], (1-nations[h, n["norwegian"]]) + get(colors, (h-1, c["blue"]), 0) + get(colors, (h+1, c["blue"]), 0) >= 1)
 
optimize!(model)
 
if termination_status(model) == MOI.OPTIMAL && primal_status(model) == MOI.FEASIBLE_POINT
m = map(1:5) do h
[Dict(values(c) .=> keys(c))[findfirst(value.(colors)[h, :] .≈ 1.0)],
Dict(values(n) .=> keys(n))[findfirst(value.(nations)[h, :] .≈ 1.0)],
Dict(values(p) .=> keys(p))[findfirst(value.(pets)[h, :] .≈ 1.0)],
Dict(values(d) .=> keys(d))[findfirst(value.(drinks)[h, :] .≈ 1.0)],
Dict(values(s) .=> keys(s))[findfirst(value.(smokes)[h, :] .≈ 1.0)]]
end
end
 
using DataFrames
DataFrame(colors=getindex.(m, 1),
nations=getindex.(m, 2),
pets=getindex.(m, 3),
drinks=getindex.(m, 4),
smokes=getindex.(m, 5))
</syntaxhighlight>
 
{{out}}
<pre>
: 5×5 DataFrame
: │ Row │ colors │ nations │ pets │ drinks │ smokes │
: ├─────┼──────────┼───────────┼──────────┼─────────────┼───────────────┤
: │ 1 │ yellow │ norwegian │ fox │ water │ kools │
: │ 2 │ blue │ ukrainian │ horse │ tea │ chesterfields │
: │ 3 │ red │ english │ snails │ milk │ winstons │
: │ 4 │ ivory │ spanish │ dog │ orangejuice │ luckystrikes │
: │ 5 │ green │ japanese │ zebra │ coffee │ parliaments │
</pre>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.3
 
fun nextPerm(perm: IntArray): Boolean {
val size = perm.size
var k = -1
for (i in size - 2 downTo 0) {
if (perm[i] < perm[i + 1]) {
k = i
break
}
}
if (k == -1) return false // last permutation
for (l in size - 1 downTo k) {
if (perm[k] < perm[l]) {
val temp = perm[k]
perm[k] = perm[l]
perm[l] = temp
var m = k + 1
var n = size - 1
while (m < n) {
val temp2 = perm[m]
perm[m++] = perm[n]
perm[n--] = temp2
}
break
}
}
return true
}
 
fun check(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
for (i in 0..4)
if (p[a1][i] == v1) return p[a2][i] == v2
return false
}
 
fun checkLeft(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
for (i in 0..3)
if (p[a1][i] == v1) return p[a2][i + 1] == v2
return false
}
 
fun checkRight(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
for (i in 1..4)
if (p[a1][i] == v1) return p[a2][i - 1] == v2
return false
}
 
fun checkAdjacent(a1: Int, a2: Int, v1: Int, v2: Int): Boolean {
return checkLeft(a1, a2, v1, v2) || checkRight(a1, a2, v1, v2)
}
 
val colors = listOf("Red", "Green", "White", "Yellow", "Blue")
val nations = listOf("English", "Swede", "Danish", "Norwegian", "German")
val animals = listOf("Dog", "Birds", "Cats", "Horse", "Zebra")
val drinks = listOf("Tea", "Coffee", "Milk", "Beer", "Water")
val smokes = listOf("Pall Mall", "Dunhill", "Blend", "Blue Master", "Prince")
 
val p = Array(120) { IntArray(5) { -1 } } // stores all permutations of numbers 0..4
 
fun fillHouses(): Int {
var solutions = 0
for (c in 0..119) {
if (!checkLeft(c, c, 1, 2)) continue // C5 : Green left of white
for (n in 0..119) {
if (p[n][0] != 3) continue // C10: Norwegian in First
if (!check(n, c, 0, 0)) continue // C2 : English in Red
if (!checkAdjacent(n, c, 3, 4)) continue // C15: Norwegian next to Blue
for (a in 0..119) {
if (!check(a, n, 0, 1)) continue // C3 : Swede has Dog
for (d in 0..119) {
if (p[d][2] != 2) continue // C9 : Middle drinks Milk
if (!check(d, n, 0, 2)) continue // C4 : Dane drinks Tea
if (!check(d, c, 1, 1)) continue // C6 : Green drinks Coffee
for (s in 0..119) {
if (!check(s, a, 0, 1)) continue // C7 : Pall Mall has Birds
if (!check(s, c, 1, 3)) continue // C8 : Yellow smokes Dunhill
if (!check(s, d, 3, 3)) continue // C13: Blue Master drinks Beer
if (!check(s, n, 4, 4)) continue // C14: German smokes Prince
if (!checkAdjacent(s, a, 2, 2)) continue // C11: Blend next to Cats
if (!checkAdjacent(s, a, 1, 3)) continue // C12: Dunhill next to Horse
if (!checkAdjacent(s, d, 2, 4)) continue // C16: Blend next to Water
solutions++
printHouses(c, n, a, d, s)
}
}
}
}
}
return solutions
}
 
fun printHouses(c: Int, n: Int, a: Int, d: Int, s: Int) {
var owner: String = ""
println("House Color Nation Animal Drink Smokes")
println("===== ====== ========= ====== ====== ===========")
for (i in 0..4) {
val f = "%3d %-6s %-9s %-6s %-6s %-11s\n"
System.out.printf(f, i + 1, colors[p[c][i]], nations[p[n][i]], animals[p[a][i]], drinks[p[d][i]], smokes[p[s][i]])
if (animals[p[a][i]] == "Zebra") owner = nations[p[n][i]]
}
println("\nThe $owner owns the Zebra\n")
}
 
fun main(args: Array<String>) {
val perm = IntArray(5) { it }
for (i in 0..119) {
for (j in 0..4) p[i][j] = perm[j]
nextPerm(perm)
}
val solutions = fillHouses()
val plural = if (solutions == 1) "" else "s"
println("$solutions solution$plural found")
}</syntaxhighlight>
 
{{out}}
<pre>
House Color Nation Animal Drink Smokes
===== ====== ========= ====== ====== ===========
1 Yellow Norwegian Cats Water Dunhill
2 Blue Danish Horse Tea Blend
3 Red English Birds Milk Pall Mall
4 Green German Zebra Coffee Prince
5 White Swede Dog Beer Blue Master
 
The German owns the Zebra
 
1 solution found
</pre>
 
=={{header|Logtalk}}==
The Logtalk distribution includes a solution for a variant of this puzzle (here reproduced with permission):
 
<syntaxhighlight lang="logtalk">
/* Houses logical puzzle: who owns the zebra and who drinks water?
 
1) Five colored houses in a row, each with an owner, a pet, cigarettes, and a drink.
2) The English lives in the red house.
3) The Spanish has a dog.
4) They drink coffee in the green house.
5) The Ukrainian drinks tea.
6) The green house is next to the white house.
7) The Winston smoker has a serpent.
8) In the yellow house they smoke Kool.
9) In the middle house they drink milk.
10) The Norwegian lives in the first house from the left.
11) The Chesterfield smoker lives near the man with the fox.
12) In the house near the house with the horse they smoke Kool.
13) The Lucky Strike smoker drinks juice.
14) The Japanese smokes Kent.
15) The Norwegian lives near the blue house.
 
Who owns the zebra and who drinks water?
*/
 
:- object(houses).
 
:- public(houses/1).
:- mode(houses(-list), one).
:- info(houses/1, [
comment is 'Solution to the puzzle.',
argnames is ['Solution']
]).
 
:- public(print/1).
:- mode(print(+list), one).
:- info(print/1, [
comment is 'Pretty print solution to the puzzle.',
argnames is ['Solution']
]).
 
houses(Solution) :-
template(Solution), % 1
member(h(english, _, _, _, red), Solution), % 2
member(h(spanish, dog, _, _, _), Solution), % 3
member(h(_, _, _, coffee, green), Solution), % 4
member(h(ukrainian, _, _, tea, _), Solution), % 5
next(h(_, _, _, _, green), h(_, _, _, _, white), Solution), % 6
member(h(_, snake, winston, _, _), Solution), % 7
member(h(_, _, kool, _, yellow), Solution), % 8
Solution = [_, _, h(_, _, _, milk, _), _, _], % 9
Solution = [h(norwegian, _, _, _, _)| _], % 10
next(h(_, fox, _, _, _), h(_, _, chesterfield, _, _), Solution), % 11
next(h(_, _, kool, _, _), h(_, horse, _, _, _), Solution), % 12
member(h(_, _, lucky, juice, _), Solution), % 13
member(h(japonese, _, kent, _, _), Solution), % 14
next(h(norwegian, _, _, _, _), h(_, _, _, _, blue), Solution), % 15
member(h(_, _, _, water, _), Solution), % one of them drinks water
member(h(_, zebra, _, _, _), Solution). % one of them owns a zebra
 
print([]).
print([House| Houses]) :-
write(House), nl,
print(Houses).
 
% h(Nationality, Pet, Cigarette, Drink, Color)
template([h(_, _, _, _, _), h(_, _, _, _, _), h(_, _, _, _, _), h(_, _, _, _, _), h(_, _, _, _, _)]).
 
member(A, [A, _, _, _, _]).
member(B, [_, B, _, _, _]).
member(C, [_, _, C, _, _]).
member(D, [_, _, _, D, _]).
member(E, [_, _, _, _, E]).
 
next(A, B, [A, B, _, _, _]).
next(B, C, [_, B, C, _, _]).
next(C, D, [_, _, C, D, _]).
next(D, E, [_, _, _, D, E]).
 
:- end_object.
</syntaxhighlight>
 
Sample query:
<syntaxhighlight lang="text">
| ?- houses::(houses(S), print(S)).
h(norwegian,fox,kool,water,yellow)
h(ukrainian,horse,chesterfield,tea,blue)
h(english,snake,winston,milk,red)
h(japonese,zebra,kent,coffee,green)
h(spanish,dog,lucky,juice,white)
 
S = [h(norwegian,fox,kool,water,yellow),h(ukrainian,horse,chesterfield,tea,blue),h(english,snake,winston,milk,red),h(japonese,zebra,kent,coffee,green),h(spanish,dog,lucky,juice,white)]
</syntaxhighlight>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
This creates a table that has 5 columns, and 25 rows. We fill the table; each column is the same and equal to all the options joined together in blocks of 5:
<pre> 1 2 3 4 5
colors Blue Blue Blue Blue Blue
colors Green Green Green Green Green
colors Red Red Red Red Red
colors White White White White White
colors Yellow Yellow Yellow Yellow Yellow
nationality Dane Dane Dane Dane Dane
nationality English English English English English
nationality German German German German German
nationality Norwegian Norwegian Norwegian Norwegian Norwegian
nationality Swede Swede Swede Swede Swede
beverage Beer Beer Beer Beer Beer
beverage Coffee Coffee Coffee Coffee Coffee
beverage Milk Milk Milk Milk Milk
beverage Tea Tea Tea Tea Tea
beverage Water Water Water Water Water
animal Birds Birds Birds Birds Birds
animal Cats Cats Cats Cats Cats
animal Dog Dog Dog Dog Dog
animal Horse Horse Horse Horse Horse
animal Zebra Zebra Zebra Zebra Zebra
smoke Blend Blend Blend Blend Blend
smoke Blue Master Blue Master Blue Master Blue Master Blue Master
smoke Dunhill Dunhill Dunhill Dunhill Dunhill
smoke Pall Mall Pall Mall Pall Mall Pall Mall Pall Mall
smoke Prince Prince Prince Prince Prince</pre>
This should be read as follows: Each column shows (in blocks of 5) the possible candidates of each kind (beverage, animal, smoke...)
We solve it now in a 'sudoku' way: We remove candidates iteratively until we are left with 1 candidate of each kind for each house.
<syntaxhighlight lang="mathematica">ClearAll[EliminatePoss, FilterPuzzle]
EliminatePoss[ct_, key1_, key2_] := Module[{t = ct, poss1, poss2, poss, notposs},
poss1 = Position[t, key1];
poss2 = Position[t, key2];
poss = Intersection[Last /@ poss1, Last /@ poss2];
notposs = Complement[Range[5], poss];
poss1 = Select[poss1, MemberQ[notposs, Last[#]] &];
poss2 = Select[poss2, MemberQ[notposs, Last[#]] &];
t = ReplacePart[t, poss1 -> Null];
t = ReplacePart[t, poss2 -> Null];
t
]
FilterPuzzle[tbl_] := Module[{t = tbl, poss1, poss2, poss, notposs, rows, columns, vals, sets, delpos},
t = EliminatePoss[t, "English", "Red"]; (*2. The English man lives in the red house. *)
t = EliminatePoss[t, "Swede", "Dog"]; (* 3. The Swede has a dog. *)
t = EliminatePoss[t, "Dane", "Tea"]; (* 4. The Dane drinks tea. *)
t = EliminatePoss[t, "Green", "Coffee"]; (* 6. They drink coffee in the green house. *)
t = EliminatePoss[t, "Pall Mall", "Birds"]; (* 7. The man who smokes Pall Mall has birds.*)
t = EliminatePoss[t, "Yellow", "Dunhill"]; (* 8. In the yellow house they smoke Dunhill. *)
t = EliminatePoss[t, "Blue Master", "Beer"]; (*13. The man who smokes Blue Master drinks beer. *)
t = EliminatePoss[t, "German", "Prince"]; (* 14. The German smokes Prince. *)
(* 9. In the middle house they drink milk. *)
poss = Position[t, "Milk"];
delpos = Select[poss, #[[2]] != 3 &];
t = ReplacePart[t, delpos -> Null];
 
(* 10. The Norwegian lives in the first house. *)
poss = Position[t, "Norwegian"];
delpos = Select[poss, #[[2]] != 1 &];
t = ReplacePart[t, delpos -> Null];
(* 15. The Norwegian lives next to the blue house.*)
poss1 = Position[t, "Norwegian"];
poss2 = Position[t, "Blue"];
poss = Tuples[{poss1, poss2}];
poss = Select[poss, #[[1, 2]] + 1 == #[[2, 2]] \[Or] #[[1, 2]] - 1 == #[[2, 2]] &]\[Transpose];
delpos = Complement[poss1, poss[[1]]];
t = ReplacePart[t, delpos -> Null];
delpos = Complement[poss2, poss[[2]]];
t = ReplacePart[t, delpos -> Null];
(* 5. The green house is immediately to the left of the white house. *)
poss1 = Position[t, "Green"];
poss2 = Position[t, "White"];
poss = Tuples[{poss1, poss2}];
poss = Select[poss, #[[1, 2]] + 1 == #[[2, 2]] &]\[Transpose];
delpos = Complement[poss1, poss[[1]]];
t = ReplacePart[t, delpos -> Null];
delpos = Complement[poss2, poss[[2]]];
t = ReplacePart[t, delpos -> Null];
(*11. The man who smokes Blend lives in the house next to the house with cats.*)
poss1 = Position[t, "Blend"];
poss2 = Position[t, "Cats"];
poss = Tuples[{poss1, poss2}];
poss = Select[poss, #[[1, 2]] + 1 == #[[2, 2]] \[Or] #[[1, 2]] - 1 == #[[2, 2]] &]\[Transpose];
delpos = Complement[poss1, poss[[1]]];
t = ReplacePart[t, delpos -> Null];
delpos = Complement[poss2, poss[[2]]];
t = ReplacePart[t, delpos -> Null];
(* 12. In a house next to the house where they have a horse, they smoke Dunhill. *)
poss1 = Position[t, "Horse"];
poss2 = Position[t, "Dunhill"];
poss = Tuples[{poss1, poss2}];
poss = Select[poss, #[[1, 2]] + 1 == #[[2, 2]] \[Or] #[[1, 2]] - 1 == #[[2, 2]] &]\[Transpose];
delpos = Complement[poss1, poss[[1]]];
t = ReplacePart[t, delpos -> Null];
delpos = Complement[poss2, poss[[2]]];
t = ReplacePart[t, delpos -> Null];
(* 16. They drink water in a house next to the house where they smoke Blend. *)
poss1 = Position[t, "Water"];
poss2 = Position[t, "Blend"];
poss = Tuples[{poss1, poss2}];
poss = Select[poss, #[[1, 2]] + 1 == #[[2, 2]] \[Or] #[[1, 2]] - 1 == #[[2, 2]] &]\[Transpose];
delpos = Complement[poss1, poss[[1]]];
t = ReplacePart[t, delpos -> Null];
delpos = Complement[poss2, poss[[2]]];
t = ReplacePart[t, delpos -> Null];
(*General rule 1 in a line => cross out vertical and horizontal lines*)
(* 1 in a row*)
vals = Select[t, Count[#, Null] == 4 &];
vals = DeleteCases[Flatten[vals], Null];
poss = Flatten[Position[t, #] & /@ vals, 1];
delpos = With[{r = First[#], c = Last[#]}, {#, c} & /@ (Range[-4, 0] + Ceiling[r, 5])] & /@ poss; (*delete in columns*)
delpos = Flatten[MapThread[DeleteCases, {delpos, poss}], 1];
t = ReplacePart[t, delpos -> Null];
(* 1 in a column*)
sets = Flatten[Table[{i + k*5, j}, {k, 0, 4}, {j, 1, 5}, {i, 1, 5}],1];
sets = {#, Extract[t, #]} & /@ sets;
sets = Select[sets, Count[#[[2]], Null] == 4 &];
sets = Flatten[Transpose /@ sets, 1];
sets = DeleteCases[sets, {{_, _}, Null}];
delpos = sets[[All, 1]];(*delete in rows*)
delpos = With[{r = First[#], c = Last[#]}, {r, #} & /@ (DeleteCases[Range[5], c])] & /@ delpos;
delpos = Flatten[delpos, 1];
t = ReplacePart[t, delpos -> Null];
t
]
colors = {"Blue", "Green", "Red", "White", "Yellow"};
nationality = {"Dane", "English", "German", "Norwegian", "Swede"};
beverage = {"Beer", "Coffee", "Milk", "Tea", "Water"};
animal = {"Birds", "Cats", "Dog", "Horse", "Zebra"};
smoke = {"Blend", "Blue Master", "Dunhill", "Pall Mall", "Prince"};
vals = {colors, nationality, beverage, animal, smoke};
bigtable = Join @@ (ConstantArray[#, 5]\[Transpose] & /@ vals);
 
bigtable = FixedPoint[FilterPuzzle, bigtable];
TableForm[DeleteCases[bigtable\[Transpose], Null, \[Infinity]], TableHeadings -> {Range[5], None}]</syntaxhighlight>
Using the command FixedPoint, we iteratively filter out these candidates, until we are (hopefully) left with 1 candidate per kind per house.
{{out}}
<pre>1 Yellow Norwegian Water Cats Dunhill
2 Blue Dane Tea Horse Blend
3 Red English Milk Birds Pall Mall
4 Green German Coffee Zebra Prince
5 White Swede Beer Dog Blue Master</pre>
 
=={{header|Mercury}}==
<syntaxhighlight lang="mercury">:- module zebra.
:- interface.
 
:- import_module io.
 
:- pred main(io, io).
:- mode main(di, uo) is cc_multi. % or det for all-solutions
 
:- implementation.
 
:- import_module list.
:- import_module solutions.
 
% perm
 
:- pred my_perm(list(T), list(T)).
:- mode my_perm(in, out) is multi.
 
my_perm([], []).
my_perm([X | Xs], Perm) :-
my_perm(Xs, PermXs),
my_insert(X, PermXs, Perm).
 
:- pred my_insert(T, list(T), list(T)).
:- mode my_insert(in, in, out) is multi.
 
my_insert(X, [], [X]).
my_insert(X, [Y | Ys], Zs) :-
(
Zs = [X, Y | Ys]
;
my_insert(X, Ys, Zs0),
Zs = [Y | Zs0]
).
 
% The puzzle
 
:- type person
---> english
; spanish
; ukrainian
; norwegian
; japanese.
 
:- pred left_of(list(T), T, T).
:- mode left_of(in, in, in) is semidet.
 
left_of([A, B | _], A, B).
left_of([_ | List], A, B) :- left_of(List, A, B).
 
:- pred next_to(list(T), T, T).
:- mode next_to(in, in, in) is semidet.
 
next_to(List, A, B) :-
( left_of(List, A, B)
; left_of(List, B, A)
).
 
:- pred puzzle({list(person), list(person), list(person), list(person),
list(person)}).
:- mode puzzle(out) is nondet.
 
puzzle({Houses, Colours, Pets, Drinks, Smokes}) :-
% 10. The Norwegian lives in the first house.
First = norwegian,
perm([english, spanish, ukrainian, japanese],
[Second, Third, Fourth, Fifth]),
 
% 2. The Englishman lives in the red house.
Red = english,
perm([spanish, ukrainian, norwegian, japanese],
[Green, Ivory, Yellow, Blue]),
 
% 10. The Norwegian lives in the first house.
% 15. The Norwegian lives next to the blue house.
Second = Blue,
 
% 6. The green house is immediately to the right of the ivory house.
left_of(Houses, Ivory, Green),
 
% 3. The Spaniard owns the dog.
Dog = spanish,
perm([english, ukrainian, norwegian, japanese],
[Snails, Fox, Horse, Zebra]),
 
% 4. Coffee is drunk in the green house.
Green = Coffee,
 
% 5. The Ukrainian drinks tea.
Tea = ukrainian,
 
% 9. Milk is drunk in the middle house.
Milk = Third,
 
perm([english, spanish, norwegian, japanese],
[Coffee, Milk, Juice, Water]),
 
% 7. The Old Gold smoker owns snails.
Snails = OldGold,
 
% 8. Kools are smoked in the yellow house.
Kools = Yellow,
 
% 13. The Lucky Strike smoker drinks orange juice.
LuckyStrike = Juice,
 
% 14. The Japanese smokes Parliaments.
Parliament = japanese,
 
perm([english, spanish, ukrainian, norwegian],
[OldGold, Kools, Chesterfield, LuckyStrike]),
 
% 11. The man who smokes Chesterfields lives in the house
% next to the man with the fox.
next_to(Houses, Chesterfield, Fox),
 
% 12. Kools are smoked in the house next to the house
% where the horse is kept.
next_to(Houses, Kools, Horse),
 
Houses = [First, Second, Third, Fourth, Fifth],
Colours = [Red, Green, Ivory, Yellow, Blue],
Pets = [Dog, Snails, Fox, Horse, Zebra],
Drinks = [Coffee, Tea, Milk, Juice, Water],
Smokes = [OldGold, Kools, Chesterfield, LuckyStrike, Parliament].
 
% Printing a solution
 
:- pred write_solution({list(person), list(person), list(person),
list(person), list(person)}::in, io::di, io::uo) is det.
 
write_solution({Houses, Colours, Pets, Drinks, Smokes}, !IO) :-
write_string("--------\n", !IO),
write_assignments(["1st", "2nd", "3rd", "4th", "5th"],
Houses, !IO),
write_assignments(["red", "green", "ivory", "yellow", "blue"],
Colours, !IO),
write_assignments(["dog", "snails", "fox", "horse", "zebra"],
Pets, !IO),
write_assignments(["coffee", "tea", "milk", "juice", "water"],
Drinks, !IO),
write_assignments(["oldgold", "kools", "chesterfield",
"luckystrike", "parliament"], Smokes, !IO).
 
:- pred write_assignments(list(string)::in, list(person)::in,
io::di, io::uo) is det.
 
write_assignments(Labels, Persons, !IO) :-
foldl_corresponding(write_assignment, Labels, Persons, !IO),
nl(!IO).
 
:- pred write_assignment(string::in, person::in, io::di, io::uo) is det.
 
write_assignment(Label, Person, !IO) :-
write_string(Label, !IO),
write_string(" - ", !IO),
write(Person, !IO),
write_string("\n", !IO).
 
% main
 
main(!IO) :-
% Print all solutions.
/*
solutions(puzzle, Solutions),
foldl(write_solution, Solutions, !IO).
*/
 
% Print solutions as they are found.
/*
unsorted_aggregate(puzzle, write_solution, !IO).
*/
 
% Print one solution.
( if puzzle(Solution) then
write_solution(Solution, !IO)
else
write_string("No solution found.\n", !IO)
).
</syntaxhighlight>
{{out}}
<pre>--------
1st - norwegian
2nd - ukrainian
3rd - english
4th - spanish
5th - japanese
 
red - english
green - japanese
ivory - spanish
yellow - norwegian
blue - ukrainian
 
dog - spanish
snails - english
fox - norwegian
horse - ukrainian
zebra - japanese
 
coffee - japanese
tea - ukrainian
milk - english
juice - spanish
water - norwegian
 
oldgold - english
kools - norwegian
chesterfield - ukrainian
luckystrike - spanish
parliament - japanese</pre>
=={{header|MiniZinc}}==
<syntaxhighlight lang="minizinc">
%Solve Zebra Puzzle. Nigel Galloway, August 27th., 2019
include "alldifferent.mzn";
enum N={English,Swedish,Danish,German,Norwegian};
enum I={Tea,Coffee,Milk,Beer,Water};
enum G={Dog,Birds,Cats,Horse,Zebra};
enum E={Red,Green,White,Blue,Yellow};
enum L={PallMall,Dunhill,BlueMaster,Prince,Blend};
array[1..5] of var N: Nz; constraint alldifferent(Nz); constraint Nz[1]=Norwegian; %The Norwegian lives in the first house.
array[1..5] of var I: Iz; constraint alldifferent(Iz); constraint Iz[3]=Milk; %In the middle house they drink milk.
array[1..5] of var G: Gz; constraint alldifferent(Gz);
array[1..5] of var E: Ez; constraint alldifferent(Ez);
array[1..5] of var L: Lz; constraint alldifferent(Lz);
constraint exists(n in 1..5)(Nz[n]=English /\ Ez[n]=Red); %The English man lives in the red house
constraint exists(n in 1..5)(Nz[n]=Swedish /\ Gz[n]=Dog); %The Swede has a dog.
constraint exists(n in 1..5)(Nz[n]=Danish /\ Iz[n]=Tea); %The Dane drinks tea.
constraint exists(n in 1..4)(Ez[n]=Green /\ Ez[n+1]=White); %The green house is immediately to the left of the white house.
constraint exists(n in 1..5)(Ez[n]=Green /\ Iz[n]=Coffee); %They drink coffee in the green house.
constraint exists(n in 1..5)(Lz[n]=PallMall /\ Gz[n]=Birds); %The man who smokes Pall Mall has birds
constraint exists(n in 1..5)(Ez[n]=Yellow /\ Lz[n]=Dunhill); %In the yellow house they smoke Dunhill.
constraint exists(n in 1..4)((Lz[n]=Blend /\ Gz[n+1]=Cats) \/ (Lz[n+1]=Blend /\ Gz[n]=Cats)); %The man who smokes Blend lives in the house next to the house with cats.
constraint exists(n in 1..4)((Gz[n]=Horse /\ Lz[n+1]=Dunhill) \/ (Gz[n+1]=Horse /\ Lz[n]=Dunhill)); %In a house next to the house where they have a horse, they smoke Dunhill.
constraint exists(n in 1..5)(Lz[n]=BlueMaster /\ Iz[n]=Beer); %The man who smokes Blue Master drinks beer.
constraint exists(n in 1..5)(Nz[n]=German /\ Lz[n]=Prince); %The German smokes Prince.
constraint exists(n in 1..4)((Nz[n]=Norwegian /\ Ez[n+1]=Blue) \/ (Nz[n+1]=Norwegian /\ Ez[n]=Blue));%The Norwegian lives next to the blue house.
constraint exists(n in 1..4)((Lz[n]=Blend /\ Iz[n+1]=Water) \/ (Lz[n+1]=Blend /\ Iz[n]=Water)); %They drink water in a house next to the house where they smoke Blend.
var 1..5: n;
constraint Gz[n]=Zebra;
solve satisfy;
output ["The "++show(Nz[n])++" owns the zebra"++"\n\n"++show(Nz)++"\n"++show(Iz)++"\n"++show(Gz)++"\n"++show(Ez)++"\n"++show(Lz)++"\n"];
</syntaxhighlight>
{{out}}
<pre>
The German owns the zebra
 
[Norwegian, Danish, English, German, Swedish]
[Water, Tea, Milk, Coffee, Beer]
[Cats, Horse, Birds, Zebra, Dog]
[Yellow, Blue, Red, Green, White]
[Dunhill, Blend, PallMall, Prince, BlueMaster]
----------
</pre>
 
=={{header|Nial}}==
 
{{works with|Q'Nial Version 6.3}}
 
I put a backslash ( \ ) at the end of many lines so that the code can
be pasted into the REPL.
 
<syntaxhighlight lang="nial">
remove is op x xs {filter (not (x =)) xs}
 
append_map is transformer func op seq { \
reduce (op x xs { (func x) link xs}) (seq append []) }
 
permutations is op seq { \
if empty seq then [[]] else \
(append_map \
(op head {each (op tail {head hitch tail}) \
(permutations (remove head seq))}) \
seq) \
endif}
 
f is find
tokenize is op str{string_split ' ' str}
mk is tr pred op str {filter pred permutations tokenize str}
eq is op x xs y ys{f x xs = f y ys}
adj is op x xs y ys{1 = abs(f x xs - f y ys)}
 
run is { \
men := mk (op xs {0 = f 'norwegian' xs}) \
'danish english german norwegian swedish'; \
colors := mk (op xs {1 = ((f 'white' xs) - (f 'green' xs))}) \
'blue green red white yellow'; \
drinks := mk (op xs {2 = f 'milk' xs}) 'beer coffee milk tea water'; \
pets := mk (op xs {l}) 'birds cats dog horse zebra'; \
smokes := mk (op xs {l}) 'blend blue-master dunhill pall-mall prince'; \
for m with men do \
for c with colors do \
if (eq 'english' m 'red' c) and \
(adj 'norwegian' m 'blue' c) then \
for d with drinks do \
if (eq 'danish' m 'tea' d) and \
(eq 'coffee' d 'green' c) then \
for s with smokes do \
if (eq 'yellow' c 'dunhill' s) and \
(eq 'blue-master' s 'beer' d) and \
(eq 'german' m 'prince' s) then \
for p with pets do \
if (eq 'birds' p 'pall-mall' s) and \
(eq 'swedish' m 'dog' p) and \
(adj 'blend' s 'cats' p) and \
(adj 'horse' p 'dunhill' s) then \
write (0 blend (p m c d s)) \
endif \
endfor \
endif \
endfor \
endif \
endfor \
endif \
endfor \
endfor }
 
abs(time - (run; time))
</syntaxhighlight>
 
{{out}}
<pre>
+-----------------------------------------+
|cats |norwegian|yellow|water |dunhill |
+-----+---------+------+------+-----------|
|horse|danish |blue |tea |blend |
+-----+---------+------+------+-----------|
|birds|english |red |milk |pall-mall |
+-----+---------+------+------+-----------|
|zebra|german |green |coffee|prince |
+-----+---------+------+------+-----------|
|dog |swedish |white |beer |blue-master|
+-----------------------------------------+
0.03
</pre>
 
=={{header|Nim}}==
 
Using the same order for test of criteria as in Kotlin solution.
 
<syntaxhighlight lang="nim">import algorithm, strformat, sequtils
 
type
 
Color {.pure.} = enum Blue, Green, Red, White, Yellow
Person {.pure.} = enum Dane, English, German, Norwegian, Swede
Pet {.pure.} = enum Birds, Cats, Dog, Horse, Zebra
Drink {.pure.} = enum Beer, Coffee, Milk, Tea, Water
Cigarettes {.pure.} = enum Blend, BlueMaster = "Blue Master",
Dunhill, PallMall = "Pall Mall", Prince
 
House = tuple
color: Color
person: Person
pet: Pet
drink: Drink
cigarettes: Cigarettes
 
Houses = array[5, House]
 
 
iterator permutations[T](): array[5, T] =
## Yield the successive permutations of values of type T.
var term = [T(0), T(1), T(2), T(3), T(4)]
yield term
while term.nextPermutation():
yield term
 
 
proc findSolutions(): seq[Houses] =
## Return all the solutions.
 
for colors in permutations[Color]():
if colors.find(White) != colors.find(Green) + 1: continue # 5
for persons in permutations[Person]():
if persons[0] != Norwegian: continue # 10
if colors.find(Red) != persons.find(English): continue # 2
if abs(persons.find(Norwegian) - colors.find(Blue)) != 1: continue # 15
for pets in permutations[Pet]():
if persons.find(Swede) != pets.find(Dog): continue # 3
for drinks in permutations[Drink]():
if drinks[2] != Milk: continue # 9
if persons.find(Dane) != drinks.find(Tea): continue # 4
if colors.find(Green) != drinks.find(Coffee): continue # 6
for cigarettes in permutations[Cigarettes]():
if cigarettes.find(PallMall) != pets.find(Birds): continue # 7
if cigarettes.find(Dunhill) != colors.find(Yellow): continue # 8
if cigarettes.find(BlueMaster) != drinks.find(Beer): continue # 13
if cigarettes.find(Prince) != persons.find(German): continue # 14
if abs(cigarettes.find(Blend) - pets.find(Cats)) != 1: continue # 11
if abs(cigarettes.find(Dunhill) - pets.find(Horse)) != 1: continue # 12
if abs(cigarettes.find(Blend) - drinks.find(Water)) != 1: continue # 16
var houses: Houses
for i in 0..4:
houses[i] = (colors[i], persons[i], pets[i], drinks[i], cigarettes[i])
result.add houses
 
let solutions = findSolutions()
echo "Number of solutions: ", solutions.len
let sol = solutions[0]
echo()
 
echo "Number Color Person Pet Drink Cigarettes"
echo "—————— —————— ————————— ————— —————— ———————————"
for i in 0..4:
echo &"{i + 1:3} {sol[i].color:6} {sol[i].person:9} ",
&"{sol[i].pet:5} {sol[i].drink:6} {sol[i].cigarettes: 11}"
 
let owner = sol.filterIt(it.pet == Zebra)[0].person
echo &"\nThe {owner} owns the zebra."</syntaxhighlight>
 
{{out}}
<pre>Number of solutions: 1
 
Number Color Person Pet Drink Cigarettes
—————— —————— ————————— ————— —————— ———————————
1 Yellow Norwegian Cats Water Dunhill
2 Blue Dane Horse Tea Blend
3 Red English Birds Milk Pall Mall
4 Green German Zebra Coffee Prince
5 White Swede Dog Beer Blue Master
 
The German owns the zebra.</pre>
 
=={{header|PARI/GP}}==
<syntaxhighlight lang="none">
perm(arr) = {
n=#arr;i=n-1;
while(i > -1,if (arr[i] < arr[i+1],break);i--);
j=n;
while(arr[j]<= arr[i],j -=1);
tmp = arr[i] ;arr[i]=arr[j];arr[j]=tmp;
i +=1; j = n;
while(i < j ,tmp = arr[i] ;arr[i]=arr[j];arr[j]=tmp;
i +=1; j -=1);
return(arr);
}
perms(arr)={
n=#arr;
result = List();
listput(result,arr);
for(i=1,n!-1,arr=perm(arr);listput(result,arr));
return(result);
}
 
adj(x,xs,y,ys)={
abs(select(z->z==x,xs,1)[1] - select(z->z==y,ys,1)[1])==1;
}
eq(x,xs,y,ys)={
select(z->z==x,xs,1) == select(z->z==y,ys,1);
}
 
colors =Vec(perms( ["Blue", "Green", "Red", "White", "Yellow"]));;
drinks =Vec(perms( ["Beer", "Coffee", "Milk", "Tea", "Water"]));;
nations =Vec(perms( ["Denmark", "England", "Germany", "Norway", "Sweden"]));;
smokes =Vec(perms( ["Blend", "BlueMaster", "Dunhill", "PallMall", "Prince"]));;
pets =Vec(perms( ["Birds", "Cats", "Dog", "Horse", "Zebra"]));;;
colors= select(x->select(z->z=="White",x,1)[1] - select(z->z=="Green",x,1)[1]==1,colors);
drinks=select(x->x[3]=="Milk",drinks);
nations=select(x->x[1]=="Norway",nations);
 
for(n=1,#nations,for(c=1,#colors,\
if(eq("Red",colors[c],"England",nations[n]) && adj("Norway",nations[n],"Blue",colors[c]),\
for(d=1,#drinks,\
if(eq("Denmark",nations[n],"Tea",drinks[d])&& eq("Coffee",drinks[d],"Green",colors[c]),\
for(s=1,#smokes,\
if(eq("Yellow",colors[c],"Dunhill",smokes[s]) &&\
eq("BlueMaster",smokes[s],"Beer",drinks[d]) &&\
eq("Germany",nations[n],"Prince",smokes[s]),\
for(p=1,#pets,\
if(eq("Birds",pets[p],"PallMall",smokes[s]) &&\
eq("Sweden",nations[n],"Dog",pets[p]) &&\
adj("Blend",smokes[s],"Cats",pets[p]) &&\
adj("Horse",pets[p],"Dunhill",smokes[s]),\
print("Zebra is owned by ",nations[n][select(z->z=="Zebra",pets[p],1)[1]]);print();\
for(i=1,5,printf("House:%s %6s %10s %10s %10s %10s\n",i,colors[c][i],nations[n][i],pets[p][i],drinks[d][i],smokes[s][i]));\
)))))))));
</syntaxhighlight>
 
{{out}}
<pre>
Zebra is owned by Germany
 
House:1 Yellow Norway Cats Water Dunhill
House:2 Blue Denmark Horse Tea Blend
House:3 Red England Birds Milk PallMall
House:4 Green Germany Zebra Coffee Prince
House:5 White Sweden Dog Beer BlueMaster
 
</pre>
 
=={{header|Perl}}==
Basically the same idea as C, though of course it's much easier to have Perl generate Perl code.
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
 
use utf8;
Line 842 ⟶ 5,283:
pair qw( water blend -1 1 );
 
$solve->();</langsyntaxhighlight>
 
Incidentally, the same logic can be used to solve the dwelling problem, if somewhat awkwardly:
<langsyntaxhighlight lang="perl">...
# property names and values
setprops
Line 865 ⟶ 5,306:
pair qw(cooper fletcher 4 3 2 -2 -3 -4);
 
$solve->();</langsyntaxhighlight>
 
=={{header|Phix}}==
<!--(phixonline)-->
<syntaxhighlight lang="phix">
--enum colour, nationality, drink, smoke, pet -- (now implicit)
enum red,white,green,yellow,blue
enum English,Swede,Dane,Norwegian,German
enum tea,coffee,milk,beer,water
enum PallMall,Dunhill,Blend,BlueMaster,Prince
enum dog,birds,cats,horse,zebra
 
constant colours = {"red","white","green","yellow","blue"},
nationalities = {"English","Swede","Dane","Norwegian","German"},
drinks = {"tea","coffee","milk","beer","water"},
smokes = {"Pall Mall","Dunhill","Blend","Blue Master","Prince"},
pets = {"dog","birds","cats","horse","zebra"},
sets = {colours,nationalities,drinks,smokes,pets}
constant p5 = permutes(tagset(5)), -- all permutes of {1,2,3,4,5},
lp = length(p5) -- (== factorial(5), ie 120)
// In the following, c1,c2 are indexes to p5, for colour..pet,
// and v1,v2 are from their corresponding enums, so eg p5[c1]
// might be {1,4,3,2,5} for the colours of 1..5 and finding
// v1 in that gives us a house number. Checking the specified
// condition, eg [h] == green && [h+1] == white is then easy.
 
function left_of(integer c1, v1, c2, v2)
integer h = find(v1,p5[c1])
return h<=4 and p5[c2][h+1]=v2
end function
 
function same_house(integer c1, v1, c2, v2)
integer h = find(v1,p5[c1])
return p5[c2][h]=v2
end function
function next_to(integer c1, v1, c2, v2)
integer h1 = find(v1,p5[c1]),
h2 = find(v2,p5[c2])
return abs(h1-h2)=1
end function
procedure print_house(integer n, sequence perm)
sequence args = {n}
for i,p in perm do
args = append(args,sets[i][p5[p][n]])
end for
printf(1,"House %d: %|7s %|10s %|6s %|12s %=6s\n",args)
end procedure
integer ns = 0
atom t0 = time()
for colour=1 to lp do
if left_of(colour,green,colour,white) then
for nationality=1 to lp do
if p5[nationality][1]=Norwegian -- Norwegian lives in 1st house
and same_house(nationality,English,colour,red)
and next_to(nationality,Norwegian,colour,blue) then
for drink=1 to lp do
if same_house(nationality,Dane,drink,tea)
and same_house(drink,coffee,colour,green)
and p5[drink][3]=milk then -- middle house drinks milk
for smoke=1 to lp do
if same_house(colour,yellow,smoke,Dunhill)
and same_house(nationality,German,smoke,Prince)
and same_house(smoke,BlueMaster,drink,beer)
and next_to(drink,water,smoke,Blend) then
for pet=1 to lp do
if same_house(nationality,Swede,pet,dog)
and same_house(smoke,PallMall,pet,birds)
and next_to(smoke,Blend,pet,cats)
and next_to(pet,horse,smoke,Dunhill) then
for i=1 to 5 do
print_house(i,{colour,nationality,drink,smoke,pet})
end for
integer z = p5[nationality][find(zebra,p5[pet])]
printf(1,"The %s owns the Zebra\n",{nationalities[z]})
ns += 1
end if
end for
end if
end for
end if
end for
end if
end for
end if
end for
printf(1,"%d solution%s found (%3.3fs).\n",{ns,iff(ns>1,"s",""),time()-t0})
</syntaxhighlight>
{{out}}
<pre>
House 1: yellow Norwegian water Dunhill cats
House 2: blue Dane tea Blend horse
House 3: red English milk Pall Mall birds
House 4: green German coffee Prince zebra
House 5: white Swede beer Blue Master dog
The German owns the Zebra
1 solution found (0.000s).
</pre>
 
=={{header|Picat}}==
<syntaxhighlight lang="picat">import cp.
 
main =>
Nat = [English, Swede, Dane, German, Norwegian],
Color = [Red, Green, White, Yellow, Blue],
Smoke = [PallMall, Dunhill, Blend, SBlue, Prince],
Pet = [Dog, Bird, Cat, Horse, Zebra],
Drink = [Tea, Coffee, Milk, Beer, Water],
 
Nat :: 1..5,
Color :: 1..5,
Smoke :: 1..5,
Pet :: 1..5,
Drink :: 1..5,
 
all_different(Nat),
all_different(Color),
all_different(Smoke),
all_different(Pet),
all_different(Drink),
 
English = Red,
Swede = Dog,
Dane = Tea,
Green #= White-1,
Coffee = Green,
Bird = PallMall,
Yellow = Dunhill,
Milk = 3,
Norwegian = 1,
abs(Blend-Cat) #= 1,
abs(Dunhill-Horse) #= 1,
SBlue = Beer,
German = Prince,
abs(Norwegian-Blue) #= 1,
abs(Blend-Water) #= 1,
 
solve(Nat ++ Color ++ Smoke ++ Pet ++ Drink),
 
L = [English=english,
Swede=swede,
Dane=dane,
German=german,
Norwegian=norwegian].sort(),
member(Zebra=ZebraOwner, L),
writef("The %w owns the zebra\n", ZebraOwner),
writeln(L).
</syntaxhighlight>
{{out}}
<pre>
The german owns the zebra
[1 = norwegian,2 = dane,3 = english,4 = german,5 = swede]
</pre>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(be match (@House @Person @Drink @Pet @Cigarettes)
(permute (red blue green yellow white) @House)
(left-of @House white @House green)
Line 908 ⟶ 5,505:
 
(be next-to (@X @A @Y @B) (right-of @X @A @Y @B))
(be next-to (@X @A @Y @B) (left-of @X @A @Y @B))</langsyntaxhighlight>
Test:
<langsyntaxhighlight PicoLisplang="picolisp">(pilog '((match @House @Person @Drink @Pet @Cigarettes))
(let Fmt (-8 -11 -8 -7 -11)
(tab Fmt "HOUSE" "PERSON" "DRINKS" "HAS" "SMOKES")
(mapc '(@ (pass tab Fmt))
@House @Person @Drink @Pet @Cigarettes ) ) )</langsyntaxhighlight>
Output:
<pre>HOUSE PERSON DRINKS HAS SMOKES
Line 927 ⟶ 5,524:
In Prolog we can specify the domain by selecting elements from it, making mutually exclusive choices for efficiency:
 
<langsyntaxhighlight Prologlang="prolog">select([A|As],S):- select(A,S,S1),select(As,S1).
select([],_).
Line 934 ⟶ 5,531:
zebra(Owns, HS):- % color,nation,pet,drink,smokes
HS = [ h(_,norwegian,_,_,_), _, h(_,_,_,milk,_), _, _],
select( [ h(red,englishman,_,_,_), h(_,swede,dog,_,_),h(_,dane,_,tea,_),
h(_,germandane,_,_tea,prince_)], h(_,german,_,_,prince) ], HS),
select( [ h(_,_,birds,_,pallmall), h(yellow,_,_,_,dunhill),
h(_,_,_,beer,bluemaster) ], HS),
left_of( h(green,_,_,coffee,_), h(white,_,_,_,_), HS),
next_to( h(_,_,_,_,dunhill), h(_,_,horse,_,_), HS),
next_to( h(_,_,_,_,blend), h(_,_,cats, _,_), HS),
next_to( h(_,_,_,_,blend), h(_,_,_,water,_), HS),
next_to( h(_,norwegian,_,_,_), h(blue,_,_,_,_), HS),
member( h(_,Owns,zebra,_,_), HS).
 
:- ?- time(( zebra(Who, HS), maplist(writeln,HS), nl, write(Who), nl, nl, fail
; write('No more solutions.') )).</syntaxhighlight>
;
write('No more solutions.').</lang>
 
Output:
<pre>
h(yellow, norwegian, cats, water, dunhill)
h(blue, dane, horse, tea, blend)
h(red, englishman, birds, milk, pallmall)
h(green, german, zebra, coffee, prince)
h(white, swede, dog, beer, bluemaster)
 
german
 
No more solutions.
% 5,959 inferences, 0.000 CPU in 0.060 seconds (0% CPU, Infinite Lips)
true.
</pre>
 
Works [http://ideone.com/Es8DV with SWI-Prolog]. More verbose [http://ideone.com/6PzbZ line-for-line translation] of the specification works as well.
 
===Direct rule by rule translation===
 
Using extensible records, letting the houses' attributes be discovered from rules, ''not'' predetermined by a programmer (as any ''"a house has five attributes"'' solution is doing).
 
<syntaxhighlight lang="prolog">% attribute store is 'Name - Value' pairs with unique names
attrs( H, [N-V | R]) :- !, memberchk( N-X, H), X = V, (R = [], ! ; attrs( H, R)).
attrs( HS, AttrsL) :- maplist( attrs, HS, AttrsL).
 
in( HS, Attrs) :- in( member, HS, Attrs).
in( G, HS, Attrs) :- call( G, A, HS), attrs( A, Attrs).
 
left_of( [A,B], HS) :- append( _, [A,B | _], HS).
next_to( [A,B], HS) :- left_of( [A,B], HS) ; left_of( [B,A], HS).
zebra( Owner, Houses):-
Houses = [A,_,C,_,_], % 1
maplist( in(Houses), [ [ nation-englishman, color-red ] % 2
, [ nation-swede, owns -dog ] % 3
, [ nation-dane, drink-tea ] % 4
, [ drink -coffee, color-green ] % 6
, [ smoke -'Pall Mall', owns -birds ] % 7
, [ color -yellow, smoke-'Dunhill' ] % 8
, [ drink -beer, smoke-'Blue Master'] % 13
, [ nation-german, smoke-'Prince' ] % 14
] ),
in( left_of, Houses, [[color -green ], [color -white ]]), % 5
in( left_of, [C,A], [[drink -milk ], [nation-norwegian]]), % 9, 10
maplist( in( next_to, Houses),
[ [[smoke -'Blend' ], [owns -cats ]] % 11
, [[owns -horse ], [smoke-'Dunhill' ]] % 12
, [[nation-norwegian], [color-blue ]] % 15
, [[drink -water ], [smoke-'Blend' ]] % 16
] ),
in( Houses, [owns-zebra, nation-Owner]).</syntaxhighlight>
[http://ideone.com/wcwXfZ Output]:
<syntaxhighlight lang="prolog">?- time(( zebra(Z,HS), (maplist(length,HS,_) -> maplist(sort,HS,S),
maplist(writeln,S),nl,writeln(Z)), false ; writeln('No More Solutions'))).
[color-yellow,drink-water, nation-norwegian, owns-cats, smoke-Dunhill ]
[color-blue, drink-tea, nation-dane, owns-horse, smoke-Blend ]
[color-red, drink-milk, nation-englishman,owns-birds, smoke-Pall Mall ]
[color-green, drink-coffee,nation-german, owns-zebra, smoke-Prince ]
[color-white, drink-beer, nation-swede, owns-dog, smoke-Blue Master]
german
No More Solutions
% 263,486 inferences, 0.047 CPU in 0.063 seconds (74% CPU, 5630007 Lips)</syntaxhighlight>
 
===Alternative version===
{{Works with|GNU Prolog}}
{{Works with|SWI Prolog}}
<syntaxhighlight lang="prolog">:- initialization(main).
 
 
zebra(X) :-
houses(Hs), member(h(_,X,zebra,_,_), Hs)
, findall(_, (member(H,Hs), write(H), nl), _), nl
, write('the one who keeps zebra: '), write(X), nl
.
 
 
houses(Hs) :-
Hs = [_,_,_,_,_] % 1
, H3 = h(_,_,_,milk,_), Hs = [_,_,H3,_,_] % 9
, H1 = h(_,nvg,_,_,_ ), Hs = [H1|_] % 10
 
, maplist( flip(member,Hs),
[ h(red,eng,_,_,_) % 2
, h(_,swe,dog,_,_) % 3
, h(_,dan,_,tea,_) % 4
, h(green,_,_,coffe,_) % 6
, h(_,_,birds,_,pm) % 7
, h(yellow,_,_,_,dh) % 8
, h(_,_,_,beer,bm) % 13
, h(_,ger,_,_,pri) % 14
])
 
, infix([ h(green,_,_,_,_)
, h(white,_,_,_,_) ], Hs) % 5
 
, maplist( flip(nextto,Hs),
[ [h(_,_,_,_,bl ), h(_,_,cats,_,_)] % 11
, [h(_,_,horse,_,_), h(_,_,_,_,dh )] % 12
, [h(_,nvg,_,_,_ ), h(blue,_,_,_,_)] % 15
, [h(_,_,_,water,_), h(_,_,_,_,bl )] % 16
])
.
 
 
flip(F,X,Y) :- call(F,Y,X).
 
infix(Xs,Ys) :- append(Xs,_,Zs) , append(_,Zs,Ys).
nextto(P,Xs) :- permutation(P,R), infix(R,Xs).
 
 
main :- findall(_, (zebra(_), nl), _), halt.
</syntaxhighlight>
{{Output}}
<pre>h(yellow,nvg,cats,water,dh)
h(blue,dan,horse,tea,bl)
h(red,eng,birds,milk,pm)
h(green,ger,zebra,coffe,pri)
h(white,swe,dog,beer,bm)
 
the one who keeps zebra: ger
</pre>
 
===Constraint Programming version===
{{Works with|SWI Prolog}}
Original source code is 'ECLiPSe ( http://eclipseclp.org/ )' example: http://eclipseclp.org/examples/zebra.ecl.txt
<syntaxhighlight lang="prolog">:- use_module(library(clpfd)).
 
zebra :-
Nation = [Englishman, Spaniard, Japanese, Ukrainian, Norwegian ],
Color = [Red, Green, White, Yellow, Blue ],
Smoke = [Oldgold, Kools, Chesterfield, Luckystrike, Parliament],
Pet = [Dog, Snails, Fox, Horse, Zebra ],
Drink = [Tea, Coffee, Milk, Orangejuice, Water ],
 
% house numbers 1 to 5
Nation ins 1..5,
Color ins 1..5,
Smoke ins 1..5,
Pet ins 1..5,
Drink ins 1..5,
% the values in each list are exclusive
all_different(Nation),
all_different(Color),
all_different(Smoke),
all_different(Pet),
all_different(Drink),
% actual constraints
Englishman #= Red,
Spaniard #= Dog,
Green #= Coffee,
Ukrainian #= Tea,
Green #= White + 1,
Oldgold #= Snails,
Yellow #= Kools,
Milk #= 3,
Norwegian #= 1,
(Chesterfield #= Fox - 1 #\/ Chesterfield #= Fox + 1),
(Kools #= Horse - 1 #\/ Kools #= Horse + 1),
Luckystrike #= Orangejuice,
Japanese #= Parliament,
(Norwegian #= Blue - 1 #\/ Norwegian #= Blue + 1),
 
% get solution
flatten([Nation, Color, Smoke, Pet, Drink], List), label(List),
% print the answers
sort([Englishman-englishman, Spaniard-spaniard, Japanese-japanese, Ukrainian-ukrainian, Norwegian-norwegian], NationNames),
sort([Red-red, Green-green, White-white, Yellow-yellow, Blue-blue], ColorNames),
sort([Oldgold-oldgold, Kools-kools, Chesterfield-chesterfield, Luckystrike-luckystrike, Parliament-parliament], SmokeNames),
sort([Dog-dog, Snails-snails, Fox-fox, Horse-horse, Zebra-zebra], PetNames),
sort([Tea-tea, Coffee-coffee, Milk-milk, Orangejuice-orangejuice, Water-water], DrinkNames),
Fmt = '~w~16|~w~32|~w~48|~w~64|~w~n',
format(Fmt, NationNames),
format(Fmt, ColorNames),
format(Fmt, SmokeNames),
format(Fmt, PetNames),
format(Fmt, DrinkNames).
</syntaxhighlight>
{{Output}}
<pre>
1-norwegian 2-ukrainian 3-englishman 4-spaniard 5-japanese
1-yellow 2-blue 3-red 4-white 5-green
1-kools 2-chesterfield 3-oldgold 4-luckystrike 5-parliament
1-fox 2-horse 3-snails 4-dog 5-zebra
1-water 2-tea 3-milk 4-orangejuice 5-coffee
</pre>
 
=={{header|Python}}==
{{trans|Clojure}}
Using 'logpy': https://github.com/logpy/logpy
<syntaxhighlight lang="python">
from logpy import *
from logpy.core import lall
import time
 
def lefto(q, p, list):
# give me q such that q is left of p in list
# zip(list, list[1:]) gives a list of 2-tuples of neighboring combinations
# which can then be pattern-matched against the query
return membero((q,p), zip(list, list[1:]))
 
def nexto(q, p, list):
# give me q such that q is next to p in list
# match lefto(q, p) OR lefto(p, q)
# requirement of vector args instead of tuples doesn't seem to be documented
return conde([lefto(q, p, list)], [lefto(p, q, list)])
 
houses = var()
 
zebraRules = lall(
# there are 5 houses
(eq, (var(), var(), var(), var(), var()), houses),
# the Englishman's house is red
(membero, ('Englishman', var(), var(), var(), 'red'), houses),
# the Swede has a dog
(membero, ('Swede', var(), var(), 'dog', var()), houses),
# the Dane drinks tea
(membero, ('Dane', var(), 'tea', var(), var()), houses),
# the Green house is left of the White house
(lefto, (var(), var(), var(), var(), 'green'),
(var(), var(), var(), var(), 'white'), houses),
# coffee is the drink of the green house
(membero, (var(), var(), 'coffee', var(), 'green'), houses),
# the Pall Mall smoker has birds
(membero, (var(), 'Pall Mall', var(), 'birds', var()), houses),
# the yellow house smokes Dunhills
(membero, (var(), 'Dunhill', var(), var(), 'yellow'), houses),
# the middle house drinks milk
(eq, (var(), var(), (var(), var(), 'milk', var(), var()), var(), var()), houses),
# the Norwegian is the first house
(eq, (('Norwegian', var(), var(), var(), var()), var(), var(), var(), var()), houses),
# the Blend smoker is in the house next to the house with cats
(nexto, (var(), 'Blend', var(), var(), var()),
(var(), var(), var(), 'cats', var()), houses),
# the Dunhill smoker is next to the house where they have a horse
(nexto, (var(), 'Dunhill', var(), var(), var()),
(var(), var(), var(), 'horse', var()), houses),
# the Blue Master smoker drinks beer
(membero, (var(), 'Blue Master', 'beer', var(), var()), houses),
# the German smokes Prince
(membero, ('German', 'Prince', var(), var(), var()), houses),
# the Norwegian is next to the blue house
(nexto, ('Norwegian', var(), var(), var(), var()),
(var(), var(), var(), var(), 'blue'), houses),
# the house next to the Blend smoker drinks water
(nexto, (var(), 'Blend', var(), var(), var()),
(var(), var(), 'water', var(), var()), houses),
# one of the houses has a zebra--but whose?
(membero, (var(), var(), var(), 'zebra', var()), houses)
)
 
t0 = time.time()
solutions = run(0, houses, zebraRules)
t1 = time.time()
dur = t1-t0
 
count = len(solutions)
zebraOwner = [house for house in solutions[0] if 'zebra' in house][0][0]
 
print "%i solutions in %.2f seconds" % (count, dur)
print "The %s is the owner of the zebra" % zebraOwner
print "Here are all the houses:"
for line in solutions[0]:
print str(line)
</syntaxhighlight>
 
===Alternative Version===
{{trans|D}}
<langsyntaxhighlight lang="python">import psyco; psyco.full()
 
class Content: elems= """Beer Coffee Milk Tea Water
Line 1,067 ⟶ 5,919:
solve(M, Test.Drink, 5)
 
main()</langsyntaxhighlight>
{{out}}
<pre> One: Water Norwegian Yellow Dunhill Cat
Line 1,076 ⟶ 5,928:
Runtime about 0.18 seconds.
===Alternative Version===
<langsyntaxhighlight lang="python">from itertools import permutations
import psyco
psyco.full()
 
class Number:elems= "One Two Three Four Five".split()
Line 1,090 ⟶ 5,940:
for i, e in enumerate(c.elems):
exec "%s.%s = %d" % (c.__name__, e, i)
 
def is_possible(number, color, drink, smoke, pet):
if number and number[Nation.Norvegian] != Number.One:
return False
if color and color[Nation.British] != Color.Red:
return False
if drink and drink[Nation.Danish] != Drink.Tea:
return False
if smoke and smoke[Nation.German] != Smoke.Prince:
return False
if pet and pet[Nation.Swedish] != Pet.Dog:
return False
 
if not number or not color or not drink or not smoke or not pet:
return True
 
for i in xrange(5):
if color[i] == Color.Green and drink[i] != Drink.Coffee:
return False
if smoke[i] == Smoke.PallMall and pet[i] != Pet.Bird:
return False
if color[i] == Color.Yellow and smoke[i] != Smoke.Dunhill:
return False
if number[i] == Number.Three and drink[i] != Drink.Milk:
return False
if smoke[i] == Smoke.BlueMaster and drink[i] != Drink.Beer:
return False
if color[i] == Color.Blue and number[i] != Number.Two:
return False
 
for j in xrange(5):
if (color[i] == Color.Green and
color[j] == Color.White and
number[j] - number[i] != 1):
return False
 
diff = abs(number[i] - number[j])
if smoke[i] == Smoke.Blend and pet[j] == Pet.Cat and diff != 1:
return False
if pet[i]==Pet.Horse and smoke[j]==Smoke.Dunhill and diff != 1:
return False
if smoke[i]==Smoke.Blend and drink[j]==Drink.Water and diff!=1:
return False
 
return True
 
def show_row(t, data):
Line 1,144 ⟶ 5,949:
def main():
perms = list(permutations(range(5)))
 
for number in perms:
if is_possible(number,[Nation.Norvegian] None,== None,Number.One: None,# None):Constraint 10
for color in perms:
if is_possible(number, color,[Nation.British] None,== None, None)Color.Red: # Constraint 2
if number[color.index(Color.Blue)] == Number.Two: # Constraint 15+10
for drink in perms:
if is_possible(number, [color,.index(Color.White)] drink,- None, Nonenumber[color.index(Color.Green)] == 1: # Constraint 5
for smokedrink in perms:
if is_possible(number, color, drink,[Nation.Danish] smoke,== None)Drink.Tea: # Constraint 4
forif petdrink[color.index(Color.Green)] in== permsDrink.Coffee: # Constraint 6
if is_possible(drink[number,.index(Number.Three)] color,== drink,Drink.Milk: smoke,# pet):Constraint 9
printfor "Foundsmoke ain solutionperms:"
show_row( if smoke[Nation,.German] == Smoke.Prince: # Constraint range(5))14
show_row(Number, number if drink[smoke.index(Smoke.BlueMaster)] == Drink.Beer: # Constraint 13
show_row(Color, if smoke[color.index(Color.Yellow)] == Smoke.Dunhill: # Constraint 8
show_row if number[smoke.index(Smoke.Blend)] - number[drink.index(Drink.Water)] in (1, drink-1): # Constraint 16
show_row(Smoke, smoke) for pet in perms:
show_row(Pet, if pet)[Nation.Swedish] == Pet.Dog: # Constraint 3
print if pet[smoke.index(Smoke.PallMall)] == Pet.Bird: # Constraint 7
if number[pet.index(Pet.Horse)] - number[smoke.index(Smoke.Dunhill)] in (1, -1): # Constraint 12
if number[smoke.index(Smoke.Blend)] - number[pet.index(Pet.Cat)] in (1, -1): # Constraint 11
print "Found a solution:"
show_row(Nation, range(5))
show_row(Number, number)
show_row(Color, color)
show_row(Drink, drink)
show_row(Smoke, smoke)
show_row(Pet, pet)
print
 
main()</langsyntaxhighlight>
Output:
<pre>Found a solution:
Line 1,173 ⟶ 5,987:
Smoke: PallMall BlueMaster Blend Dunhill Prince
Pet: Bird Dog Horse Cat Zebra</pre>
Runtime about 0.0013 seconds
===Constraint Programming Version===
Using 'python-constraint': http://labix.org/python-constraint,
Original source code is 'ECLiPSe ( http://eclipseclp.org/ )' example: http://eclipseclp.org/examples/zebra.ecl.txt
<syntaxhighlight lang="python">'''
Improved version: Instead of simple variables (a, b),
more intelligible and readable (?) variables are employed.
'''
def doc1():
'''
There are five houses.
The English man lives in the red house.
The Swede has a dog.
The Dane drinks tea.
The green house is immediately to the left of the white house.
They drink coffee in the green house.
The man who smokes Pall Mall has a bird.
In the yellow house they smoke Dunhill.
In the middle house they drink milk.
The Norwegian lives in the first house.
The man who smokes Blend lives in the house next to the house with a cat.
In a house next to the house where they have a horse, they smoke Dunhill.
The man who smokes Blue Master drinks beer.
The German smokes Prince.
The Norwegian lives next to the blue house.
They drink water in a house next to the house where they smoke Blend.
 
The solution:
 
Nation: Norwegian Dane Englishman German Swede
Color: Yellow Blue Red Green White
Smoke: Dunhill Blend PallMall Prince BlueMaster
Pet: Cat Horse Bird Zebra Dog
Drink: Water Tea Milk Coffee Beer
'''
 
import os
print(os.system('cls') if os.name == 'nt' else os.system('clear'))
 
print(doc1.__doc__)
input('<key>')
 
from constraint import *
 
p = Problem()
 
Nation = ['Englishman', 'Dane', 'German', 'Norwegian', 'Swede']
Color = [ 'Blue', 'Green', 'Red', 'White', 'Yellow']
Smoke = [ 'Blend', 'BlueMaster', 'Dunhill', 'PallMall', 'Prince']
Pet = [ 'Bird', 'Cat', 'Dog', 'Horse', 'Zebra']
Drink = [ 'Beer', 'Coffee', 'Milk', 'Tea', 'Water']
 
# add variables: house numbers 1 to 5
p.addVariables(Nation, range(1,6))
p.addVariables(Color, range(1,6))
p.addVariables(Smoke, range(1,6))
p.addVariables(Pet, range(1,6))
p.addVariables(Drink, range(1,6))
 
# add constraint: the values in each list are exclusive
p.addConstraint(AllDifferentConstraint(), Nation)
p.addConstraint(AllDifferentConstraint(), Color)
p.addConstraint(AllDifferentConstraint(), Smoke)
p.addConstraint(AllDifferentConstraint(), Pet)
p.addConstraint(AllDifferentConstraint(), Drink)
 
# add constraint: actual constraints
# The English man lives in the red house.
p.addConstraint(
lambda house_englishman, red:
house_englishman is red,
['Englishman', 'Red'])
 
# The Swede has a dog.
p.addConstraint(
lambda pet_swede, dog:
pet_swede is dog,
['Swede', 'Dog'])
 
# The Dane drinks tea.
p.addConstraint(
lambda drink_dane, tea:
drink_dane is tea,
['Dane', 'Tea'])
 
# The green house is immediately to the left of the white house.
p.addConstraint(
lambda green_house, white_house:
# Houses 1 .. 5 -> green house is 1 lower than white house
green_house is white_house - 1,
['Green', 'White'])
 
# They drink coffee in the green house.
p.addConstraint(
lambda drink_green_house, coffee:
drink_green_house is coffee,
['Green', 'Coffee'])
 
# The man who smokes Pall Mall has a bird.
p.addConstraint(
lambda pet_of_pallmall_smoker, a_bird:
pet_of_pallmall_smoker is a_bird,
['PallMall', 'Bird'])
 
# In the yellow house they smoke Dunhill.
p.addConstraint(
lambda owner_yellow_house, dunhill_smoker:
owner_yellow_house is dunhill_smoker,
['Yellow', 'Dunhill'])
 
# In the middle house they drink milk.
p.addConstraint(
lambda house_number_milk_drinker:
house_number_milk_drinker is 3,
['Milk'])
 
# The Norwegian lives in the first house.
p.addConstraint(
lambda house_number_norwegian:
house_number_norwegian is 1,
['Norwegian'])
 
# The man who smokes Blend lives in the house next to the house with a cat.
p.addConstraint(
lambda house_number_blend_smoker, number_of_house_with_cat:
# next -> housenumber +/- 1
house_number_blend_smoker is number_of_house_with_cat + 1 or
house_number_blend_smoker is number_of_house_with_cat - 1,
['Blend', 'Cat'])
 
# In a house next to the house where they have a horse, they smoke Dunhill.
p.addConstraint(
lambda house_number_dunhill_smoker, number_of_house_with_horse:
# next -> housenumber +/- 1
house_number_dunhill_smoker is number_of_house_with_horse + 1 or
house_number_dunhill_smoker is number_of_house_with_horse - 1,
['Dunhill', 'Horse'])
 
# The man who smokes Blue Master drinks beer.
p.addConstraint(
lambda drink_bluemaster_smoker, beer:
drink_bluemaster_smoker is beer,
['BlueMaster', 'Beer'])
 
# The German smokes Prince.
p.addConstraint(
lambda prince_smoker, german:
prince_smoker is german,
['Prince', 'German'])
 
# The Norwegian lives next to the blue house.
p.addConstraint(
lambda house_number_norwegian, house_number_blue_house:
house_number_norwegian is house_number_blue_house + 1 or
house_number_norwegian is house_number_blue_house - 1,
['Norwegian', 'Blue'])
 
# They drink water in a house next to the house where they smoke Blend.
p.addConstraint(
lambda house_number_water_drinker, house_number_blend_smoker:
house_number_water_drinker is house_number_blend_smoker + 1 or
house_number_water_drinker is house_number_blend_smoker - 1,
['Water', 'Blend'])
 
# get solution
sol = p.getSolution()
 
# print the answers
nation = ['Nation' if i == 0 else '' for i in range(6)]
color = ['Color' if i == 0 else '' for i in range(6)]
smoke = ['Smoke' if i == 0 else '' for i in range(6)]
pet = ['Pet' if i == 0 else '' for i in range(6)]
drink = ['Drink' if i == 0 else '' for i in range(6)]
 
for n in Nation: nation[sol[n]] = n
for n in Color: color[sol[n]] = n
for n in Smoke: smoke[sol[n]] = n
for n in Pet: pet[sol[n]] = n
for n in Drink: drink[sol[n]] = n
 
# put the answers in the correct order of solution
print('\n\n', 'The calculated solution:', '\n')
 
for r in [nation, color, smoke, pet, drink]:
print(f'{r[0]:>13s}: ', end='')
for i in range(1, 6):
print(f'{r[i]:>14s}',end='')
print()
print()
</syntaxhighlight>
Output:
<pre> Nation: Norwegian Dane Englishman German Swede
Color: Yellow Blue Red Green White
Smoke: Dunhill Blend PallMall Prince BlueMaster
Pet: Cat Horse Bird Zebra Dog
Drink: Water Tea Milk Coffee Beer
</pre>
 
=={{header|R}}==
{{libheader|combinat}}<syntaxhighlight lang="r">
 
library(combinat)
 
col <- factor(c("Red","Green","White","Yellow","Blue"))
own <- factor(c("English","Swedish","Danish","German","Norwegian"))
pet <- factor(c("Dog","Birds","Cats","Horse","Zebra"))
drink <- factor(c("Coffee","Tea","Milk","Beer","Water"))
smoke <- factor(c("PallMall", "Blend", "Dunhill", "BlueMaster", "Prince"))
 
col_p <- permn(levels(col))
own_p <- permn(levels(own))
pet_p <- permn(levels(pet))
drink_p <- permn(levels(drink))
smoke_p <- permn(levels(smoke))
 
imright <- function(h1,h2){
return(h1-h2==1)
}
 
nextto <- function(h1,h2){
return(abs(h1-h2)==1)
}
 
house_with <- function(f,val){
return(which(levels(f)==val))
}
 
for (i in seq(length(col_p))){
col <- factor(col, levels=col_p[[i]])
if (imright(house_with(col,"Green"),house_with(col,"White"))) {
for (j in seq(length(own_p))){
own <- factor(own, levels=own_p[[j]])
if(house_with(own,"English") == house_with(col,"Red")){
if(house_with(own,"Norwegian") == 1){
if(nextto(house_with(own,"Norwegian"),house_with(col,"Blue"))){
for(k in seq(length(drink_p))){
drink <- factor(drink, levels=drink_p[[k]])
if(house_with(drink,"Coffee") == house_with(col,"Green")){
if(house_with(own,"Danish") == house_with(drink,"Tea")){
if(house_with(drink,"Milk") == 3){
for(l in seq(length(smoke_p))){
smoke <- factor(smoke, levels=smoke_p[[l]])
if(house_with(smoke,"Dunhill") == house_with(col,"Yellow")){
if(house_with(smoke,"BlueMaster") == house_with(drink,"Beer")){
if(house_with(own,"German") == house_with(smoke,"Prince")){
if(nextto(house_with(smoke,"Blend"),house_with(drink,"Water"))){
for(m in seq(length(pet_p))){
pet <- factor(pet, levels=pet_p[[m]])
if(house_with(own,"Swedish") == house_with(pet,"Dog")){
if(house_with(smoke,"PallMall") == house_with(pet,"Birds")){
if(nextto(house_with(smoke,"Blend"),house_with(pet,"Cats"))){
if(nextto(house_with(smoke,"Dunhill"),house_with(pet,"Horse"))){
res <- sapply(list(own,col,pet,smoke,drink),levels)
colnames(res) <- c("Nationality","Colour","Pet","Drink","Smoke")
print(res)
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}</syntaxhighlight>
{{out}}
<pre>
Nationality Colour Pet Drink Smoke
[1,] "Norwegian" "Yellow" "Cats" "Dunhill" "Water"
[2,] "Danish" "Blue" "Horse" "Blend" "Tea"
[3,] "English" "Red" "Birds" "PallMall" "Milk"
[4,] "Swedish" "White" "Dog" "BlueMaster" "Beer"
[5,] "German" "Green" "Zebra" "Prince" "Coffee"
</pre>
 
=={{header|Racket}}==
 
{{trans|Prolog}}
 
<syntaxhighlight lang="racket">#lang racket
 
(require racklog)
 
(define %select
(%rel (x xs S S1)
[(x (cons x xs) xs)]
[(x (cons S xs) (cons S S1)) (%select x xs S1)]
[((cons x xs) S)
(%select x S S1)
(%select xs S1)]
[('() (_))]))
 
(define %next-to
(%rel (A B C)
[(A B C)
(%or (%left-of A B C)
(%left-of B A C))]))
 
(define %left-of
(%rel (A B C)
[(A B C) (%append (_) (cons A (cons B (_))) C)]))
 
(define %zebra
(%rel (Owns HS)
[(Owns HS)
(%is HS (list (list (_) 'norwegian (_) (_) (_))
(_)
(list (_) (_) (_) 'milk (_))
(_) (_)))
(%select (list (list 'red 'englishman (_) (_) (_))
(list (_) 'swede 'dog (_) (_))
(list (_) 'dane (_) 'tea (_))
(list (_) 'german (_) (_) 'prince))
HS)
(%select (list (list (_) (_) 'birds (_) 'pallmall)
(list 'yellow (_) (_) (_) 'dunhill)
(list (_) (_) (_) 'beer 'bluemaster))
HS)
(%left-of (list 'green (_) (_) 'coffee (_))
(list 'white (_) (_) (_) (_))
HS)
(%next-to (list (_) (_) (_) (_) 'dunhill)
(list (_) (_) 'horse (_) (_))
HS)
(%next-to (list (_) (_) (_) (_) 'blend)
(list (_) (_) 'cats (_) (_))
HS)
(%next-to (list (_) (_) (_) (_) 'blend)
(list (_) (_) (_) 'water (_))
HS)
(%next-to (list (_) 'norwegian (_) (_) (_))
(list 'blue (_) (_) (_) (_))
HS)
(%member (list (_) Owns 'zebra (_) (_)) HS)]))
 
(%which (Who HS) (%zebra Who HS))</syntaxhighlight>
 
Output:
<pre>
'((Who . german)
(HS
(yellow norwegian cats water dunhill)
(blue dane horse tea blend)
(red englishman birds milk pallmall)
(green german zebra coffee prince)
(white swede dog beer bluemaster)))
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
A rule driven approach:
<syntaxhighlight lang="raku" line>my Hash @houses = (1 .. 5).map: { %(:num($_)) }; # 1 there are five houses
 
my @facts = (
{ :nat<English>, :color<red> }, # 2 The English man lives in the red house.
{ :nat<Swede>, :pet<dog> }, # 3 The Swede has a dog.
{ :nat<Dane>, :drink<tea> }, # 4 The Dane drinks tea.
{ :color<green>, :Left-Of(:color<white>) }, # 5 the green house is immediately to the left of the white house
{ :drink<coffee>, :color<green> }, # 6 They drink coffee in the green house.
{ :smoke<Pall-Mall>, :pet<birds> }, # 7 The man who smokes Pall Mall has birds.
{ :color<yellow>, :smoke<Dunhill> }, # 8 In the yellow house they smoke Dunhill.
{ :num(3), :drink<milk> }, # 9 In the middle house they drink milk.
{ :num(1), :nat<Norwegian> }, # 10 The Norwegian lives in the first house.
{ :smoke<Blend>, :Next-To(:pet<cats>) }, # 11 The man who smokes Blend lives in the house next to the house with cats.
{ :pet<horse>, :Next-To(:smoke<Dunhill>) }, # 12 In a house next to the house where they have a horse, they smoke Dunhill.
{ :smoke<Blue-Master>, :drink<beer> }, # 13 The man who smokes Blue Master drinks beer.
{ :nat<German>, :smoke<Prince> }, # 14 The German smokes Prince.
{ :nat<Norwegian>, :Next-To(:color<blue>) }, # 15 The Norwegian lives next to the blue house.
{ :drink<water>, :Next-To(:smoke<Blend>) }, # 16 They drink water in a house next to the house where they smoke Blend.
{ :pet<zebra> }, # who owns this?
);
 
sub MAIN {
for gather solve(@houses, @facts) {
#-- output
say .head.sort.map(*.key.uc.fmt("%-9s")).join(' | ');
say .sort.map(*.value.fmt("%-9s")).join(' | ')
for .list;
last; # stop after first solution
}
}
 
#| a solution has been found that fits all the facts
multi sub solve(@solution, @facts [ ]) {
take @solution;
}
 
#| extend this scenario to fit the next fact
multi sub solve(@scenario, [ $fact, *@facts ]) {
for gather match(@scenario, |$fact) -> @houses {
solve(@houses, @facts)
}
}
 
#| find all possible solutions for pairs of houses with
#| properties %b, left of a house with properties %a
multi sub match(@houses, :Left-Of(%a)!, *%b) {
for 1 ..^ @houses {
my %left-house := @houses[$_-1];
my %right-house := @houses[$_];
if plausible(%left-house, %a) && plausible(%right-house, %b) {
temp %left-house ,= %a;
temp %right-house ,= %b;
take @houses;
}
}
}
 
#| match these houses are next to each other (left or right)
multi sub match(@houses, :Next-To(%b)!, *%a ) {
match(@houses, |%a, :Left-Of(%b) );
match(@houses, |%b, :Left-Of(%a) );
}
 
#| find all possible houses that match the given properties
multi sub match(@houses, *%props) {
for @houses.grep({plausible($_, %props)}) -> %house {
temp %house ,= %props;
take @houses;
}
}
 
#| plausible if doesn't conflict with anything
sub plausible(%house, %props) {
! %props.first: {%house{.key} && %house{.key} ne .value };
}
</syntaxhighlight>
{{out}}
<pre>
COLOR | DRINK | NAT | NUM | PET | SMOKE
yellow | water | Norwegian | 1 | cats | Dunhill
blue | tea | Dane | 2 | horse | Blend
red | milk | English | 3 | birds | Pall-Mall
green | coffee | German | 4 | zebra | Prince
white | beer | Swede | 5 | dog | Blue-Master
</pre>
 
Note: Facts can be shuffled by changing line 3 to <code>my @facts = pick *, (</code>. It seems to reliably find solutions, although execution times will vary (from under 1 sec up to about 10sec).
 
=={{header|REXX}}==
{{trans|BBC BASIC}}
Permutations algorithm taken from REXX
<syntaxhighlight lang="rexx">/* REXX ---------------------------------------------------------------
* Solve the Zebra Puzzle
*--------------------------------------------------------------------*/
Call mk_perm /* compute all permutations */
Call encode /* encode the elements of the specifications */
/* ex2 .. eg16 the formalized specifications */
solutions=0
Call time 'R'
Do nation_i = 1 TO 120
Nations = perm.nation_i
IF ex10() Then Do
Do color_i = 1 TO 120
Colors = perm.color_i
IF ex5() & ex2() & ex15() Then Do
Do drink_i = 1 TO 120
Drinks = perm.drink_i
IF ex9() & ex4() & ex6() Then Do
Do smoke_i = 1 TO 120
Smokes = perm.smoke_i
IF ex14() & ex13() & ex16() & ex8() Then Do
Do animal_i = 1 TO 120
Animals = perm.animal_i
IF ex3() & ex7() & ex11() & ex12() Then Do
/* Call out 'Drinks =' Drinks 54321 Wat Tea Mil Cof Bee */
/* Call out 'Nations=' Nations 41235 Nor Den Eng Ger Swe */
/* Call out 'Colors =' Colors 51324 Yel Blu Red Gre Whi */
/* Call out 'Smokes =' Smokes 31452 Dun Ble Pal Pri Blu */
/* Call out 'Animals=' Animals 24153 Cat Hor Bir Zeb Dog */
Call out 'House Drink Nation Colour'||,
' Smoke Animal'
Do i=1 To 5
di=substr(drinks,i,1)
ni=substr(nations,i,1)
ci=substr(colors,i,1)
si=substr(smokes,i,1)
ai=substr(animals,i,1)
ol.i=right(i,3)' '||left(drink.di,11),
||left(nation.ni,11),
||left(color.ci,11),
||left(smoke.si,11),
||left(animal.ai,11)
Call out ol.i
End
solutions=solutions+1
End
End /* animal_i */
End
End /* smoke_i */
End
End /* drink_i */
End
End /* color_i */
End
End /* nation_i */
Say 'Number of solutions =' solutions
Say 'Solved in' time('E') 'seconds'
Exit
 
/*------------------------------------------------------------------------------
#There are five houses.
ex2: #The English man lives in the red house.
ex3: #The Swede has a dog.
ex4: #The Dane drinks tea.
ex5: #The green house is immediately to the left of the white house.
ex6: #They drink coffee in the green house.
ex7: #The man who smokes Pall Mall has birds.
ex8: #In the yellow house they smoke Dunhill.
ex9: #In the middle house they drink milk.
ex10: #The Norwegian lives in the first house.
ex11: #The man who smokes Blend lives in the house next to the house with cats.
ex12: #In a house next to the house where they have a horse, they smoke Dunhill.
ex13: #The man who smokes Blue Master drinks beer.
ex14: #The German smokes Prince.
ex15: #The Norwegian lives next to the blue house.
ex16: #They drink water in a house next to the house where they smoke Blend.
------------------------------------------------------------------------------*/
ex2: Return pos(England,Nations)=pos(Red,Colors)
ex3: Return pos(Sweden,Nations)=pos(Dog,Animals)
ex4: Return pos(Denmark,Nations)=pos(Tea,Drinks)
ex5: Return pos(Green,Colors)=pos(White,Colors)-1
ex6: Return pos(Coffee,Drinks)=pos(Green,Colors)
ex7: Return pos(PallMall,Smokes)=pos(Birds,Animals)
ex8: Return pos(Dunhill,Smokes)=pos(Yellow,Colors)
ex9: Return substr(Drinks,3,1)=Milk
ex10: Return left(Nations,1)=Norway
ex11: Return abs(pos(Blend,Smokes)-pos(Cats,Animals))=1
ex12: Return abs(pos(Dunhill,Smokes)-pos(Horse,Animals))=1
ex13: Return pos(BlueMaster,Smokes)=pos(Beer,Drinks)
ex14: Return pos(Germany,Nations)=pos(Prince,Smokes)
ex15: Return abs(pos(Norway,Nations)-pos(Blue,Colors))=1
ex16: Return abs(pos(Blend,Smokes)-pos(Water,Drinks))=1
 
mk_perm: Procedure Expose perm.
/*---------------------------------------------------------------------
* Make all permutations of 12345 in perm.*
*--------------------------------------------------------------------*/
perm.=0
n=5
Do pop=1 For n
p.pop=pop
End
Call store
Do While nextperm(n,0)
Call store
End
Return
 
nextperm: Procedure Expose p. perm.
Parse Arg n,i
nm=n-1
Do k=nm By-1 For nm
kp=k+1
If p.k<p.kp Then Do
i=k
Leave
End
End
Do j=i+1 While j<n
Parse Value p.j p.n With p.n p.j
n=n-1
End
If i>0 Then Do
Do j=i+1 While p.j<p.i
End
Parse Value p.j p.i With p.i p.j
End
Return i>0
 
store: Procedure Expose p. perm.
z=perm.0+1
_=''
Do j=1 To 5
_=_||p.j
End
perm.z=_
perm.0=z
Return
 
encode:
Beer=1 ; Drink.1='Beer'
Coffee=2 ; Drink.2='Coffee'
Milk=3 ; Drink.3='Milk'
Tea=4 ; Drink.4='Tea'
Water=5 ; Drink.5='Water'
Denmark=1 ; Nation.1='Denmark'
England=2 ; Nation.2='England'
Germany=3 ; Nation.3='Germany'
Norway=4 ; Nation.4='Norway'
Sweden=5 ; Nation.5='Sweden'
Blue=1 ; Color.1='Blue'
Green=2 ; Color.2='Green'
Red=3 ; Color.3='Red'
White=4 ; Color.4='White'
Yellow=5 ; Color.5='Yellow'
Blend=1 ; Smoke.1='Blend'
BlueMaster=2 ; Smoke.2='BlueMaster'
Dunhill=3 ; Smoke.3='Dunhill'
PallMall=4 ; Smoke.4='PallMall'
Prince=5 ; Smoke.5='Prince'
Birds=1 ; Animal.1='Birds'
Cats=2 ; Animal.2='Cats'
Dog=3 ; Animal.3='Dog'
Horse=4 ; Animal.4='Horse'
Zebra=5 ; Animal.5='Zebra'
Return
 
out:
Say arg(1)
Return</syntaxhighlight>
{{out}}
<pre>House Drink Nation Colour Smoke Animal
1 Water Norway Yellow Dunhill Cats
2 Tea Denmark Blue Blend Horse
3 Milk England Red PallMall Birds
4 Coffee Germany Green Prince Zebra
5 Beer Sweden White BlueMaster Dog
Number of solutions = 1
Solved in 0.063000 seconds</pre>
 
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">CONTENT = { House: '',
Nationality: %i[English Swedish Danish Norwegian German],
Colour: %i[Red Green White Blue Yellow],
Pet: %i[Dog Birds Cats Horse Zebra],
Drink: %i[Tea Coffee Milk Beer Water],
Smoke: %i[PallMall Dunhill BlueMaster Prince Blend] }
 
def adjacent? (n,i,g,e)
(0..3).any?{|x| (n[x]==i and g[x+1]==e) or (n[x+1]==i and g[x]==e)}
end
 
def leftof? (n,i,g,e)
(0..3).any?{|x| n[x]==i and g[x+1]==e}
end
 
def coincident? (n,i,g,e)
n.each_index.any?{|x| n[x]==i and g[x]==e}
end
 
def solve_zebra_puzzle
CONTENT[:Nationality].permutation{|nation|
next unless nation.first == :Norwegian # 10
CONTENT[:Colour].permutation{|colour|
next unless leftof?(colour, :Green, colour, :White) # 5
next unless coincident?(nation, :English, colour, :Red) # 2
next unless adjacent?(nation, :Norwegian, colour, :Blue) # 15
CONTENT[:Pet].permutation{|pet|
next unless coincident?(nation, :Swedish, pet, :Dog) # 3
CONTENT[:Drink].permutation{|drink|
next unless drink[2] == :Milk # 9
next unless coincident?(nation, :Danish, drink, :Tea) # 4
next unless coincident?(colour, :Green, drink, :Coffee) # 6
CONTENT[:Smoke].permutation{|smoke|
next unless coincident?(smoke, :PallMall, pet, :Birds) # 7
next unless coincident?(smoke, :Dunhill, colour, :Yellow) # 8
next unless coincident?(smoke, :BlueMaster, drink, :Beer) # 13
next unless coincident?(smoke, :Prince, nation, :German) # 14
next unless adjacent?(smoke, :Blend, pet, :Cats) # 11
next unless adjacent?(smoke, :Blend, drink, :Water) # 16
next unless adjacent?(smoke, :Dunhill,pet, :Horse) # 12
print_out(nation, colour, pet, drink, smoke)
} } } } }
end
 
def print_out (nation, colour, pet, drink, smoke)
width = CONTENT.map{|x| x.flatten.map{|y|y.size}.max}
fmt = width.map{|w| "%-#{w}s"}.join(" ")
national = nation[ pet.find_index(:Zebra) ]
puts "The Zebra is owned by the man who is #{national}",""
puts fmt % CONTENT.keys, fmt % width.map{|w| "-"*w}
[nation,colour,pet,drink,smoke].transpose.each.with_index(1){|x,n| puts fmt % [n,*x]}
end
 
solve_zebra_puzzle</syntaxhighlight>
 
{{out}}
<pre>
The Zebra is owned by the man who is German
 
House Nationality Colour Pet Drink Smoke
----- ----------- ------ ----- ------ ----------
1 Norwegian Yellow Cats Water Dunhill
2 Danish Blue Horse Tea Blend
3 English Red Birds Milk PallMall
4 German Green Zebra Coffee Prince
5 Swedish White Dog Beer BlueMaster
</pre>
 
===Another approach===
<syntaxhighlight lang="ruby">
class String; def brk; split(/(?=[A-Z])/); end; end
men,drinks,colors,pets,smokes = "NorwegianGermanDaneSwedeEnglish
MilkTeaBeerWaterCoffeeGreenWhiteRedYellowBlueZebraDogCatsHorseBirds
PallmallDunhillBlendBluemasterPrince".delete(" \n").
brk.each_slice(5).map{|e| e.permutation.to_a};
men.select!{|x| "Norwegian"==x[0]};
drinks.select!{|x| "Milk"==x[2]};
colors.select!{|x| x.join[/GreenWhite/]};
 
dis = proc{|s,*a| s.brk.map{|w| a.map{|p| p.index(w)}.
compact[0]}.each_slice(2).map{|a,b| (a-b).abs}}
 
men.each{|m| colors.each{|c|
next unless dis["RedEnglishBlueNorwegian",c,m]==[0,1]
drinks.each{|d| next unless dis["DaneTeaCoffeeGreen",m,d,c]==[0,0]
smokes.each{|s|
next unless dis["YellowDunhillBluemasterBeerGermanPrince",
c,s,d,m]==[0,0,0]
pets.each{|p|
next unless dis["SwedeDogBirdsPallmallCatsBlendHorseDunhill",
m,p,s]==[0,0,1,1]
x = [p,m,c,d,s].transpose
puts "The #{x.find{|y|y[0]=="Zebra"}[1]} owns the zebra.",
x.map{|y| y.map{|z| z.ljust(11)}.join}}}}}}
</syntaxhighlight>
Output:
<pre>
The German owns the zebra.
Cats Norwegian Yellow Water Dunhill
Horse Dane Blue Tea Blend
Birds English Red Milk Pallmall
Zebra German Green Coffee Prince
Dog Swede White Beer Bluemaster
</pre>
 
=={{header|Scala}}==
===Idiomatic (for comprehension)===
<syntaxhighlight lang="scala">/* Note to the rules:
*
* It can further concluded that:
* 5a: The green house cannot be at the h1 position
* 5b: The white house cannot be at the h5 position
*
* 16: This rule is redundant.
*/
 
object Einstein extends App {
val possibleMembers = for { // pair clues results in 78 members
nationality <- List("Norwegian", "German", "Dane", "Englishman", "Swede")
color <- List("Red", "Green", "Yellow", "White", "Blue")
beverage <- List("Milk", "Coffee", "Tea", "Beer", "Water")
animal <- List("Dog", "Horse", "Birds", "Cats", "Zebra")
brand <- List("Blend", "Pall Mall", "Prince", "Blue Master", "Dunhill")
if (color == "Red") == (nationality == "Englishman") // #2
if (nationality == "Swede") == (animal == "Dog") // #3
if (nationality == "Dane") == (beverage == "Tea") // #4
if (color == "Green") == (beverage == "Coffee") // #6
if (brand == "Pall Mall") == (animal == "Birds") // #7
if (brand == "Dunhill") == (color == "Yellow") // #8
if (brand == "Blue Master") == (beverage == "Beer") // #13
if (brand == "Prince") == (nationality == "German") // #14
} yield new House(nationality, color, beverage, animal, brand)
val members = for { // Neighborhood clues
h1 <- housesLeftOver().filter(p => (p.nationality == "Norwegian" /* #10 */) && (p.color != "Green") /* #5a */) // 28
h3 <- housesLeftOver(h1).filter(p => p.beverage == "Milk") // #9 // 24
h2 <- housesLeftOver(h1, h3).filter(_.color == "Blue") // #15
if matchMiddleBrandAnimal(h1, h2, h3, "Blend", "Cats") // #11
if matchCornerBrandAnimal(h1, h2, "Horse", "Dunhill") // #12
h4 <- housesLeftOver(h1, h2, h3).filter(_.checkAdjacentWhite(h3) /* #5 */)
h5 <- housesLeftOver(h1, h2, h3, h4)
 
// Redundant tests
if h2.checkAdjacentWhite(h1)
if h3.checkAdjacentWhite(h2)
if matchCornerBrandAnimal(h5, h4, "Horse", "Dunhill")
if matchMiddleBrandAnimal(h2, h3, h4, "Blend", "Cats")
if matchMiddleBrandAnimal(h3, h4, h5, "Blend", "Cats")
} yield Seq(h1, h2, h3, h4, h5)
 
def matchMiddleBrandAnimal(home1: House, home2: House, home3: House, brand: String, animal: String) =
(home1.animal == animal || home2.brand != brand || home3.animal == animal) &&
(home1.brand == brand || home2.animal != animal || home3.brand == brand)
 
def matchCornerBrandAnimal(corner: House, inner: House, animal: String, brand: String) =
(corner.brand != brand || inner.animal == animal) && (corner.animal == animal || inner.brand != brand)
 
def housesLeftOver(pickedHouses: House*): List[House] = {
possibleMembers.filter(house => pickedHouses.forall(_.totalUnEqual(house)))
}
 
class House(val nationality: String, val color: String, val beverage: String, val animal: String, val brand: String) {
override def toString = {
f"$nationality%10s, ${color + ", "}%-8s$beverage,\t$animal,\t$brand."
}
 
def totalUnEqual(home2: House) =
this.animal != home2.animal &&
this.beverage != home2.beverage &&
this.brand != home2.brand &&
this.color != home2.color &&
this.nationality != home2.nationality
 
//** Checks if the this green house is next to the other white house*/
def checkAdjacentWhite(home2: House) = (this.color == "Green") == (home2.color == "White") // #5
}
 
{ // Main program
val beest = "Zebra"
members.flatMap(p => p.filter(p => p.animal == beest)).
foreach(s => println(s"The ${s.nationality} is the owner of the ${beest.toLowerCase}."))
 
println(s"The ${members.size} solution(s) are:")
members.foreach(solution => solution.zipWithIndex.foreach(h => println(s"House ${h._2 + 1} ${h._1}")))
}
} // loc 58</syntaxhighlight>
{{Out}}See it in running in your browser by [https://scalafiddle.io/sf/h5Y98te/0 ScalaFiddle (JavaScript executed in browser)] or by [https://scastie.scala-lang.org/fJZRog4xQ9aAV4D3crM1gQ Scastie (remote JVM)].{{out}}
<pre> The German is the owner of the zebra.
The 1 solution(s) are:
House 1 Norwegian, Yellow, Water, Cats, Dunhill.
House 2 Dane, Blue, Tea, Horse, Blend.
House 3 Englishman, Red, Milk, Birds, Pall Mall.
House 4 Swede, White, Beer, Dog, Blue Master.
House 5 German, Green, Coffee, Zebra, Prince.
</pre>
 
===Scala Alternate Version (Over-engineered)===
<syntaxhighlight lang="scala">import scala.util.Try
 
object Einstein extends App {
 
// The strategy here is to mount a brute-force attack on the solution space, pruning very aggressively.
// The scala standard `permutations` method is extremely helpful here. It turns out that by pruning
// quickly and smartly we can solve this very quickly (45ms on my machine) compared to days or weeks
// required to fully enumerate the solution space.
 
// We set up a for comprehension with an enumerator for each of the 5 variables, with if clauses to
// prune. The hard part is the pruning logic, which is basically just translating the rules to code
// and the data model. The data model is basically Seq[Seq[String]]
 
// Rules are encoded as for comprehension filters. There is a natural cascade of rules from
// depending on more or less criteria. The rules about smokes are the most complex and depend
// on the most other factors
 
// 4. The green house is just to the left of the white one.
def colorRules(colors: Seq[String]) = Try(colors(colors.indexOf("White") - 1) == "Green").getOrElse(false)
 
// 1. The Englishman lives in the red house.
// 9. The Norwegian lives in the first house.
// 14. The Norwegian lives next to the blue house.
def natRules(colors: Seq[String], nats: Seq[String]) =
nats.head == "Norwegian" && colors(nats.indexOf("Brit")) == "Red" &&
(Try(colors(nats.indexOf("Norwegian") - 1) == "Blue").getOrElse(false) ||
Try(colors(nats.indexOf("Norwegian") + 1) == "Blue").getOrElse(false))
 
// 3. The Dane drinks tea.
// 5. The owner of the green house drinks coffee.
// 8. The man in the center house drinks milk.
def drinkRules(colors: Seq[String], nats: Seq[String], drinks: Seq[String]) =
drinks(nats.indexOf("Dane")) == "Tea" &&
drinks(colors.indexOf("Green")) == "Coffee" &&
drinks(2) == "Milk"
 
// 2. The Swede keeps dogs.
def petRules(nats: Seq[String], pets: Seq[String]) = pets(nats.indexOf("Swede")) == "Dogs"
 
// 6. The Pall Mall smoker keeps birds.
// 7. The owner of the yellow house smokes Dunhills.
// 10. The Blend smoker has a neighbor who keeps cats.
// 11. The man who smokes Blue Masters drinks bier.
// 12. The man who keeps horses lives next to the Dunhill smoker.
// 13. The German smokes Prince.
// 15. The Blend smoker has a neighbor who drinks water.
def smokeRules(colors: Seq[String], nats: Seq[String], drinks: Seq[String], pets: Seq[String], smokes: Seq[String]) =
pets(smokes.indexOf("Pall Mall")) == "Birds" &&
smokes(colors.indexOf("Yellow")) == "Dunhill" &&
(Try(pets(smokes.indexOf("Blend") - 1) == "Cats").getOrElse(false) ||
Try(pets(smokes.indexOf("Blend") + 1) == "Cats").getOrElse(false)) &&
drinks(smokes.indexOf("BlueMaster")) == "Beer" &&
(Try(smokes(pets.indexOf("Horses") - 1) == "Dunhill").getOrElse(false) ||
Try(pets(pets.indexOf("Horses") + 1) == "Dunhill").getOrElse(false)) &&
smokes(nats.indexOf("German")) == "Prince" &&
(Try(drinks(smokes.indexOf("Blend") - 1) == "Water").getOrElse(false) ||
Try(drinks(smokes.indexOf("Blend") + 1) == "Water").getOrElse(false))
 
// once the rules are created it, the actual solution is simple: iterate brute force, pruning early.
val solutions = for {
colors <- Seq("Red", "Blue", "White", "Green", "Yellow").permutations if colorRules(colors)
nats <- Seq("Brit", "Swede", "Dane", "Norwegian", "German").permutations if natRules(colors, nats)
drinks <- Seq("Tea", "Coffee", "Milk", "Beer", "Water").permutations if drinkRules(colors, nats, drinks)
pets <- Seq("Dogs", "Birds", "Cats", "Horses", "Fish").permutations if petRules(nats, pets)
smokes <- Seq("BlueMaster", "Blend", "Pall Mall", "Dunhill", "Prince").permutations if smokeRules(colors, nats, drinks, pets, smokes)
} yield Seq(colors, nats, drinks, pets, smokes)
 
// There *should* be just one solution...
solutions.foreach { solution =>
// so we can pretty-print, find out the maximum string length of all cells
val maxLen = solution.flatten.map(_.length).max
 
def pretty(str: String): String = str + (" " * (maxLen - str.length + 1))
 
// a labels column
val labels = ("" +: Seq("Color", "Nation", "Drink", "Pet", "Smoke").map(_ + ":")).toIterator
 
// print each row including a column header
((1 to 5).map(n => s"House $n") +: solution).map(_.map(pretty)).map(x => (pretty(labels.next) +: x).mkString(" ")).foreach(println)
 
println(s"\nThe ${solution(1)(solution(3).indexOf("Fish"))} owns the Fish")
}
 
}// loc 38</syntaxhighlight>
{{Out}}Experience running it in your browser by [https://scalafiddle.io/sf/hJgtjYG/1 ScalaFiddle (JavaScript executed in browser)] or by [https://scastie.scala-lang.org/ajeuRgDSQKyVv4Jd6SPfVQ Scastie (remote JVM)].
{{out}}
<pre> House 1 House 2 House 3 House 4 House 5
Color: Yellow Blue Red Green White
Nation: Norwegian Dane Brit German Swede
Drink: Water Tea Milk Coffee Beer
Pet: Cats Horses Birds Fish Dogs
Smoke: Dunhill Blend Pall Mall Prince BlueMaster
 
The German owns the Fish
</pre>
 
=={{header|Sidef}}==
{{trans|Ruby}}
<syntaxhighlight lang="ruby">var CONTENT = Hash(
:House => nil,
:Nationality => [:English, :Swedish, :Danish, :Norwegian, :German],
:Colour => [:Red, :Green, :White, :Blue, :Yellow],
:Pet => [:Dog, :Birds, :Cats, :Horse, :Zebra],
:Drink => [:Tea, :Coffee, :Milk, :Beer, :Water],
:Smoke => [:PallMall, :Dunhill, :BlueMaster, :Prince, :Blend]
)
 
func adjacent(n,i,g,e) {
(0..3).any {|x| (n[x]==i && g[x+1]==e) || (n[x+1]==i && g[x]==e) }
}
 
func leftof(n,i,g,e) {
(0..3).any {|x| n[x]==i && g[x+1]==e }
}
 
func coincident(n,i,g,e) {
n.indices.any {|x| n[x]==i && g[x]==e }
}
 
func solve {
CONTENT{:Nationality}.permutations{|*nation|
nation.first == :Norwegian ->
&& CONTENT{:Colour}.permutations {|*colour|
leftof(colour,:Green,colour,:White) ->
&& coincident(nation,:English,colour,:Red) ->
&& adjacent(nation,:Norwegian,colour,:Blue) ->
&& CONTENT{:Pet}.permutations {|*pet|
coincident(nation,:Swedish,pet,:Dog) ->
&& CONTENT{:Drink}.permutations {|*drink|
drink[2] == :Milk ->
&& coincident(nation,:Danish,drink,:Tea) ->
&& coincident(colour,:Green,drink,:Coffee) ->
&& CONTENT{:Smoke}.permutations {|*smoke|
coincident(smoke,:PallMall,pet,:Birds) ->
&& coincident(smoke,:Dunhill,colour,:Yellow) ->
&& coincident(smoke,:BlueMaster,drink,:Beer) ->
&& coincident(smoke,:Prince,nation,:German) ->
&& adjacent(smoke,:Blend,pet,:Cats) ->
&& adjacent(smoke,:Blend,drink,:Water) ->
&& adjacent(smoke,:Dunhill,pet,:Horse) ->
&& return [nation,colour,pet,drink,smoke]
} } } } } }
 
var res = solve();
var keys = [:House, :Nationality, :Colour, :Pet, :Drink, :Smoke]
var width = keys.map{ .len }
var fmt = width.map{|w| "%-#{w+2}s" }.join(" ")
say "The Zebra is owned by the man who is #{res[0][res[2].first_index(:Zebra)]}\n"
say (fmt % keys..., "\n", fmt % width.map{|w| "-"*w }...)
res[0].indices.map{|i| res.map{|a| a[i] }}.each_kv {|k,v| say fmt%(k,v...) }</syntaxhighlight>
{{out}}
<pre>
The Zebra is owned by the man who is German
 
House Nationality Colour Pet Drink Smoke
----- ----------- ------ --- ----- -----
0 Norwegian Yellow Cats Water Dunhill
1 Danish Blue Horse Tea Blend
2 English Red Birds Milk PallMall
3 German Green Zebra Coffee Prince
4 Swedish White Dog Beer BlueMaster
</pre>
 
=={{header|Standard ML}}==
{{works with|SML/NJ}}
{{trans|C++}}(This implementation uses the search algorithm of the C++ implementation, but the rules check algorithm is different.)
<syntaxhighlight lang="sml">
(* Attributes and values *)
val str_attributes = Vector.fromList ["Color", "Nation", "Drink", "Pet", "Smoke"]
val str_colors = Vector.fromList ["Red", "Green", "White", "Yellow", "Blue"]
val str_nations = Vector.fromList ["English", "Swede", "Dane", "German", "Norwegian"]
val str_drinks = Vector.fromList ["Tea", "Coffee", "Milk", "Beer", "Water"]
val str_pets = Vector.fromList ["Dog", "Birds", "Cats", "Horse", "Zebra"]
val str_smokes = Vector.fromList ["PallMall", "Dunhill", "Blend", "BlueMaster", "Prince"]
 
val (Color, Nation, Drink, Pet, Smoke) = (0, 1, 2, 3, 4) (* Attributes *)
val (Red, Green, White, Yellow, Blue) = (0, 1, 2, 3, 4) (* Color *)
val (English, Swede, Dane, German, Norwegian) = (0, 1, 2, 3, 4) (* Nation *)
val (Tea, Coffee, Milk, Beer, Water) = (0, 1, 2, 3, 4) (* Drink *)
val (Dog, Birds, Cats, Horse, Zebra) = (0, 1, 2, 3, 4) (* Pet *)
val (PallMall, Dunhill, Blend, BlueMaster, Prince) = (0, 1, 2, 3, 4) (* Smoke *)
 
type attr = int
type value = int
type houseno = int
 
(* Rules *)
datatype rule =
AttrPairRule of (attr * value) * (attr * value)
| NextToRule of (attr * value) * (attr * value)
| LeftOfRule of (attr * value) * (attr * value)
 
(* Conditions *)
val rules = [
AttrPairRule ((Nation, English), (Color, Red)), (* #02 *)
AttrPairRule ((Nation, Swede), (Pet, Dog)), (* #03 *)
AttrPairRule ((Nation, Dane), (Drink, Tea)), (* #04 *)
LeftOfRule ((Color, Green), (Color, White)), (* #05 *)
AttrPairRule ((Color, Green), (Drink, Coffee)), (* #06 *)
AttrPairRule ((Smoke, PallMall), (Pet, Birds)), (* #07 *)
AttrPairRule ((Smoke, Dunhill), (Color, Yellow)), (* #08 *)
NextToRule ((Smoke, Blend), (Pet, Cats)), (* #11 *)
NextToRule ((Smoke, Dunhill), (Pet, Horse)), (* #12 *)
AttrPairRule ((Smoke, BlueMaster), (Drink, Beer)), (* #13 *)
AttrPairRule ((Nation, German), (Smoke, Prince)), (* #14 *)
NextToRule ((Nation, Norwegian), (Color, Blue)), (* #15 *)
NextToRule ((Smoke, Blend), (Drink, Water))] (* #16 *)
 
 
type house = value option * value option * value option * value option * value option
 
fun houseval ((a, b, c, d, e) : house, 0 : attr) = a
| houseval ((a, b, c, d, e) : house, 1 : attr) = b
| houseval ((a, b, c, d, e) : house, 2 : attr) = c
| houseval ((a, b, c, d, e) : house, 3 : attr) = d
| houseval ((a, b, c, d, e) : house, 4 : attr) = e
| houseval _ = raise Domain
 
fun sethouseval ((a, b, c, d, e) : house, 0 : attr, a2 : value option) = (a2, b, c, d, e )
| sethouseval ((a, b, c, d, e) : house, 1 : attr, b2 : value option) = (a, b2, c, d, e )
| sethouseval ((a, b, c, d, e) : house, 2 : attr, c2 : value option) = (a, b, c2, d, e )
| sethouseval ((a, b, c, d, e) : house, 3 : attr, d2 : value option) = (a, b, c, d2, e )
| sethouseval ((a, b, c, d, e) : house, 4 : attr, e2 : value option) = (a, b, c, d, e2)
| sethouseval _ = raise Domain
 
fun getHouseVal houses (no, attr) = houseval (Array.sub (houses, no), attr)
fun setHouseVal houses (no, attr, newval) =
Array.update (houses, no, sethouseval (Array.sub (houses, no), attr, newval))
 
 
fun match (house, (rule_attr, rule_val)) =
let
val value = houseval (house, rule_attr)
in
isSome value andalso valOf value = rule_val
end
 
fun matchNo houses (no, rule) =
match (Array.sub (houses, no), rule)
 
fun compare (house1, house2, ((rule_attr1, rule_val1), (rule_attr2, rule_val2))) =
let
val val1 = houseval (house1, rule_attr1)
val val2 = houseval (house2, rule_attr2)
in
if isSome val1 andalso isSome val2
then (valOf val1 = rule_val1 andalso valOf val2 <> rule_val2)
orelse
(valOf val1 <> rule_val1 andalso valOf val2 = rule_val2)
else false
end
 
fun compareNo houses (no1, no2, rulepair) =
compare (Array.sub (houses, no1), Array.sub (houses, no2), rulepair)
 
 
fun invalid houses no (AttrPairRule rulepair) =
compareNo houses (no, no, rulepair)
 
| invalid houses no (NextToRule rulepair) =
(if no > 0
then compareNo houses (no, no-1, rulepair)
else true)
andalso
(if no < 4
then compareNo houses (no, no+1, rulepair)
else true)
 
| invalid houses no (LeftOfRule rulepair) =
if no > 0
then compareNo houses (no-1, no, rulepair)
else matchNo houses (no, #1rulepair)
 
 
(*
* val checkRulesForNo : house vector -> houseno -> bool
* Check all rules for a house;
* Returns true, when one rule was invalid.
*)
fun checkRulesForNo (houses : house array) no =
let
exception RuleError
in
(map (fn rule => if invalid houses no rule then raise RuleError else ()) rules;
false)
handle RuleError => true
end
 
(*
* val checkAll : house vector -> bool
* Check all rules;
* return true if everything is ok.
*)
fun checkAll (houses : house array) =
let
exception RuleError
in
(map (fn no => if checkRulesForNo houses no then raise RuleError else ()) [0,1,2,3,4];
true)
handle RuleError => false
end
 
 
(*
*
* House printing for debugging
*
*)
 
fun valToString (0, SOME a) = Vector.sub (str_colors, a)
| valToString (1, SOME b) = Vector.sub (str_nations, b)
| valToString (2, SOME c) = Vector.sub (str_drinks, c)
| valToString (3, SOME d) = Vector.sub (str_pets, d)
| valToString (4, SOME e) = Vector.sub (str_smokes, e)
| valToString _ = "-"
 
(*
* Note:
* Format needs SML NJ
*)
fun printHouse no ((a, b, c, d, e) : house) =
(
print (Format.format "%12d" [Format.LEFT (12, Format.INT no)]);
print (Format.format "%12s%12s%12s%12s%12s"
(map (fn (x, y) => Format.LEFT (12, Format.STR (valToString (x, y))))
[(0,a), (1,b), (2,c), (3,d), (4,e)]));
print ("\n")
)
 
fun printHouses houses =
(
print (Format.format "%12s" [Format.LEFT (12, Format.STR "House")]);
Vector.map (fn a => print (Format.format "%12s" [Format.LEFT (12, Format.STR a)]))
str_attributes;
print "\n";
Array.foldli (fn (no, house, _) => printHouse no house) () houses
)
 
(*
*
* Solving
*
*)
 
exception SolutionFound
 
fun search (houses : house array, used : bool Array2.array) (no : houseno, attr : attr) =
let
val i = ref 0
val (nextno, nextattr) = if attr < 4 then (no, attr + 1) else (no + 1, 0)
in
if isSome (getHouseVal houses (no, attr))
then
(
search (houses, used) (nextno, nextattr)
)
else
(
while (!i < 5)
do
(
if Array2.sub (used, attr, !i) then ()
else
(
Array2.update (used, attr, !i, true);
setHouseVal houses (no, attr, SOME (!i));
 
if checkAll houses then
(
if no = 4 andalso attr = 4
then raise SolutionFound
else search (houses, used) (nextno, nextattr)
)
else ();
Array2.update (used, attr, !i, false)
); (* else *)
i := !i + 1
); (* do *)
setHouseVal houses (no, attr, NONE)
) (* else *)
end
 
fun init () =
let
val unknown : house = (NONE, NONE, NONE, NONE, NONE)
val houses = Array.fromList [unknown, unknown, unknown, unknown, unknown]
val used = Array2.array (5, 5, false)
in
(houses, used)
end
 
fun solve () =
let
val (houses, used) = init()
in
setHouseVal houses (2, Drink, SOME Milk); (* #09 *)
Array2.update (used, Drink, Milk, true);
setHouseVal houses (0, Nation, SOME Norwegian); (* #10 *)
Array2.update (used, Nation, Norwegian, true);
(search (houses, used) (0, 0); NONE)
handle SolutionFound => SOME houses
end
 
(*
*
* Execution
*
*)
 
fun main () = let
val solution = solve()
in
if isSome solution
then printHouses (valOf solution)
else print "No solution found!\n"
end
</syntaxhighlight>
 
{{out}}
<pre>
- main();
House Color Nation Drink Pet Smoke
0 Yellow Norwegian Water Cats Dunhill
1 Blue Dane Tea Horse Blend
2 Red English Milk Birds PallMall
3 Green German Coffee Zebra Prince
4 White Swede Beer Dog BlueMaster
val it = () : unit
</pre>
 
=={{header|Tailspin}}==
===General solver with relational algebra===
A general solver for this type of puzzle, using relational algebra. This solver can also be used for "Dinesman's multiple-dwelling problem"
<syntaxhighlight lang="tailspin">
processor EinsteinSolver
@: [{|{}|}]; // A list of possible relations, start with one relation with an empty tuple
$ -> \(
when <[](1..)> do
def variableRange: $(1);
@EinsteinSolver: [($@EinsteinSolver(1) join {|{by $variableRange...}|})];
$(2..last) -> #
\) -> !VOID
 
sink isFact
def fact: $;
def parts: [$... -> {$}];
@EinsteinSolver: [$@EinsteinSolver... -> \(
def new: ($ matching {|$fact|});
@: $;
$parts... -> @: ($@ notMatching {| $ |});
($new union $@) !
\)];
end isFact
 
operator (a nextTo&{byField:, bMinusA:} b)
data ES_temp__ <"1"> local
@EinsteinSolver: [$@EinsteinSolver... -> \(
def in: $;
def temp: {| $... -> {$, ES_temp__: ($(byField)::raw)"1"} |};
def numbers: [$temp({ES_temp__:})... -> $.ES_temp__];
$numbers... -> \(
def aNumber: $;
def bNumbers: [$bMinusA... -> ($ + $aNumber)"1"];
def new: ($temp matching {| {$a, ES_temp__: $aNumber} |});
@: ($new union (($temp notMatching {| $a |}) notMatching {| {ES_temp__: $aNumber} |}));
$numbers... -> \(<~ ?($bNumbers <[<=$>]>)> $! \) -> @: ($@ notMatching {| {$b, ES_temp__: $} |});
($in matching $@) !
\) !
\)];
end nextTo
 
source solutions&{required:}
templates resolve&{rows:}
when <?($rows <=1>)?($::count <=1>)> do $ !
when <?($::count <$rows..>)> do
def in: $;
def selected: [$...] -> $(1);
($in minus {|$selected|}) -> resolve&{rows: $rows} ! // Alternative solutions
@: $;
$selected... -> {$} -> @: ($@ notMatching {| $ |});
[$@ -> resolve&{rows: $rows-1}] -> \(
when <~=[]> do
$... -> {| $..., $selected |} !
\) !
end resolve
[$@EinsteinSolver... -> resolve&{rows: $required}] !
end solutions
end EinsteinSolver
 
def numbers: [1..5 -> (no: $)];
def nationalities: [['Englishman', 'Swede', 'Dane', 'Norwegian', 'German']... -> (nationality:$)];
def colours: [['red', 'green', 'white', 'yellow', 'blue']... -> (colour:$)];
def pets: [['dog', 'birds', 'cats', 'horse', 'zebra']... -> (pet:$)];
def drinks: [['tea', 'coffee', 'milk', 'beer', 'water']... -> (drink:$)];
def smokes: [['Pall Mall', 'Dunhill', 'Blend', 'Blue Master', 'Prince']... -> (smoke: $)];
 
 
def solutions: [$numbers, $nationalities, $colours, $pets, $drinks, $smokes] -> \(
def solver: $ -> EinsteinSolver;
 
{nationality: 'Englishman', colour: 'red'} -> !solver::isFact
{nationality: 'Swede', pet: 'dog'} -> !solver::isFact
{nationality: 'Dane', drink: 'tea'} -> !solver::isFact
({colour: 'green'} solver::nextTo&{byField: :(no:), bMinusA: [1]} {colour: 'white'}) -> !VOID
{drink: 'coffee', colour: 'green'} -> !solver::isFact
{smoke: 'Pall Mall', pet: 'birds'} -> !solver::isFact
{colour: 'yellow', smoke: 'Dunhill'} -> !solver::isFact
{no: 3, drink: 'milk'} -> !solver::isFact
{nationality: 'Norwegian', no: 1} -> !solver::isFact
({smoke: 'Blend'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {pet: 'cats'}) -> !VOID
({smoke: 'Dunhill'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {pet: 'horse'}) -> !VOID
{smoke: 'Blue Master', drink: 'beer'} -> !solver::isFact
{nationality: 'German', smoke: 'Prince'} -> !solver::isFact
({nationality: 'Norwegian'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {colour: 'blue'}) -> !VOID
({drink: 'water'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {smoke: 'Blend'}) -> !VOID
 
$solver::solutions&{required: 5}!
\);
 
$solutions... -> ($ matching {| {pet: 'zebra'} |}) ... -> 'The $.nationality; owns the zebra.
 
' -> !OUT::write
 
$solutions -> \[i]('Solution $i;:
$... -> '$;
';
'! \)... -> !OUT::write
'No more solutions
' -> !OUT::write
</syntaxhighlight>
 
{{out}}
<pre>
The German owns the zebra.
 
Solution 1:
{colour=green, drink=coffee, nationality=German, no=4, pet=zebra, smoke=Prince}
{colour=white, drink=beer, nationality=Swede, no=5, pet=dog, smoke=Blue Master}
{colour=blue, drink=tea, nationality=Dane, no=2, pet=horse, smoke=Blend}
{colour=yellow, drink=water, nationality=Norwegian, no=1, pet=cats, smoke=Dunhill}
{colour=red, drink=milk, nationality=Englishman, no=3, pet=birds, smoke=Pall Mall}
 
No more solutions
</pre>
 
===Manual "Norvig" solution===
{{trans|C#}}
The streaming syntax of Tailspin lends itself naturally to this solution
<syntaxhighlight lang="tailspin">
templates permutations
when <=1> do [1] !
otherwise
def n: $;
templates expand
def p: $;
1..$n -> \(def k: $;
[$p(1..$k-1)..., $n, $p($k..last)...] !\) !
end expand
$n - 1 -> permutations -> expand !
end permutations
 
def permutationsOf5: [5 -> permutations];
 
def nationalities: ['Englishman', 'Swede', 'Dane', 'Norwegian', 'German'];
def colours: ['red', 'green', 'white', 'yellow', 'blue'];
def pets: ['dog', 'birds', 'cats', 'horse', 'zebra'];
def drinks: ['tea', 'coffee', 'milk', 'beer', 'water'];
def smokes: ['Pall Mall', 'Dunhill', 'Blend', 'Blue Master', 'Prince'];
 
$permutationsOf5... -> $colours($) -> [$... -> {colour: $}]
-> \(<[(<{colour: <='green'>}>:<{colour: <='white'>}>)]> $! \)
-> \(def current: $;
$permutationsOf5... -> $nationalities($) -> \[i]({$current($i), nationality: $}! \) !
\)
-> \(<?($(1) <{nationality: <='Norwegian'>}>)> $! \)
-> \(<[<{nationality: <='Englishman'>, colour: <='red'>}>]> $! \)
-> \(<[(<{nationality: <='Norwegian'>}>:<{colour: <='blue'>}>)] | [(<{colour: <='blue'>}>:<{nationality: <='Norwegian'>}>)]> $! \)
-> \(def current: $;
$permutationsOf5... -> $drinks($) -> \[i]({$current($i), drink: $}! \) !
\)
-> \(<?($(3) <{drink: <='milk'>}>)> $! \)
-> \(<[<{drink: <='coffee'>, colour: <='green'>}>]> $! \)
-> \(<[<{drink: <='tea'>, nationality: <='Dane'>}>]> $! \)
-> \(def current: $;
$permutationsOf5... -> $pets($) -> \[i]({$current($i), pet: $}! \)!
\)
-> \(<[<{nationality: <='Swede'>, pet: <='dog'>}>]> $! \)
-> \(def current: $;
$permutationsOf5... -> $smokes($) -> \[i]({$current($i), smoke: $}! \)!
\)
-> \(<[<{smoke: <='Pall Mall'>, pet: <='birds'>}>]> $! \)
-> \(<[<{smoke: <='Dunhill'>, colour: <='yellow'>}>]> $! \)
-> \(<[(<{smoke: <='Blend'>}>:<{pet: <='cats'>}>)] | [(<{pet: <='cats'>}>:<{smoke: <='Blend'>}>)]> $! \)
-> \(<[(<{smoke: <='Dunhill'>}>:<{pet: <='horse'>}>)] | [(<{pet: <='horse'>}>:<{smoke: <='Dunhill'>}>)]> $! \)
-> \(<[<{smoke: <='Blue Master'>, drink: <='beer'>}>]> $! \)
-> \(<[<{smoke: <='Prince'>, nationality: <='German'>}>]> $! \)
-> \(<[(<{smoke: <='Blend'>}>:<{drink: <='water'>}>)] | [(<{drink: <='water'>}>:<{smoke: <='Blend'>}>)]> $! \)
-> \[i](when <{pet: <='zebra'>}> do 'The $.nationality; owns the zebra.$#10;' -> !OUT::write $!
otherwise $! \)
-> \[i]('$i;: $;'! \) -> '$... -> '$;$#10;';$#10;'
-> !OUT::write
</syntaxhighlight>
{{out}}
<pre>
The German owns the zebra.
1: {colour=yellow, drink=water, nationality=Norwegian, pet=cats, smoke=Dunhill}
2: {colour=blue, drink=tea, nationality=Dane, pet=horse, smoke=Blend}
3: {colour=red, drink=milk, nationality=Englishman, pet=birds, smoke=Pall Mall}
4: {colour=green, drink=coffee, nationality=German, pet=zebra, smoke=Prince}
5: {colour=white, drink=beer, nationality=Swede, pet=dog, smoke=Blue Master}
</pre>
 
=={{header|Tcl}}==
{{trans|Python}}
{{tcllib|struct::list}}<syntaxhighlight lang="tcl">package require struct::list
<lang tcl>package require struct::list
 
# Implements the constants by binding them directly into the named procedures.
Line 1,292 ⟶ 7,551:
 
initConstants isPossible
main</langsyntaxhighlight>
{{out}}
<pre>
Found a solution:
Nation: British Swedish Danish Norwegian German
Number: Three Five Two One Four
Color: Red White Blue Yellow Green
Drink: Milk Beer Tea Water Coffee
Smoke: PallMall BlueMaster Blend Dunhill Prince
Pet: Bird Dog Horse Cat Zebra
</pre>
 
=={{header|Uiua}}==
Usese the same re-ordering of rules as a lot of other approaches. Builds and filters the list as it goes.
<syntaxhighlight lang="uiua">
Perms ← ☇1⍉∧(≡↻⇡⟜↯+1⟜⊂):¤¤°⊂⇡
Ps ← ≡⊏⊙¤Perms ⧻.
 
Ps "BGRWY" # Col = 0
▽⊸(=-1⊃(⊗@W|⊗@G)) # W right of G
 
/⊂⊞⊟ :Ps "DEGNS" # Nation = 1
▽⊸≡(=@N⊡0⊡1) # Norwegian in pos 0
▽⊸≡(=⊃(⊗@E⊡1|⊗@R⊡0)) # Red == English
▽⊸≡(=1⌵-⊃(⊗@N⊡1|⊗@B⊡0)) # Blue next to Norwegian
 
/⊂⊞⊂ :Ps"BCDHZ" # Pets = 2
▽⊸≡(=⊃(⊗@D⊡2|⊗@S⊡1)) # Swede owns dog
 
/⊂⊞⊂ :Ps"BCMTW" # Drinks = 3
▽⊸≡(=@M⊡2⊡3) # Milk in pos 2
▽⊸≡(=⊃(⊗@T⊡3|⊗@D⊡1)) # Dane drinks tea
▽⊸≡(=⊃(⊗@C⊡3|⊗@G⊡0)) # Green = Coffee
 
/⊂⊞⊂ :Ps"BbDpP" # Cigs = 4
▽⊸≡(=⊃(⊗@p⊡4|⊗@B⊡2)) # PallMall = Birds
▽⊸≡(=⊃(⊗@D⊡4|⊗@Y⊡0)) # Dunhill = Yellow
▽⊸≡(=⊃(⊗@b⊡4|⊗@B⊡3)) # BlueM = Beer
▽⊸≡(=⊃(⊗@P⊡4|⊗@G⊡1)) # Prince = German
▽⊸≡(=1⌵-⊃(⊗@B⊡4|⊗@C⊡2)) # Cat next to Blend
▽⊸≡(=1⌵-⊃(⊗@D⊡4|⊗@H⊡2)) # Horse next to Dunhill
▽⊸≡(=1⌵-⊃(⊗@B⊡4|⊗@W⊡3)) # Water next to Blend
&p $"Solutions found: _" ⧻.
&p$"_ owns the Z"⊡:⊡1,⊗@Z⊡2.⊢
&p"One line per house: "
&p"Col\tNat\tPet\tDrink\tCig"
≡(&p/(⊂⊂)"\t")⍉
</syntaxhighlight>
{{out}}
<pre>
Solutions found: 1
G owns the Z
One line per house:
Col Nat Pet Drink Cig
Y N C W D
B D H T B
R E B M p
G G Z C P
W S D B b
</pre>
=={{header|VBA}}==
{{trans|Phix}}
<syntaxhighlight lang="vb">Option Base 1
Public Enum attr
Colour = 1
Nationality
Beverage
Smoke
Pet
End Enum
Public Enum Drinks_
Beer = 1
Coffee
Milk
Tea
Water
End Enum
Public Enum nations
Danish = 1
English
German
Norwegian
Swedish
End Enum
Public Enum colors
Blue = 1
Green
Red
White
Yellow
End Enum
Public Enum tobaccos
Blend = 1
BlueMaster
Dunhill
PallMall
Prince
End Enum
Public Enum animals
Bird = 1
Cat
Dog
Horse
Zebra
End Enum
Public permutation As New Collection
Public perm(5) As Variant
Const factorial5 = 120
Public Colours As Variant, Nationalities As Variant, Drinks As Variant, Smokes As Variant, Pets As Variant
 
Private Sub generate(n As Integer, A As Variant)
If n = 1 Then
permutation.Add A
Else
For i = 1 To n
generate n - 1, A
If n Mod 2 = 0 Then
tmp = A(i)
A(i) = A(n)
A(n) = tmp
Else
tmp = A(1)
A(1) = A(n)
A(n) = tmp
End If
Next i
End If
End Sub
 
Function house(i As Integer, name As Variant) As Integer
Dim x As Integer
For x = 1 To 5
If perm(i)(x) = name Then
house = x
Exit For
End If
Next x
End Function
Function left_of(h1 As Integer, h2 As Integer) As Boolean
left_of = (h1 - h2) = -1
End Function
Function next_to(h1 As Integer, h2 As Integer) As Boolean
next_to = Abs(h1 - h2) = 1
End Function
Private Sub print_house(i As Integer)
Debug.Print i & ": "; Colours(perm(Colour)(i)), Nationalities(perm(Nationality)(i)), _
Drinks(perm(Beverage)(i)), Smokes(perm(Smoke)(i)), Pets(perm(Pet)(i))
End Sub
Public Sub Zebra_puzzle()
Colours = [{"blue","green","red","white","yellow"}]
Nationalities = [{"Dane","English","German","Norwegian","Swede"}]
Drinks = [{"beer","coffee","milk","tea","water"}]
Smokes = [{"Blend","Blue Master","Dunhill","Pall Mall","Prince"}]
Pets = [{"birds","cats","dog","horse","zebra"}]
Dim solperms As New Collection
Dim solutions As Integer
Dim b(5) As Integer, i As Integer
For i = 1 To 5: b(i) = i: Next i
'There are five houses.
generate 5, b
For c = 1 To factorial5
perm(Colour) = permutation(c)
'The green house is immediately to the left of the white house.
If left_of(house(Colour, Green), house(Colour, White)) Then
For n = 1 To factorial5
perm(Nationality) = permutation(n)
'The Norwegian lives in the first house.
'The English man lives in the red house.
'The Norwegian lives next to the blue house.
If house(Nationality, Norwegian) = 1 _
And house(Nationality, English) = house(Colour, Red) _
And next_to(house(Nationality, Norwegian), house(Colour, Blue)) Then
For d = 1 To factorial5
perm(Beverage) = permutation(d)
'The Dane drinks tea.
'They drink coffee in the green house.
'In the middle house they drink milk.
If house(Nationality, Danish) = house(Beverage, Tea) _
And house(Beverage, Coffee) = house(Colour, Green) _
And house(Beverage, Milk) = 3 Then
For s = 1 To factorial5
perm(Smoke) = permutation(s)
'In the yellow house they smoke Dunhill.
'The German smokes Prince.
'The man who smokes Blue Master drinks beer.
'They Drink water in a house next to the house where they smoke Blend.
If house(Colour, Yellow) = house(Smoke, Dunhill) _
And house(Nationality, German) = house(Smoke, Prince) _
And house(Smoke, BlueMaster) = house(Beverage, Beer) _
And next_to(house(Beverage, Water), house(Smoke, Blend)) Then
For p = 1 To factorial5
perm(Pet) = permutation(p)
'The Swede has a dog.
'The man who smokes Pall Mall has birds.
'The man who smokes Blend lives in the house next to the house with cats.
'In a house next to the house where they have a horse, they smoke Dunhill.
If house(Nationality, Swedish) = house(Pet, Dog) _
And house(Smoke, PallMall) = house(Pet, Bird) _
And next_to(house(Smoke, Blend), house(Pet, Cat)) _
And next_to(house(Pet, Horse), house(Smoke, Dunhill)) Then
For i = 1 To 5
print_house i
Next i
Debug.Print
solutions = solutions + 1
solperms.Add perm
End If
Next p
End If
Next s
End If
Next d
End If
Next n
End If
Next c
Debug.Print Format(solutions, "@"); " solution" & IIf(solutions > 1, "s", "") & " found"
For i = 1 To solperms.Count
For j = 1 To 5
perm(j) = solperms(i)(j)
Next j
Debug.Print "The " & Nationalities(perm(Nationality)(house(Pet, Zebra))) & " owns the Zebra"
Next i
End Sub</syntaxhighlight>{{out}}
<pre>1: yellow Norwegian water Dunhill cats
2: blue Dane tea Blend horse
3: red English milk Pall Mall birds
4: green German coffee Prince zebra
5: white Swede beer Blue Master dog
 
1 solution found
The German owns the Zebra</pre>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">type HouseSet = []House
struct House {
n Nationality
c Colour
a Animal
d Drink
s Smoke
}
// Define the possible values
enum Nationality {
english = 0
swede
dane
norwegian
german
}
enum Colour {
red = 0
green
white
yellow
blue
}
enum Animal {
dog = 0
birds
cats
horse
zebra
}
enum Drink {
tea = 0
coffee
milk
beer
water
}
enum Smoke {
pall_mall = 0
dunhill
blend
blue_master
prince
}
// And how to print them
const nationalities = [Nationality.english, Nationality.swede, Nationality.dane, Nationality.norwegian, Nationality.german]
const colours = [Colour.red, Colour.green, Colour.white, Colour.yellow, Colour.blue]
const animals = [Animal.dog, Animal.birds, Animal.cats, Animal.horse, Animal.zebra]
const drinks = [Drink.tea, Drink.coffee, Drink.milk, Drink.beer, Drink.water]
const smokes = [Smoke.pall_mall, Smoke.dunhill, Smoke.blend, Smoke.blue_master, Smoke.prince]
 
fn (h House) str() string {
return "${h.n:-9} ${h.c:-6} ${h.a:-5} ${h.d:-6} $h.s"
}
fn (hs HouseSet) str() string {
mut lines := []string{len: 0, cap: 5}
for i, h in hs {
s := "$i $h"
lines << s
}
return lines.join("\n")
}
// Simple brute force solution
fn simple_brute_force() (int, HouseSet) {
mut v := []House{}
for n in nationalities {
for c in colours {
for a in animals {
for d in drinks {
for s in smokes {
h := House{
n: n,
c: c,
a: a,
d: d,
s: s,
}
if !h.valid() {
continue
}
v << h
}
}
}
}
}
n := v.len
println("Generated $n valid houses")
mut combos := 0
mut first := 0
mut valid := 0
mut valid_set := []House{}
for a := 0; a < n; a++ {
if v[a].n != Nationality.norwegian { // Condition 10:
continue
}
for b := 0; b < n; b++ {
if b == a {
continue
}
if v[b].any_dups(v[a]) {
continue
}
for c := 0; c < n; c++ {
if c == b || c == a {
continue
}
if v[c].d != Drink.milk { // Condition 9:
continue
}
if v[c].any_dups(v[b], v[a]) {
continue
}
for d := 0; d < n; d++ {
if d == c || d == b || d == a {
continue
}
if v[d].any_dups(v[c], v[b], v[a]) {
continue
}
for e := 0; e < n; e++ {
if e == d || e == c || e == b || e == a {
continue
}
if v[e].any_dups(v[d], v[c], v[b], v[a]) {
continue
}
combos++
set := HouseSet([v[a], v[b], v[c], v[d], v[e]])
if set.valid() {
valid++
if valid == 1 {
first = combos
}
valid_set = set
//return set
}
}
}
}
}
}
println("Tested $first different combinations of valid houses before finding solution")
println("Tested $combos different combinations of valid houses in total")
return valid, valid_set
}
// any_dups returns true if h as any duplicate attributes with any of the specified houses
fn (h House) any_dups(list ...House) bool {
for b in list {
if h.n == b.n || h.c == b.c || h.a == b.a || h.d == b.d || h.s == b.s {
return true
}
}
return false
}
fn (h House) valid() bool {
// Condition 2:
if (h.n == Nationality.english && h.c != Colour.red) || (h.n != Nationality.english && h.c == Colour.red) {
return false
}
// Condition 3:
if (h.n == Nationality.swede && h.a != Animal.dog) || (h.n != Nationality.swede && h.a == Animal.dog) {
return false
}
// Condition 4:
if (h.n == Nationality.dane && h.d != Drink.tea) || (h.n != Nationality.dane && h.d == Drink.tea ){
return false
}
// Condition 6:
if (h.c == Colour.green && h.d != Drink.coffee) || (h.c != Colour.green && h.d == Drink.coffee) {
return false
}
// Condition 7:
if (h.a == Animal.birds && h.s != Smoke.pall_mall) || (h.a != Animal.birds && h.s == Smoke.pall_mall) {
return false
}
// Condition 8:
if (h.c == Colour.yellow && h.s != Smoke.dunhill) || (h.c != Colour.yellow && h.s == Smoke.dunhill) {
return false
}
// Condition 11:
if h.a == Animal.cats && h.s == Smoke.blend {
return false
}
// Condition 12:
if h.a == Animal.horse && h.s == Smoke.dunhill {
return false
}
// Condition 13:
if (h.d == Drink.beer && h.s != Smoke.blue_master) || (h.d != Drink.beer && h.s == Smoke.blue_master) {
return false
}
// Condition 14:
if (h.n == Nationality.german && h.s != Smoke.prince) || (h.n != Nationality.german && h.s == Smoke.prince) {
return false
}
// Condition 15:
if h.n == Nationality.norwegian && h.c == Colour.blue {
return false
}
// Condition 16:
if h.d == Drink.water && h.s == Smoke.blend {
return false
}
return true
}
fn (hs HouseSet) valid() bool {
mut ni := map[Nationality]int{}
mut ci := map[Colour]int{}
mut ai := map[Animal]int{}
mut di := map[Drink]int{}
mut si := map[Smoke]int{}
for i, h in hs {
ni[h.n] = i
ci[h.c] = i
ai[h.a] = i
di[h.d] = i
si[h.s] = i
}
// Condition 5:
if ci[Colour.green]+1 != ci[Colour.white] {
return false
}
// Condition 11:
if dist(ai[Animal.cats], si[Smoke.blend]) != 1 {
return false
}
// Condition 12:
if dist(ai[Animal.horse], si[Smoke.dunhill]) != 1 {
return false
}
// Condition 15:
if dist(ni[Nationality.norwegian], ci[Colour.blue]) != 1 {
return false
}
// Condition 16:
if dist(di[Drink.water], si[Smoke.blend]) != 1 {
return false
}
 
// Condition 9: (already tested elsewhere)
if hs[2].d != Drink.milk {
return false
}
// Condition 10: (already tested elsewhere)
if hs[0].n != Nationality.norwegian {
return false
}
return true
}
fn dist(a int, b int) int {
if a > b {
return a - b
}
return b - a
}
fn main() {
n, sol := simple_brute_force()
println("$n solution found")
println(sol)
}</syntaxhighlight>
 
{{out}}
<pre>
Generated 51 valid houses
Tested 652 different combinations of valid houses before finding solution
Tested 750 different combinations of valid houses in total
1 solution found
0 norwegian yellow cats water dunhill
1 dane blue horse tea blend
2 english red birds milk pall_mall
3 german green zebra coffee prince
4 swede white dog beer blue_master
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./fmt" for Fmt
 
var colors = ["Red", "Green", "White", "Yellow", "Blue"]
var nations = ["English", "Swede", "Danish", "Norwegian", "German"]
var animals = ["Dog", "Birds", "Cats", "Horse", "Zebra"]
var drinks = ["Tea", "Coffee", "Milk", "Beer", "Water"]
var smokes = ["Pall Mall", "Dunhill", "Blend", "Blue Master", "Prince"]
 
var p = List.filled(120, null) // stores all permutations of numbers 0..4
for (i in 0..119) p[i] = List.filled(5, -1)
 
var nextPerm = Fn.new { |perm|
var size = perm.count
var k = -1
for (i in size-2..0) {
if (perm[i] < perm[i + 1]) {
k = i
break
}
}
if (k == -1) return false // last permutation
for (l in size-1..k) {
if (perm[k] < perm[l]) {
perm.swap(k, l)
var m = k + 1
var n = size - 1
while (m < n) {
perm.swap(m, n)
m = m + 1
n = n - 1
}
break
}
}
return true
}
 
var check = Fn.new { |a1, a2, v1, v2|
for (i in 0..4) {
if (p[a1][i] == v1) return p[a2][i] == v2
}
return false
}
 
var checkLeft = Fn.new { |a1, a2, v1, v2|
for (i in 0..3) {
if (p[a1][i] == v1) return p[a2][i + 1] == v2
}
return false
}
 
var checkRight = Fn.new { |a1, a2, v1, v2|
for (i in 1..4) {
if (p[a1][i] == v1) return p[a2][i - 1] == v2
}
return false
}
 
var checkAdjacent = Fn.new { |a1, a2, v1, v2|
return checkLeft.call(a1, a2, v1, v2) || checkRight.call(a1, a2, v1, v2)
}
 
var printHouses = Fn.new { |c, n, a, d, s|
var owner = ""
System.print("House Color Nation Animal Drink Smokes")
System.print("===== ====== ========= ====== ====== ===========")
for (i in 0..4) {
var f = "$3d $-6s $-9s $-6s $-6s $-11s"
var l = [i + 1, colors[p[c][i]], nations[p[n][i]], animals[p[a][i]], drinks[p[d][i]], smokes[p[s][i]]]
Fmt.lprint(f, l)
if (animals[p[a][i]] == "Zebra") owner = nations[p[n][i]]
}
System.print("\nThe %(owner) owns the Zebra\n")
}
 
var fillHouses = Fn.new {
var solutions = 0
for (c in 0..119) {
if (!checkLeft.call(c, c, 1, 2)) continue // C5 : Green left of white
for (n in 0..119) {
if (p[n][0] != 3) continue // C10: Norwegian in First
if (!check.call(n, c, 0, 0)) continue // C2 : English in Red
if (!checkAdjacent.call(n, c, 3, 4)) continue // C15: Norwegian next to Blue
for (a in 0..119) {
if (!check.call(a, n, 0, 1)) continue // C3 : Swede has Dog
for (d in 0..119) {
if (p[d][2] != 2) continue // C9 : Middle drinks Milk
if (!check.call(d, n, 0, 2)) continue // C4 : Dane drinks Tea
if (!check.call(d, c, 1, 1)) continue // C6 : Green drinks Coffee
for (s in 0..119) {
if (!check.call(s, a, 0, 1)) continue // C7 : Pall Mall has Birds
if (!check.call(s, c, 1, 3)) continue // C8 : Yellow smokes Dunhill
if (!check.call(s, d, 3, 3)) continue // C13: Blue Master drinks Beer
if (!check.call(s, n, 4, 4)) continue // C14: German smokes Prince
if (!checkAdjacent.call(s, a, 2, 2)) continue // C11: Blend next to Cats
if (!checkAdjacent.call(s, a, 1, 3)) continue // C12: Dunhill next to Horse
if (!checkAdjacent.call(s, d, 2, 4)) continue // C16: Blend next to Water
solutions = solutions + 1
printHouses.call(c, n, a, d, s)
}
}
}
}
}
return solutions
}
 
var perm = [0, 1, 2, 3, 4]
for (i in 0..119) {
for (j in 0..4) p[i][j] = perm[j]
nextPerm.call(perm)
}
var solutions = fillHouses.call()
var plural = (solutions == 1) ? "" : "s"
System.print("%(solutions) solution%(plural) found")</syntaxhighlight>
 
{{out}}
<pre>
House Color Nation Animal Drink Smokes
===== ====== ========= ====== ====== ===========
1 Yellow Norwegian Cats Water Dunhill
2 Blue Danish Horse Tea Blend
3 Red English Birds Milk Pall Mall
4 Green German Zebra Coffee Prince
5 White Swede Dog Beer Blue Master
 
The German owns the Zebra
 
1 solution found
</pre>
 
=={{header|zkl}}==
The solution space is too large to brute force search so solutions are built up by solving for one or two variables, then solving that set for a one or two more variables until all the variables & constraints are tested.
 
Lists are used as associated arrays rather than hash tables. With only five entries, it doesn't really matter.
<syntaxhighlight lang="zkl">var people,drinks,houses,smokes,pets; // lists treated as associated arrays
fcn c2 { people.find(English)==houses.find(Red) }
fcn c3 { people.find(Swede)==pets.find(Dog) }
fcn c4 { people.find(Dane)==drinks.find(Tea) }
fcn c5 { (houses.find(Green) + 1)==houses.find(White) }
fcn c5a{ houses.find(Green)!=4 } // deduced constraint (from c5)
fcn c5b{ houses.find(White)!=0 } // deduced constraint (from c5)
fcn c6 { drinks.find(Coffee)==houses.find(Green) }
fcn c7 { smokes.find(PallMall)==pets.find(Bird) }
fcn c8 { houses.find(Yellow)==smokes.find(Dunhill) }
fcn c9 { drinks[2]==Milk } // 0,1,2,3,4
fcn c10{ people[0]==Norwegian }
fcn c11{ (smokes.find(Blend) - pets.find(Cat)).abs()==1 }
fcn c12{ (pets.find(Horse) - smokes.find(Dunhill)).abs()==1 }
fcn c13{ smokes.find(BlueMaster)==drinks.find(Beer) }
fcn c14{ people.find(German)==smokes.find(Prince) }
fcn c15{ (people.find(Norwegian) - houses.find(Blue)).abs()==1 }
fcn c16{ (drinks.find(Water) - smokes.find(Blend)).abs()==1 }
#<<<#//////////////////////////////////////////////////////////////////////
Showing a solution to c2,c5,c10,c15:
|0 1 2 3 4
--------+-------------------------------------------
houses: |Yellow Blue Red Green White
people: |Norwegian Dane English German Swede
#<<<#//////////////////////////////////////////////////////////////////////
 
const Blue =0,Green =1,Red =2,White =3,Yellow=4,
Dane =0,English =1,German =2,Norwegian=3,Swede =4,
Beer =0,Coffee =1,Milk =2,Tea =3,Water =4,
Blend=0,BlueMaster=1,Dunhill=2,PallMall =3,Prince=4,
Bird =0,Cat =1,Dog =2,Horse =3,Zebra =4;
perm5:=T(0,1,2,3,4) : Utils.Helpers.permute(_); // 120 sets
 
constraints:=T(c2,c3,c4,c5,c5a,c5b,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16);
constraints1:=T(c2,c5,c10,c15); // houses,people: 12 solutions
constraints2:=T(c4,c6,c9); // houses,people,drinks: down to 8 solutions
foreach _houses,_people in (perm5,perm5){ houses,people=_houses,_people;
if(not constraints1.runNFilter(False)){ // all constraints are True
foreach _drinks in (perm5){ drinks=_drinks;
if(not constraints2.runNFilter(False)){
foreach _smokes,_pets in (perm5,perm5){ smokes,pets=_smokes,_pets;
if(not constraints.runNFilter(False)) printSolution();
}// smokes,pets
}
} // drinks
} // houses,people
}
fcn printSolution{
var titles=T("Houses:","People:","Drinks:","Smokes:","Pets:"),
names=T(
T("Blue", "Green", "Red", "White", "Yellow",),
T("Dane", "English", "German", "Norwegian","Swede",),
T("Beer", "Coffee", "Milk", "Tea", "Water",),
T("Blend","Blue Master","Dunhill","Pall Mall","Prince",),
T("Bird", "Cat", "Dog", "Horse", "Zebra",) ),
;
fmt:=("%-7s " + "%-11s "*5).fmt;
foreach list,title,names in (T(houses,people,drinks,smokes,pets)
.zip(titles,names))
{ println(list.apply(names.get):fmt(title,_.xplode())) }
}</syntaxhighlight>
{{out}}
<pre>
Houses: Yellow Blue Red Green White
People: Norwegian Dane English German Swede
Drinks: Water Tea Milk Coffee Beer
Smokes: Dunhill Blend Pall Mall Prince Blue Master
Pets: Cat Horse Bird Zebra Dog
</pre>
190

edits