RosettaCodeData/Task/Zebra-puzzle/Phix/zebra-puzzle.phix
2024-07-13 15:19:22 -07:00

86 lines
3.6 KiB
Text

--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})