75 lines
3.3 KiB
Plaintext
75 lines
3.3 KiB
Plaintext
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)
|