在 Prolog 中使用约束和排列解决难题
Posted
技术标签:
【中文标题】在 Prolog 中使用约束和排列解决难题【英文标题】:Solving puzzle using constraints and permutations in Prolog 【发布时间】:2018-08-01 19:55:07 【问题描述】:我被要求使用 Prolog 解决一个类似于斑马谜题的谜题。相反,我试图找出吃馅饼的人的国籍。我知道这个问题有不同的解决方案,但是我试图通过使用约束和排列来解决这个难题。但是,运行 pie_eater 谓词会返回 false,并且在跟踪代码时它不会停止运行。
约束列表如下:
1) the Irish person lives next to the yellow house
2) the person who likes donuts lives next to the person who enjoys embroidery
3) the person who enjoys trainspotting lives next to the one who likes pizza
4) the person who enjoys pachinko likes beets
5) the Czech lives in the purple house
6) the person living in the center house listens to grunge
7) the person who enjoys glassblowing listens to hip hop
8) the American likes tofu
9) the Dutch person listens to J-Pop
10) the pink house's owner listens to country
11) the owner of the green house enjoys embroidery
12) the Irish person lives in the first house
13) the pink house is on the left of the orange house
14) the Japanese person enjoys gardening
15) the person who enjoys trainspotting has a neighbor who listens to jazz
在我的代码中,我定义了一个列表 Street,其中包含 5 座房屋。然后,我为列表中每个元素的每个对应形容词定义变量,以用于我的排列猜测。我将每个约束都翻译成代码。为了生成答案,我为每所房子的每组变量创建了排列。 在底部,我定义了谓词 leftof 和 nextto 以满足问题的一些约束。
代码如下:
%who eats pie
pie_eater(PieEater) :-
puzzle(X),
member(house(PieEater, _, _, _, pie), X).
puzzle(Street) :-
Street = [H1, H2, H3, H4, H5], %street of 5 houses
%vars for permutation
H1 = house(Nat1, Col1, Mus1, Hob1, Food1),
H2 = house(Nat2, Col2, Mus2, Hob2, Food2),
H3 = house(Nat3, Col3, Mus3, Hob3, Food3),
H4 = house(Nat4, Col4, Mus4, Hob4, Food4),
H5 = house(Nat5, Col5, Mus5, Hob5, Food5),
% facts
nextto(house(irish, _, _, _, _), house(_, yellow, _, _, _), Street), %irish next to yellow house
nextto(house(_, _, _, _, donuts), house(_, _, _, embroidery, _), Street), %donut next to embrodier lover
nextto(house(_, _, _, trainspotting, _), house(_, _, _, _, pizza), Street), %trainspotting next to pizza ouse
member(house(_, _, _, pachinko, beets), Street), %pachinko person eats beets
member(house(czech, purple, _, _, _), Street), %czech person lives in purple house
[_, _, house(_, _, grunge, _, _), _, _] = Street, %middle house listens to grunge
member(house(_, _, hiphop, glassblowing, _), Street), %hiphop lover likes glassblowing
member(house(american, _, _, _, tofu), Street), %american likes tofu
member(house(dutch, _, jpop, _, _), Street), %dutch person likes jpop
member(house(_, pink, country, _, _), Street), %pink house person likes country music
member(house(_, green, _, embroidery, _), Street), %green house person likes embroidery
[house(irish, _, _, _, _), _, _, _, _] = Street, %irish person in first house
leftof(house(_, pink, _, _, _),house(_, orange, _, _, _), Street), %pink house left of orange house
member(house(japanese, _, _, gardening, _), Street), %japanese person likes gardening
member(house(_, _, jazz, trainspotting, _), Street), %trainspotting person likes jazz
member(house(_, _, _, _, pie), Street), %one person likes pie
%permutation guesses
permutation([irish, czech, american, dutch, japanese],[Nat1, Nat2, Nat3, Nat4, Nat5]), %nat permutations
permutation([yellow, purple, pink, green, orange],[Col1, Col2, Col3, Col4, Col5]), %color permutations
permutation([grunge, hiphop, jpop, country, jazz],[Mus1, Mus2, Mus3, Mus4, Mus5]), %music permutation
permutation([trainspotting, pachinko, glassblowing, embroidery, gardening],[Hob1, Hob2, Hob3, Hob4, Hob5]), %hobby permutation
permutation([donuts, beets, pizza, tofu, pie],[Food1, Food2, Food3, Food4, Food5]). %food permutation
%defining other predicates to help solve puzzle
nextto(X, Y, List) :- leftof(X, Y, List).
nextto(X, Y, List) :- leftof(Y, X, List).
%check if left of
leftof(L, R, [L,R|_]).
leftof(L, R, [_ | Rest]) :- leftof(L, R, Rest).
盯着我的代码几个小时,我觉得它应该可以工作,但是我仍然无法弄清楚为什么我不能生成正确的排列,因为我已经定义了所有的约束。在这一点上我被卡住了。
自己做题,我相信日本人就是答案。
【问题讨论】:
【参考方案1】:约束 15 未正确表示。改成
nextto(house(_, _, _, trainspotting, _), house(_, _, jazz, _, _), Street)
允许代码工作。
【讨论】:
【参考方案2】:这是我过去使用的代码:
?- puzzle(Who), write(Who), nl, fail.
first(H,[H|_]).
on_the_left(X,Y,[X,Y|_]).
on_the_left(X,Y,[_|Hs]) :- on_the_left(X,Y,Hs).
next_to(X,Y,[X,Y|_]).
next_to(X,Y,[Y,X|_]).
next_to(X,Y,[_|Hs]) :- next_to(X,Y,Hs).
middle(X,[_,_,X,_,_]).
puzzle(Who) :-
Houses = [
house(Nationality, Colour, Music, Hobby, Food),
house(_, _, _, _, _),
house(_, _, _, _, _),
house(_, _, _, _, _),
house(_, _, _, _, _)],
next_to(house(irish, _, _, _, _), house( _, yellow, _, _, _), Houses), % 01) the Irish person lives next to the yellow house
next_to(house(_, _, _, _, donuts), house( _, _, _, embroidery, _), Houses), % 02) the person who likes donuts lives next to the person who enjoys embroidery
next_to(house(_, _, _, trainspotting, _), house( _, _, _, _, pizza), Houses), % 03) the person who enjoys trainspotting lives next to the one who likes pizza
member(house(_, _, _, pachinko, beets), Houses), % 04) the person who enjoys pachinko likes beets
member(house(czech, purple, _, _, _), Houses), % 05) the Czech lives in the purple house
middle(house(_, _, grunge, _, _), Houses), % 06) the person living in the center house listens to grunge
member(house(_, _, hiphop, glassblowing, _), Houses), % 07) the person who enjoys glassblowing listens to hip hop
member(house(american, _, _, _, tofu), Houses), % 08) the American likes tofu
member(house(dutch, _, jpop, _, _), Houses), % 09) the Dutch person listens to J-Pop
member(house(_, pink, country, _, _), Houses), % 10) the pink house's owner listens to country
member(house(_, green, _, embroidery, _), Houses), % 11) the owner of the green house enjoys embroidery
first(house(irish, _, _, _, _), Houses), % 12) the Irish person lives in the first house
on_the_left(house(_, pink, _, _, _), house(_, orange, _, _, _), Houses), % 13) the pink house is on the left of the orange house
member(house(japanese, _, _, gardening, _), Houses), % 14) the Japanese person enjoys gardening
next_to(house(_, _, _, trainspotting, _), house( _, _, jazz, _, _), Houses), % 15) the person who enjoys trainspotting has a neighbor who listens to jazz
member(house(Who, _, _, _, pie), Houses),
write(Houses), nl.
输出:
[房子(爱尔兰,绿色,爵士,刺绣,比萨),房子(荷兰,黄色,jpop,trainspotting,甜甜圈),房子(捷克,紫色,垃圾,弹球,甜菜),房子(日本,粉红色,乡村,园艺,馅饼),房子(美国,橙子,嘻哈,吹玻璃,豆腐)] 日本人【讨论】:
【参考方案3】:用调试器运行你的代码,看起来这部分从来没有成功过。
member(house(_, _, jazz, trainspotting, _), Street),
调用时,变量的内容为:
H1 = house(irish, green, Mus1, embroidery, pizza)
H2 = house(dutch, yellow, jpop, trainspotting, donuts)
H3 = house(czech, purple, grunge, pachinko, beets)
H4 = house(japanese, pink, country, gardening, Food4)
H5 = house(american, orange, hiphop, glassblowing, tofu)
这些信息有帮助吗? derpnallday 的建议可能是真的(我不知道为什么他的回答被低估了。)
顺便说一句,我曾经使用 clpfd 解决了另一个斑马问题。
以下版本的谜题出现在 1962 年的 Life International:
有五间房子。 英国人住在红房子里。 西班牙人拥有这只狗。 咖啡是在温室里喝的。 乌克兰人喝茶。 温室就在象牙屋的右侧。 老黄金吸烟者拥有蜗牛。 库尔斯在黄色的房子里抽烟。 牛奶是在中间屋喝的。 挪威人住在第一间房子里。 抽切斯特菲尔德烟的那个人住在养狐狸的人旁边的房子里。 在养马的房子旁边的房子里抽烟。 幸运罢工吸烟者喝橙汁。 日本人抽议会。 挪威人住在蓝屋旁边。 现在,谁喝水?谁拥有斑马?
为了清楚起见,必须补充的是,五座房屋中的每一座都涂有不同的颜色,其居民具有不同的民族血统,拥有不同的宠物,喝不同的饮料并抽不同品牌的美国香烟[原文如此]。另一件事:在陈述 6 中,权利意味着您的权利。
:-use_module(library(clpfd)).
zebra_prob:-
% left ------> right
House=[Color1,Color2,Color3,Color4,Color5],
Pet=[Pet1,Pet2,Pet3,Pet4,Pet5],
Race=[Race1,Race2,Race3,Race4,Race5],
Drink=[Bev1,Bev2,Bev3,Bev4,Bev5],
Smoke=[Cig1,Cig2,Cig3,Cig4,Cig5],
% Race 1:English 2:Spaniard 3:Ukrainian 4:Norwegian 5:Japanese
% HouseColor 1:red 2:green 3:ivory 4:yellow 5:blue
% Pet 1:dog 2:snails 3:fox 4:horse 5:zebra
% Drink 1:coffee 2:tea 3:milk 4:orange juice 5:water
% Smoke 1:Old Gold 2:Kool 3:Chesterfields 4:Lucky Strike 5:Parliaments
all_different(House), %house
all_different(Pet), %pet
all_different(Race), %country
all_different(Drink), %drink
all_different(Smoke), %smoke
House ins 1..5,
Pet ins 1..5,
Race ins 1..5,
Drink ins 1..5,
Smoke ins 1..5,
% The Englishman(1) lives in the red house(1).
Race1 #= 1 #<==> Color1 #= 1,
Race2 #= 1 #<==> Color2 #= 1,
Race3 #= 1 #<==> Color3 #= 1,
Race4 #= 1 #<==> Color4 #= 1,
Race5 #= 1 #<==> Color5 #= 1,
% The Spaniard(2) owns the dog(1).
Race1 #= 2 #<==> Pet1 #= 1,
Race2 #= 2 #<==> Pet2 #= 1,
Race3 #= 2 #<==> Pet3 #= 1,
Race4 #= 2 #<==> Pet4 #= 1,
Race5 #= 2 #<==> Pet5 #= 1,
% Coffee(1) is drunk in the green house(2).
Bev1 #= 1 #<==> Color1 #= 2,
Bev2 #= 1 #<==> Color2 #= 2,
Bev3 #= 1 #<==> Color3 #= 2,
Bev4 #= 1 #<==> Color4 #= 2,
Bev5 #= 1 #<==> Color5 #= 2,
% The Ukrainian(3) drinks tea(2).
Race1 #= 3 #<==> Bev1 #= 2,
Race2 #= 3 #<==> Bev2 #= 2,
Race3 #= 3 #<==> Bev3 #= 2,
Race4 #= 3 #<==> Bev4 #= 2,
Race5 #= 3 #<==> Bev5 #= 2,
% The green house(2) is immediately to the right of the ivory house(3).
Color1 #= 3 #<==> Color2 #= 2 ,
Color2 #= 3 #<==> Color3 #= 2 ,
Color3 #= 3 #<==> Color4 #= 2 ,
Color4 #= 3 #<==> Color5 #= 2 ,
% So, green house(2) is not leftmost.
Color1 #\= 2,
% The Old Gold(1) smoker owns snails(2).
Cig1 #= 1 #<==> Pet1 #= 2,
Cig2 #= 1 #<==> Pet2 #= 2,
Cig3 #= 1 #<==> Pet3 #= 2,
Cig4 #= 1 #<==> Pet4 #= 2,
Cig5 #= 1 #<==> Pet5 #= 2,
% Kools(2) are smoked in the yellow(4) house.
Cig1 #= 2 #<==> Color1 #= 4,
Cig2 #= 2 #<==> Color2 #= 4,
Cig3 #= 2 #<==> Color3 #= 4,
Cig4 #= 2 #<==> Color4 #= 4,
Cig5 #= 2 #<==> Color5 #= 4,
% Milk(3) is drunk in the middle house.
Bev3 #= 3,
% The Norwegian(4) lives in the first house. (I assume that "first" means leftmost)
Race1 #= 4,
% The man who smokes Chesterfields(3) lives in the house next to the man with the fox(3).
(Cig1 #= 3 #/\ Pet2 #= 3) #\/
(Cig2 #= 3 #/\ Pet3 #= 3) #\/
(Cig3 #= 3 #/\ Pet4 #= 3) #\/
(Cig4 #= 3 #/\ Pet5 #= 3) #\/
(Pet1 #= 3 #/\ Cig2 #= 3) #\/
(Pet2 #= 3 #/\ Cig3 #= 3) #\/
(Pet3 #= 3 #/\ Cig4 #= 3) #\/
(Pet4 #= 3 #/\ Cig5 #= 3) ,
% Kools(2) are smoked in the house next to the house where the horse(4) is kept.
(Cig1 #= 2 #/\ Pet2 #= 4) #\/
(Cig2 #= 2 #/\ Pet3 #= 4) #\/
(Cig3 #= 2 #/\ Pet4 #= 4) #\/
(Cig4 #= 2 #/\ Pet5 #= 4) #\/
(Pet1 #= 4 #/\ Cig2 #= 2) #\/
(Pet2 #= 4 #/\ Cig3 #= 2) #\/
(Pet3 #= 4 #/\ Cig4 #= 2) #\/
(Pet4 #= 4 #/\ Cig5 #= 2) ,
% The Lucky Strike(4) smoker drinks orange juice(4).
Cig1 #= 4 #<==> Bev1 #= 4,
Cig2 #= 4 #<==> Bev2 #= 4,
Cig3 #= 4 #<==> Bev3 #= 4,
Cig4 #= 4 #<==> Bev4 #= 4,
Cig5 #= 4 #<==> Bev5 #= 4,
% The Japanese(5) smokes Parliaments(5).
Race1 #= 5 #<==> Cig1 #= 5,
Race2 #= 5 #<==> Cig2 #= 5,
Race3 #= 5 #<==> Cig3 #= 5,
Race4 #= 5 #<==> Cig4 #= 5,
Race5 #= 5 #<==> Cig5 #= 5,
% The Norwegian(4) lives next to the blue house(5).
(Race1 #= 4 #/\ Color2 #= 5) #\/
(Race2 #= 4 #/\ Color3 #= 5) #\/
(Race3 #= 4 #/\ Color4 #= 5) #\/
(Race4 #= 4 #/\ Color5 #= 5) #\/
(Color1 #= 5 #/\ Race2 #= 4) #\/
(Color2 #= 5 #/\ Race3 #= 4) #\/
(Color3 #= 5 #/\ Race4 #= 4) #\/
(Color4 #= 5 #/\ Race5 #= 4) ,
label(House),
label(Pet),
label(Race),
label(Smoke),
label(Drink),
write('house:'),write(House),nl,
write('pet:'),write(Pet),nl,
write('race:'),write(Race),nl,
write('drink:'),write(Drink),nl,
write('smoke:'),write(Smoke),nl,nl.
[3] 23 ?- zebra_prob.
house:[4,5,1,3,2]
pet:[3,4,2,1,5]
race:[4,3,1,2,5]
drink:[5,2,3,4,1]
smoke:[2,3,1,4,5]
true ;
false.
% Race 1:English 2:Spaniard 3:Ukrainian 4:Norwegian 5:Japanese
% HouseColor 1:red 2:green 3:ivory 4:yellow 5:blue
% Pet 1:dog 2:snails 3:fox 4:horse 5:zebra
% Drink 1:coffee 2:tea 3:milk 4:orange juice 5:water
% Smoke 1:Old Gold 2:Kool 3:Chesterfields 4:Lucky Strike 5:Parliaments
Now, who drinks water? Who owns the zebra?
5:water is drunk by 4:Norwegian
5:zebra is tamed by 5:Japanese
【讨论】:
以上是关于在 Prolog 中使用约束和排列解决难题的主要内容,如果未能解决你的问题,请参考以下文章
在 CLPQ/R (Prolog) 中解决一个简单的几何难题