Erlang helps you solve the "zebra puzzle" problem

Source: Internet
Author: User

The zebra puzzle is a typical constraint satisfaction problem (CSPs). Sudoku, Magic Square also belongs to CSPs problem. The language features of Erlang's list parsing allow it to solve such problems in a way that is very close to the natural language: it does not need to consider the process-solving steps to describe the constraints, and the Erlang interpreter matches the answer through a domain search. Someone has also used Erlang to write an extension to a finite domain constraint (finite domain Constraints).





Using Erlang's list parsing to generate all third-order magic squares is so simple:





% Magicsquare.erl





-module (Magicsquare).


-export ([magicsquare/0]).





Magicsquare ()->


[{A00, A01, A02, A10, A11, A12, A20, A21, A22} | |


A00 <-lists:seq (1, 9),


A01 <-lists:seq (1, 9)--[A00],


A02 <-lists:seq (1, 9)--[A00, A01],


A10 <-lists:seq (1, 9)--[A00, A01, A02],


A11 <-lists:seq (1, 9)--[A00, A01, A02, A10],


A12 <-lists:seq (1, 9)--[A00, A01, A02, A10, A11],


A20 <-lists:seq (1, 9)--[A00, A01, A02, A10, A11, A12],


A21 <-lists:seq (1, 9)--[A00, A01, A02, A10, A11, A12, A20],


A22 <-lists:seq (1, 9)--[A00, A01, A02, A10, A11, A12, A20, A21],





% of each line is 15


A00 + A01 + A02 =:= 15,


A10 + A11 + A12 =:= 15,


A20 + A21 + A22 =:= 15,





% of each column is 15


A00 + A10 + A20 =:= 15,


A01 + A11 + A21 =:= 15,


A02 + A12 + A22 =:= 15,





% of percent diagonal and 15


A00 + A11 + A22 =:= 15,


A02 + A11 + A20 =:= 15


].





Since the famous Zebra puzzle and magic square are the same type of problem, it is arguably not a difficult task to write a solution program in Erlang. Post the zebra issue first:





Five Men of different nationality (England, Spain, Japan, Italy, Norway) live in the The the the the "a street." They all have a profession (painter, diplomat, violinist, doctor, sculptor), one animal (dog, Zebra, fox, snail, hors e), and one favorite drink (juice, water, tea, coffee, milk), all different from the others. Each of the houses are painted in a color different to others (green, red, yellow, blue, white).





Furthermore:





The Englishman lives in the Red House.


The Spaniard owns the dog.


The Japanese is the painter.


The Italian likes tea.


The Norwegian lives in the leftmost house.


The owner of the Green House likes coffee.


The green house was to the right, the white one.


The sculptor breeds snails.


The diplomat lives in the Yellow House.


Milk is drunk into the third house.


The Norwegian ' s house was next to the blue one.


The violinist likes juice.


The "Fox is" in "house" next to the doctor's house.


The horse is in the house next to the diplomat ' s.





The problem is thus to infer who owns zebra drinks.





For the convenience of program description problems, first for nationalities, occupations, colours, pets, beverages these five items are mapped to 1~5 these several numbers go:


House:l to R 1 2 3 4 5


Nation England Spain Japan Italy Norway


profession painter diplomat violinist doctor sculptor


Color Green red Yellow blue white


Animal dog zebra fox snail Horse


Drink Juice Water Tea coffee milk





Then you can use Erlang to describe the problem:





% Zebra.erl version 1


-module (Zebra).


-compile (Export_all).





Perms ([])-> [[]];


Perms (L)-> [[h| T] | | H <-L, T <-perms (L--[h])].





Full_perms (N)->


Perms (Lists:seq (1, N)).





Zebra ()->


[{N, C, P, A, D} | |


N <-full_perms (5),


C <-full_perms (5),


P <-full_perms (5),


A <-full_perms (5),


D <-full_perms (5),


Lists:nth (1, N) =:= lists:nth (2, C),% condition 1


Lists:nth (2, N) =:= lists:nth (1, A),% condition 2


Lists:nth (3, N) =:= lists:nth (1, P),% condition 3


Lists:nth (4, N) =:= lists:nth (3, D),% condition 4


Lists:nth (5, N) =:= 1,% condition 5


Lists:nth (1, C) =:= lists:nth (4, D),% condition 6


Lists:nth (5, C) + 1 =:= lists:nth (1, c),% condition 7


Lists:nth (5, P) =:= lists:nth (4, A),% condition 8


Lists:nth (2, P) =:= lists:nth (3, C),% condition 9


Lists:nth (5, D) =:= 3,% condition 10


(((Lists:nth (5, N) + 1) =:= Lists:nth (4, C)) OrElse ((Lists:nth (4, C) + 1) =:= Lists:nth (5, N)),% condition 11


Lists:nth (3, P) =:= lists:nth (1, D),% condition 12


((Lists:nth (3, a) + 1) =:= lists:nth (4, p)) OrElse ((Lists:nth (4, p) + 1) =:= Lists:nth (3, a)),% condition 13


((Lists:nth (5, a) + 1) =:= lists:nth (2, p)) OrElse ((Lists:nth (2, p) + 1) =:= Lists:nth (5, a))% condition 14


].





Compile run:





$ erl


1> C (Zebra).


{OK, zebra}


2> Zebra:zebra ().


[{[3,4,5,2,1],


[5,3,1,2,4],


[5,1,4,2,3],


[4,5,1,3,2],


[4,1,2,5,3]}]





Yes, a few twenty or thirty lines of code (mostly in terms of constraints) can solve the correct answer. But it was running so slowly that it took about two hours on my machine! And the answer also needs to manually map the numbers to the corresponding attributes.





To solve the slow problem first: Remember the construction and interpretation of computer programs SICP exercise 4.39? The order of the constraints does not affect the answer, but it affects the size of the search scope when the program executes, resulting in a huge difference in the order in which different constraints are run. Putting a strong constraint on the front will significantly reduce the search scope and reduce the running time. Adjust the above zebra to solve the code, immediately solve the answer:





% Zebra.erl Version2


-module (Zebra).


-compile (Export_all).





Perms ([])-> [[]];


Perms (L)-> [[h| T] | | H <-L, T <-perms (L--[h])].





Full_perms (N)->


Perms (Lists:seq (1, N)).





Zebra ()->


[{N, C, P, A, D} | |


N <-full_perms (5),


Lists:nth (5, N) =:= 1,% condition 5


C <-full_perms (5),


(((Lists:nth (5, N) + 1) =:= Lists:nth (4, C)) OrElse ((Lists:nth (4, C) + 1) =:= Lists:nth (5, N)),% condition 11


Lists:nth (1, N) =:= lists:nth (2, C),% condition 1


Lists:nth (5, C) + 1 =:= lists:nth (1, c),% condition 7


P <-full_perms (5),


Lists:nth (3, N) =:= lists:nth (1, P),% condition 3


Lists:nth (2, P) =:= lists:nth (3, C),% condition 9


A <-full_perms (5),


Lists:nth (2, N) =:= lists:nth (1, A),% condition 2


Lists:nth (5, P) =:= lists:nth (4, A),% condition 8


((Lists:nth (3, a) + 1) =:= lists:nth (4, p)) OrElse ((Lists:nth (4, p) + 1) =:= Lists:nth (3, a)),% condition 13


((Lists:nth (5, a) + 1) =:= lists:nth (2, p)) OrElse ((Lists:nth (2, p) + 1) =:= Lists:nth (5, a)),% condition 14


D <-full_perms (5),


Lists:nth (5, D) =:= 3,% condition 10


Lists:nth (4, N) =:= lists:nth (3, D),% condition 4


Lists:nth (1, C) =:= lists:nth (4, D),% condition 6


Lists:nth (3, P) =:= lists:nth (1, D)% condition 12


].





Solve the performance problems, and then to improve the program, in the program mapping a variety of properties, so that you can better describe the constraints of the condition. The complete Erlang code is as follows:





% Zebra.erl final version


-module (Zebra).


-export ([zebra/0, zebra_print/0, who_own_zebra/0]).





% percent @spec (list::list (), Ele)-> integer ()


% @doc Returns the position of ' Ele ' in the ' List '. 0 is returned


%% when ' Ele ' isn't found.


% percent @end


POS (List, Ele)->


POS (List, Ele, 1).


POS ([Ele | _tail], Ele, POS)->


Pos;


POS ([_ | Tail], Ele, Pos)->


POS (Tail, Ele, pos+1);


POS ([], _ele, _)->


0.





Nation ()-> [' England ', ' Spain ', ' Japan ', ' Italy ', ' Norway '].


Profession ()-> [painter, diplomat, violinist, doctor, sculptor].


Color ()-> [Green, red, yellow, blue, white].


Animal ()-> [Dog, Zebra, fox, snail, horse].


Drink ()-> [Juice, water, tea, coffee, milk].





Data_inx (N, Data)->


Lists:nth (N, Data ()).





Data_pos (Name, Data)->


POS (Data (), Name).





Perms ([])-> [[]];


Perms (L)-> [[h| T] | | H <-L, T <-perms (L--[h])].





Full_perms (N)->


Perms (Lists:seq (1, N)).





Zebra_print ()->


[Io:format ("Nation:tt~-12s~-12s~-12s~-12s~-12s~n"


"Color:tt~-12s~-12s~-12s~-12s~-12s~n"


"Profession:t~-12s~-12s~-12s~-12s~-12s~n"


"Animal:tt~-12s~-12s~-12s~-12s~-12s~n"


"Drink:tt~-12s~-12s~-12s~-12s~-12s~n~n",


[Data_inx (POS (N, 1), Fun nation/0),


Data_inx (POS (N, 2), fun nation/0),


Data_inx (POS (N, 3), fun nation/0),


Data_inx (POS (N, 4), Fun nation/0),


Data_inx (POS (N, 5), fun nation/0),





Data_inx (POS (C, 1), Fun color/0),


Data_inx (POS (C, 2), fun color/0),


Data_inx (POS (C, 3), fun color/0),


Data_inx (POS (C, 4), Fun color/0),


Data_inx (POS (C, 5), fun color/0),





Data_inx (POS (P, 1), Fun profession/0),


Data_inx (POS (P, 2), fun profession/0),


Data_inx (POS (P, 3), fun profession/0),


Data_inx (POS (P, 4), Fun profession/0),


Data_inx (POS (P, 5), fun profession/0),





Data_inx (POS (A, 1), Fun animal/0),


Data_inx (POS (A, 2), fun animal/0),


Data_inx (POS (A, 3), fun animal/0),


Data_inx (POS (A, 4), Fun animal/0),


Data_inx (POS (A, 5), fun animal/0),





Data_inx (POS (D, 1), Fun drink/0),


Data_inx (POS (D, 2), fun drink/0),


Data_inx (POS (D, 3), fun drink/0),


Data_inx (POS (D, 4), Fun drink/0),


Data_inx (POS (D, 5), Fun drink/0)] | |


{N, C, P, A, D} <-Zebra ()


].





Who_own_zebra ()->


[Data_inx (POS (N, POS (A, Data_pos (Zebra, fun animal/0)), fun nation/0) | |


{N, _c, _p, A, _d} <-Zebra ()


].





Zebra ()->


[{N, C, P, A, D} | |


N <-full_perms (5),





%% The Norwegian lives in the leftmost house


Lists:nth (Data_pos (' Norway ', fun nation/0), N) =:= 1,





C <-full_perms (5),





%% of the Norwegian ' s house are next to the blue one


(((Lists:nth (Data_pos (' Norway ', fun nation/0), N) + 1) =:=


Lists:nth (Data_pos (blue, fun color/0), C) OrElse


((Lists:nth (4, C) + 1) =:= Lists:nth (5, N)),





%% The Englishman lives in the Red House


Lists:nth (Data_pos (' England ', fun nation/0), N) =:=


Lists:nth (Data_pos (red, fun color/0), C),





%% of the "green house" to "right" of the white one


Lists:nth (Data_pos (white, fun color/0), C) + 1 =:=


Lists:nth (Data_pos (green, fun color/0), C),





P <-full_perms (5),





%% of the Japanese is the painter


Lists:nth (Data_pos (' Japan ', fun nation/0), N) =:=


Lists:nth (Data_pos (painter, fun profession/0), P),





A <-full_perms (5),





%% The Spaniard owns the dog


Lists:nth (Data_pos (' Spain ', fun nation/0), N) =:=


Lists:nth (Data_pos (dog, Fun animal/0), A),





%% of the sculptor breeds snails


Lists:nth (Data_pos (sculptor, fun profession/0), P) =:=


Lists:nth (Data_pos (snail, fun animal/0), A),





D <-full_perms (5),





%% The diplomat lives in the yellow House


Lists:nth (Data_pos (diplomat, fun profession/0), P) =:=


Lists:nth (Data_pos (yellow, fun color/0), C),





% of the "Fox is" in "house" next to the Doctor ' s house


(((Lists:nth (Data_pos (Fox, Fun animal/0), A) + 1) =:=


Lists:nth (Data_pos (doctor, Fun profession/0), P) OrElse


((Lists:nth (Data_pos (doctor, Fun profession/0), P) + 1) =:=


Lists:nth (Data_pos (Fox, Fun animal/0), A)),





%% of the horse is in the house next to the diplomat ' s


(((Lists:nth (Data_pos (horse, Fun animal/0), A) + 1) =:=


Lists:nth (Data_pos (diplomat, fun profession/0), P) OrElse


((Lists:nth (Data_pos (diplomat, fun profession/0), P) + 1) =:=


Lists:nth (Data_pos (horse, Fun animal/0), A)),





% Milk is drunk in the third house


Lists:nth (Data_pos (milk, fun drink/0), D) =:= 3,





%% The Italian likes tea


Lists:nth (Data_pos (' Italy ', fun nation/0), N) =:=


Lists:nth (Data_pos (tea, fun drink/0), D),





%% of the owner of the Green house likes coffee


Lists:nth (Data_pos (green, fun color/0), C) =:=


Lists:nth (Data_pos (coffee, fun drink/0), D),





%% of the violinist likes juice


Lists:nth (Data_pos (violinist, fun profession/0), P) =:=


Lists:nth (Data_pos (juice, fun drink/0), D)


].





Compile run:





$ erl


>1 C (Zebra).


{OK, zebra}


>2 Zebra:zebra_print ().


Nation:norway Italy England Spain Japan


Color:yellow Blue Red White green


Profession:diplomat doctor sculptor violinist painter


Animal:fox horse snail Dog zebra


Drink:water Tea milk Juice coffee





[OK]


>3 Zebra:who_own_zebra ().


[' Japan ']

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.