2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,3 +1,5 @@
|
|||
[[File:zebra.png|550px||right]]
|
||||
|
||||
The [[wp:Zebra puzzle|Zebra puzzle]], a.k.a. Einstein's Riddle,
|
||||
is a logic puzzle which is to be solved programmatically. <br>
|
||||
It has several variants, one of them this:
|
||||
|
|
@ -19,9 +21,13 @@ It has several variants, one of them this:
|
|||
#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?
|
||||
<br>The question is, who owns the zebra?
|
||||
|
||||
Additionally, list the solution for all the houses.
|
||||
Optionally, show the solution is unique.
|
||||
|
||||
cf. [[Dinesman's multiple-dwelling problem]], [[Twelve statements]]
|
||||
|
||||
;Related tasks:
|
||||
* [[Dinesman's multiple-dwelling problem]]
|
||||
* [[Twelve statements]]
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
(ns zebra
|
||||
(:require [clojure.math.combinatorics :as c]))
|
||||
|
||||
(defn solve
|
||||
[]
|
||||
(defn solve []
|
||||
(let [arrangements (c/permutations (range 5))
|
||||
before? #(= (inc %1) %2)
|
||||
after? #(= (dec %1) %2)
|
||||
|
|
@ -35,8 +34,7 @@
|
|||
(map zipmap [persons colors drinks cigs pets])))))
|
||||
|
||||
|
||||
(defn -main
|
||||
[& _]
|
||||
(defn -main [& _]
|
||||
(doseq [[[persons _ _ _ pets :as solution] i]
|
||||
(map vector (solve) (iterate inc 1))
|
||||
:let [zebra-house (some #(when (= :zebra (val %)) (key %)) pets)]]
|
||||
|
|
|
|||
74
Task/Zebra-puzzle/Elixir/zebra-puzzle.elixir
Normal file
74
Task/Zebra-puzzle/Elixir/zebra-puzzle.elixir
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
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)
|
||||
|
|
@ -1,28 +1,32 @@
|
|||
% populate domain by selecting from it
|
||||
attrs(H,[N-V|R]):- memberchk( N-X, H), X=V, % unique attribute names
|
||||
(R=[] -> true ; attrs(H,R)).
|
||||
one_of(HS,AS) :- member(H,HS), attrs(H,AS).
|
||||
two_of(HS,G,AS):- call(G,H1,H2,HS), maplist(attrs,[H1,H2],AS).
|
||||
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( Z, HS):-
|
||||
length( HS, 5),
|
||||
member( H1, HS), nation(H1, eng), color(H1, red),
|
||||
member( H2, HS), nation(H2, swe), owns( H2, dog),
|
||||
member( H3, HS), nation(H3, dane), drink(H3, tea),
|
||||
left_of(A,B, HS), color( A, green), color( B, white),
|
||||
member( H4, HS), drink( H4, coffee), color(H4, green),
|
||||
member( H5, HS), smoke( H5, palmal), owns( H5, birds),
|
||||
member( H6, HS), color( H6, yellow), smoke(H6, dunhill),
|
||||
middle( C, HS), drink( C, milk),
|
||||
first( D, HS), nation( D, norweg),
|
||||
next_to(E,F, HS), smoke( E, blend), owns( F, cats),
|
||||
next_to(G,H, HS), owns( G, horse), smoke( H, dunhill),
|
||||
member( H7, HS), smoke( H7, bluemas), drink(H7, beer),
|
||||
member( H8, HS), nation(H8, german), smoke(H8, prince),
|
||||
next_to(I,J, HS), nation( I, norweg), color( J, blue),
|
||||
next_to(V,W, HS), drink( W, water), smoke( V, blend),
|
||||
member( X, HS), owns( X, zebra), nation(X, Z).
|
||||
|
||||
zebra(Zebra,Houses):-
|
||||
Houses = [A,_,C,_,_], % 1
|
||||
maplist( one_of(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
|
||||
] ),
|
||||
two_of(Houses, left_of, [[color -green ], [color -white ]]), % 5
|
||||
maplist(attrs, [C,A], [[drink -milk ], [nation-norwegian]]), % 9, 10
|
||||
maplist(two_of(Houses,next_to),
|
||||
[ [[smoke -'Blend' ], [owns -cats ]] % 11
|
||||
, [[owns -horse ], [smoke-'Dunhill' ]] % 12
|
||||
, [[nation-norwegian], [color-blue ]] % 15
|
||||
, [[drink -water ], [smoke-'Blend' ]] % 16
|
||||
] ),
|
||||
one_of(Houses, [ owns-zebra, nation-Zebra]).
|
||||
left_of( A, B, HS):- append( _, [A,B|_], HS).
|
||||
next_to( A, B, HS):- left_of( A, B, HS) ; left_of( B, A, HS).
|
||||
middle( A, [_,_,A,_,_]).
|
||||
first( A, [A|_]).
|
||||
|
||||
attr( House, Name-Value):-
|
||||
memberchk( Name-X, House), % unique attribute names
|
||||
X = Value. % set, validate, or reject
|
||||
nation(H, V):- attr( H, nation-V).
|
||||
owns( H, V):- attr( H, owns-V). % select an attribute
|
||||
smoke( H, V):- attr( H, smoke-V). % from an extensible record
|
||||
color( H, V):- attr( H, color-V). % of house attributes
|
||||
drink( H, V):- attr( H, drink-V). % which *is* a house
|
||||
|
|
|
|||
|
|
@ -1,12 +1,32 @@
|
|||
?- time(( zebra(Z,HS), ( maplist(length,HS,_) -> maplist(sort,HS,S),
|
||||
maplist(writeln,S),nl,writeln(Z) ), false ; true)).
|
||||
attrs( R, [N-V|T]):- % extensible record, attribute specs
|
||||
memberchk( N-X, R), % unique attribute names
|
||||
X = V, % set, validate, or reject
|
||||
( T = [] -> true ; attrs( R, T) ).
|
||||
|
||||
[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]
|
||||
specs( P, Hs, [Spec1]) :- call(P, A, Hs), attrs(A, Spec1).
|
||||
specs( P, Hs, [Spec1, Spec2]) :- call(P, A, B, Hs), attrs(A, Spec1), attrs(B, Spec2).
|
||||
|
||||
german
|
||||
% 234,852 inferences, 0.100 CPU in 0.170 seconds (59% CPU, 2345143 Lips)
|
||||
true.
|
||||
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( Zebra, Houses):- % a house *is* a collection of attributes
|
||||
Houses = [A,_,C,_,_], % 1
|
||||
maplist( specs( member, 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
|
||||
] ),
|
||||
specs( left_of, Houses, [[color -green ], [color-white ]]), % 5
|
||||
maplist( attrs, [A, C], [[nation-norwegian], [drink-milk ]]), % 10, 9
|
||||
maplist( specs( next_to, Houses),
|
||||
[ [[smoke -'Blend' ], [owns -cats ]] % 11
|
||||
, [[owns -horse ], [smoke-'Dunhill' ]] % 12
|
||||
, [[nation-norwegian], [color-blue ]] % 15
|
||||
, [[drink -water ], [smoke-'Blend' ]] % 16
|
||||
] ),
|
||||
specs( member, Houses, [[ owns-zebra, nation-Zebra]]).
|
||||
|
|
|
|||
|
|
@ -1,45 +1,12 @@
|
|||
:- initialization(main).
|
||||
?- time(( zebra(Z,HS), ( maplist(length,HS,_) -> maplist(sort,HS,S),
|
||||
maplist(writeln,S), nl, writeln(Z) ), false ; true)).
|
||||
|
||||
[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]
|
||||
|
||||
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.
|
||||
german
|
||||
% 202,730 inferences, 0.031 CPU in 0.031 seconds (100% CPU, 6497715 Lips)
|
||||
true.
|
||||
|
|
|
|||
45
Task/Zebra-puzzle/Prolog/zebra-puzzle-5.pro
Normal file
45
Task/Zebra-puzzle/Prolog/zebra-puzzle-5.pro
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
:- 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.
|
||||
|
|
@ -1,101 +1,73 @@
|
|||
import psyco; psyco.full()
|
||||
from logpy import *
|
||||
from logpy.core import lall
|
||||
import time
|
||||
|
||||
class Content: elems= """Beer Coffee Milk Tea Water
|
||||
Danish English German Norwegian Swedish
|
||||
Blue Green Red White Yellow
|
||||
Blend BlueMaster Dunhill PallMall Prince
|
||||
Bird Cat Dog Horse Zebra""".split()
|
||||
class Test: elems= "Drink Person Color Smoke Pet".split()
|
||||
class House: elems= "One Two Three Four Five".split()
|
||||
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:]))
|
||||
|
||||
for c in (Content, Test, House):
|
||||
c.values = range(len(c.elems))
|
||||
for i, e in enumerate(c.elems):
|
||||
exec "%s.%s = %d" % (c.__name__, e, i)
|
||||
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)])
|
||||
|
||||
def finalChecks(M):
|
||||
def diff(a, b, ca, cb):
|
||||
for h1 in House.values:
|
||||
for h2 in House.values:
|
||||
if M[ca][h1] == a and M[cb][h2] == b:
|
||||
return h1 - h2
|
||||
assert False
|
||||
houses = var()
|
||||
|
||||
return abs(diff(Content.Norwegian, Content.Blue,
|
||||
Test.Person, Test.Color)) == 1 and \
|
||||
diff(Content.Green, Content.White,
|
||||
Test.Color, Test.Color) == -1 and \
|
||||
abs(diff(Content.Horse, Content.Dunhill,
|
||||
Test.Pet, Test.Smoke)) == 1 and \
|
||||
abs(diff(Content.Water, Content.Blend,
|
||||
Test.Drink, Test.Smoke)) == 1 and \
|
||||
abs(diff(Content.Blend, Content.Cat,
|
||||
Test.Smoke, Test.Pet)) == 1
|
||||
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)
|
||||
)
|
||||
|
||||
def constrained(M, atest):
|
||||
if atest == Test.Drink:
|
||||
return M[Test.Drink][House.Three] == Content.Milk
|
||||
elif atest == Test.Person:
|
||||
for h in House.values:
|
||||
if ((M[Test.Person][h] == Content.Norwegian and
|
||||
h != House.One) or
|
||||
(M[Test.Person][h] == Content.Danish and
|
||||
M[Test.Drink][h] != Content.Tea)):
|
||||
return False
|
||||
return True
|
||||
elif atest == Test.Color:
|
||||
for h in House.values:
|
||||
if ((M[Test.Person][h] == Content.English and
|
||||
M[Test.Color][h] != Content.Red) or
|
||||
(M[Test.Drink][h] == Content.Coffee and
|
||||
M[Test.Color][h] != Content.Green)):
|
||||
return False
|
||||
return True
|
||||
elif atest == Test.Smoke:
|
||||
for h in House.values:
|
||||
if ((M[Test.Color][h] == Content.Yellow and
|
||||
M[Test.Smoke][h] != Content.Dunhill) or
|
||||
(M[Test.Smoke][h] == Content.BlueMaster and
|
||||
M[Test.Drink][h] != Content.Beer) or
|
||||
(M[Test.Person][h] == Content.German and
|
||||
M[Test.Smoke][h] != Content.Prince)):
|
||||
return False
|
||||
return True
|
||||
elif atest == Test.Pet:
|
||||
for h in House.values:
|
||||
if ((M[Test.Person][h] == Content.Swedish and
|
||||
M[Test.Pet][h] != Content.Dog) or
|
||||
(M[Test.Smoke][h] == Content.PallMall and
|
||||
M[Test.Pet][h] != Content.Bird)):
|
||||
return False
|
||||
return finalChecks(M)
|
||||
t0 = time.time()
|
||||
solutions = run(0, houses, zebraRules)
|
||||
t1 = time.time()
|
||||
dur = t1-t0
|
||||
|
||||
def show(M):
|
||||
for h in House.values:
|
||||
print "%5s:" % House.elems[h],
|
||||
for t in Test.values:
|
||||
print "%10s" % Content.elems[M[t][h]],
|
||||
print
|
||||
count = len(solutions)
|
||||
zebraOwner = [house for house in solutions[0] if 'zebra' in house][0][0]
|
||||
|
||||
def solve(M, t, n):
|
||||
if n == 1 and constrained(M, t):
|
||||
if t < 4:
|
||||
solve(M, Test.values[t + 1], 5)
|
||||
else:
|
||||
show(M)
|
||||
return
|
||||
|
||||
for i in xrange(n):
|
||||
solve(M, t, n - 1)
|
||||
M[t][0 if n % 2 else i], M[t][n - 1] = \
|
||||
M[t][n - 1], M[t][0 if n % 2 else i]
|
||||
|
||||
def main():
|
||||
M = [[None] * len(Test.elems) for _ in xrange(len(House.elems))]
|
||||
for t in Test.values:
|
||||
for h in House.values:
|
||||
M[t][h] = Content.values[t * 5 + h]
|
||||
|
||||
solve(M, Test.Drink, 5)
|
||||
|
||||
main()
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -1,89 +1,101 @@
|
|||
from itertools import permutations
|
||||
import psyco
|
||||
psyco.full()
|
||||
import psyco; psyco.full()
|
||||
|
||||
class Number:elems= "One Two Three Four Five".split()
|
||||
class Color: elems= "Red Green Blue White Yellow".split()
|
||||
class Drink: elems= "Milk Coffee Water Beer Tea".split()
|
||||
class Smoke: elems= "PallMall Dunhill Blend BlueMaster Prince".split()
|
||||
class Pet: elems= "Dog Cat Zebra Horse Bird".split()
|
||||
class Nation:elems= "British Swedish Danish Norvegian German".split()
|
||||
class Content: elems= """Beer Coffee Milk Tea Water
|
||||
Danish English German Norwegian Swedish
|
||||
Blue Green Red White Yellow
|
||||
Blend BlueMaster Dunhill PallMall Prince
|
||||
Bird Cat Dog Horse Zebra""".split()
|
||||
class Test: elems= "Drink Person Color Smoke Pet".split()
|
||||
class House: elems= "One Two Three Four Five".split()
|
||||
|
||||
for c in (Number, Color, Drink, Smoke, Pet, Nation):
|
||||
for c in (Content, Test, House):
|
||||
c.values = range(len(c.elems))
|
||||
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
|
||||
def finalChecks(M):
|
||||
def diff(a, b, ca, cb):
|
||||
for h1 in House.values:
|
||||
for h2 in House.values:
|
||||
if M[ca][h1] == a and M[cb][h2] == b:
|
||||
return h1 - h2
|
||||
assert False
|
||||
|
||||
if not number or not color or not drink or not smoke or not pet:
|
||||
return True
|
||||
return abs(diff(Content.Norwegian, Content.Blue,
|
||||
Test.Person, Test.Color)) == 1 and \
|
||||
diff(Content.Green, Content.White,
|
||||
Test.Color, Test.Color) == -1 and \
|
||||
abs(diff(Content.Horse, Content.Dunhill,
|
||||
Test.Pet, Test.Smoke)) == 1 and \
|
||||
abs(diff(Content.Water, Content.Blend,
|
||||
Test.Drink, Test.Smoke)) == 1 and \
|
||||
abs(diff(Content.Blend, Content.Cat,
|
||||
Test.Smoke, Test.Pet)) == 1
|
||||
|
||||
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
|
||||
def constrained(M, atest):
|
||||
if atest == Test.Drink:
|
||||
return M[Test.Drink][House.Three] == Content.Milk
|
||||
elif atest == Test.Person:
|
||||
for h in House.values:
|
||||
if ((M[Test.Person][h] == Content.Norwegian and
|
||||
h != House.One) or
|
||||
(M[Test.Person][h] == Content.Danish and
|
||||
M[Test.Drink][h] != Content.Tea)):
|
||||
return False
|
||||
return True
|
||||
elif atest == Test.Color:
|
||||
for h in House.values:
|
||||
if ((M[Test.Person][h] == Content.English and
|
||||
M[Test.Color][h] != Content.Red) or
|
||||
(M[Test.Drink][h] == Content.Coffee and
|
||||
M[Test.Color][h] != Content.Green)):
|
||||
return False
|
||||
return True
|
||||
elif atest == Test.Smoke:
|
||||
for h in House.values:
|
||||
if ((M[Test.Color][h] == Content.Yellow and
|
||||
M[Test.Smoke][h] != Content.Dunhill) or
|
||||
(M[Test.Smoke][h] == Content.BlueMaster and
|
||||
M[Test.Drink][h] != Content.Beer) or
|
||||
(M[Test.Person][h] == Content.German and
|
||||
M[Test.Smoke][h] != Content.Prince)):
|
||||
return False
|
||||
return True
|
||||
elif atest == Test.Pet:
|
||||
for h in House.values:
|
||||
if ((M[Test.Person][h] == Content.Swedish and
|
||||
M[Test.Pet][h] != Content.Dog) or
|
||||
(M[Test.Smoke][h] == Content.PallMall and
|
||||
M[Test.Pet][h] != Content.Bird)):
|
||||
return False
|
||||
return finalChecks(M)
|
||||
|
||||
for j in xrange(5):
|
||||
if (color[i] == Color.Green and
|
||||
color[j] == Color.White and
|
||||
number[j] - number[i] != 1):
|
||||
return False
|
||||
def show(M):
|
||||
for h in House.values:
|
||||
print "%5s:" % House.elems[h],
|
||||
for t in Test.values:
|
||||
print "%10s" % Content.elems[M[t][h]],
|
||||
print
|
||||
|
||||
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
|
||||
def solve(M, t, n):
|
||||
if n == 1 and constrained(M, t):
|
||||
if t < 4:
|
||||
solve(M, Test.values[t + 1], 5)
|
||||
else:
|
||||
show(M)
|
||||
return
|
||||
|
||||
return True
|
||||
|
||||
def show_row(t, data):
|
||||
print "%6s: %12s%12s%12s%12s%12s" % (
|
||||
t.__name__, t.elems[data[0]],
|
||||
t.elems[data[1]], t.elems[data[2]],
|
||||
t.elems[data[3]], t.elems[data[4]])
|
||||
for i in xrange(n):
|
||||
solve(M, t, n - 1)
|
||||
M[t][0 if n % 2 else i], M[t][n - 1] = \
|
||||
M[t][n - 1], M[t][0 if n % 2 else i]
|
||||
|
||||
def main():
|
||||
perms = list(permutations(range(5)))
|
||||
M = [[None] * len(Test.elems) for _ in xrange(len(House.elems))]
|
||||
for t in Test.values:
|
||||
for h in House.values:
|
||||
M[t][h] = Content.values[t * 5 + h]
|
||||
|
||||
for number in perms:
|
||||
if is_possible(number, None, None, None, None):
|
||||
for color in perms:
|
||||
if is_possible(number, color, None, None, None):
|
||||
for drink in perms:
|
||||
if is_possible(number, color, drink, None, None):
|
||||
for smoke in perms:
|
||||
if is_possible(number, color, drink, smoke, None):
|
||||
for pet in perms:
|
||||
if is_possible(number, color, drink, smoke, pet):
|
||||
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
|
||||
solve(M, Test.Drink, 5)
|
||||
|
||||
main()
|
||||
|
|
|
|||
51
Task/Zebra-puzzle/Python/zebra-puzzle-3.py
Normal file
51
Task/Zebra-puzzle/Python/zebra-puzzle-3.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
from itertools import permutations
|
||||
|
||||
class Number:elems= "One Two Three Four Five".split()
|
||||
class Color: elems= "Red Green Blue White Yellow".split()
|
||||
class Drink: elems= "Milk Coffee Water Beer Tea".split()
|
||||
class Smoke: elems= "PallMall Dunhill Blend BlueMaster Prince".split()
|
||||
class Pet: elems= "Dog Cat Zebra Horse Bird".split()
|
||||
class Nation:elems= "British Swedish Danish Norvegian German".split()
|
||||
|
||||
for c in (Number, Color, Drink, Smoke, Pet, Nation):
|
||||
for i, e in enumerate(c.elems):
|
||||
exec "%s.%s = %d" % (c.__name__, e, i)
|
||||
|
||||
def show_row(t, data):
|
||||
print "%6s: %12s%12s%12s%12s%12s" % (
|
||||
t.__name__, t.elems[data[0]],
|
||||
t.elems[data[1]], t.elems[data[2]],
|
||||
t.elems[data[3]], t.elems[data[4]])
|
||||
|
||||
def main():
|
||||
perms = list(permutations(range(5)))
|
||||
for number in perms:
|
||||
if number[Nation.Norvegian] == Number.One: # Constraint 10
|
||||
for color in perms:
|
||||
if color[Nation.British] == Color.Red: # Constraint 2
|
||||
if number[color.index(Color.Blue)] == Number.Two: # Constraint 15+10
|
||||
if number[color.index(Color.White)] - number[color.index(Color.Green)] == 1: # Constraint 5
|
||||
for drink in perms:
|
||||
if drink[Nation.Danish] == Drink.Tea: # Constraint 4
|
||||
if drink[color.index(Color.Green)] == Drink.Coffee: # Constraint 6
|
||||
if drink[number.index(Number.Three)] == Drink.Milk: # Constraint 9
|
||||
for smoke in perms:
|
||||
if smoke[Nation.German] == Smoke.Prince: # Constraint 14
|
||||
if drink[smoke.index(Smoke.BlueMaster)] == Drink.Beer: # Constraint 13
|
||||
if smoke[color.index(Color.Yellow)] == Smoke.Dunhill: # Constraint 8
|
||||
if number[smoke.index(Smoke.Blend)] - number[drink.index(Drink.Water)] in (1, -1): # Constraint 16
|
||||
for pet in perms:
|
||||
if pet[Nation.Swedish] == Pet.Dog: # Constraint 3
|
||||
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()
|
||||
170
Task/Zebra-puzzle/REXX/zebra-puzzle.rexx
Normal file
170
Task/Zebra-puzzle/REXX/zebra-puzzle.rexx
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/* REXX ---------------------------------------------------------------
|
||||
* Solve the Zebra Puzzle
|
||||
*--------------------------------------------------------------------*/
|
||||
oid='zebra.txt'; 'erase' oid
|
||||
Call mk_perm /* compute all permutations */
|
||||
Call encode /* encode the elements of the specifucations */
|
||||
/* 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+=1
|
||||
End
|
||||
End /* animal_i */
|
||||
End
|
||||
End /* smoke_i */
|
||||
End
|
||||
End /* drink_i */
|
||||
End
|
||||
End /* colr_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 lineout(oid,arg(1))
|
||||
|
|
@ -1,13 +1,9 @@
|
|||
# Solve Zebra Puzzle.
|
||||
#
|
||||
# Nigel_Galloway
|
||||
# August 31st., 2014.
|
||||
CONTENT = { :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] }
|
||||
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)}
|
||||
|
|
@ -21,33 +17,38 @@ def coincident? (n,i,g,e)
|
|||
n.each_index.any?{|x| n[x]==i and g[x]==e}
|
||||
end
|
||||
|
||||
def solve
|
||||
def solve_zebra_puzzle
|
||||
CONTENT[:Nationality].permutation{|nation|
|
||||
next if nation.first != :Norwegian # 10
|
||||
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
|
||||
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
|
||||
next unless coincident?(nation, :Swedish, pet, :Dog) # 3
|
||||
CONTENT[:Drink].permutation{|drink|
|
||||
next if drink[2] != :Milk # 9
|
||||
next unless coincident?(nation,:Danish,drink,:Tea) # 4
|
||||
next unless coincident?(colour,:Green,drink,:Coffee) # 6
|
||||
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
|
||||
return [nation,colour,pet,drink,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
|
||||
res = solve
|
||||
width = CONTENT.map{|x| x.flatten.map{|y|y.to_s.size}.max}
|
||||
fmt = width.map{|w| "%-#{w}s"}.join(" ")
|
||||
puts "The Zebra is owned by the man who is #{res[0][res[2].find_index(:Zebra)]}",""
|
||||
puts fmt % CONTENT.keys, fmt % width.map{|w| "-"*w}
|
||||
res.transpose.each.with_index(1){|x,n| puts fmt % [n,*x]}
|
||||
|
||||
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
|
||||
|
|
|
|||
85
Task/Zebra-puzzle/Scala/zebra-puzzle-2.scala
Normal file
85
Task/Zebra-puzzle/Scala/zebra-puzzle-2.scala
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
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 strength 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()
|
||||
println(s"The ${solution(1)(solution(3).indexOf("Fish"))} owns the Fish")
|
||||
}
|
||||
|
||||
}
|
||||
249
Task/Zebra-puzzle/Standard-ML/zebra-puzzle.ml
Normal file
249
Task/Zebra-puzzle/Standard-ML/zebra-puzzle.ml
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
(* 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue