Prolog 中的逻辑难题 - 使用列表
Logic Puzzle in Prolog - using lists
我试图在 Prolog 中解决以下问题,我认为我的编码是正确的,但我的查询只是 return 错误。关于更改内容的任何建议?问题如下:
“当地的百吉饼店 Bagel Alley 一直是一个令人愤怒的地方 activity
早上上下班路上,人们停下来买咖啡和百吉饼
工作方式。每天早上现场新鲜制作的百吉饼非常受欢迎,
事实上,这家商店也有很棒的咖啡,就像锦上添花!人民
在 Bagel Alley 工作的人都很开朗友好,也很能干,所以
尽管顾客众多,但等待的时间从不会很长或令人不快。乔
他的四个同事今天早上路过来看看每个人都在做什么
赞不绝口,惊喜地发现这家商店不负众望
名声。确定每个同事的名字,什么样的百吉饼
浇头,以及每种咖啡的口味和大小(小、中或大)。"
布拉德得到了他的百吉饼,它不是小麦,上面什么也没有。 Walt 点了一杯小咖啡。
得到中杯咖啡的两个同事一个得到了榛子味的,另一个得到了花生百吉饼
黄油.
得到洋葱百吉饼但没有加黄油的那个,还得到了法式香草咖啡,但不是小杯。
五个同事是乔,一个拿了一大杯咖啡,一个拿了杏仁味咖啡,一个拿了小麦百吉饼,
还有那个在他的百吉饼上放了鸡蛋和培根的人。
瑞克没有点蓝莓百吉饼,但他点了哥伦比亚咖啡。 Amaretto 咖啡是和切达百吉饼一起点的,但是
不是沃尔特。
蓝莓百吉饼没有配奶油芝士,但配了一大杯咖啡。芝麻百吉饼配黄油但是
卡洛斯没点。
我写的Prolog代码在这里:
bagels(Sol):-
Sol = [[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_]],
member([brad,X,plain,_,_], Sol), X \== wheat,
member([walt,_,_,small,_], Sol),
member([_,_,_,medium1,hazelnut], Sol),
member([_,_,peanut_butter,medium2,_], Sol),
member([_,onion,Y,Z,french_vanilla], Sol), Y \== butter, Z \== small,
member([joe,Ja,Jb,Jc,Jd], Sol),Ja\==wheat,Jb\==egg_bacon,Jc\==large,Jd==amaretto,
member([La,Lb,Lc,large,Ld], Sol), La\==joe,Lb\==wheat,Lc\==egg_bacon,Ld\==amaretto,
member([Aa,Ab,Ac,Ad,amaretto], Sol), Aa\==joe,Ab\==wheat,Ac\==egg_bacon,Ad\==large,
member([Wa,wheat,Wb,Wc,Wd], Sol), Wa\==joe,Wb\==egg_bacon,Wc\==large,Wd\==amaretto,
member([Ea,Eb,egg_bacon,Ec,Ed], Sol), Ea\==joe,Eb\==wheat,Ec\==large,Ed\==amaretto,
member([rick,R,_,_,columbian], Sol),R\==blueberry,
member([A,cheddar,_,_,amaretto], Sol), A\==walt,
member([_,B,cream_cheese,large,_], Sol), B\==blueberry,
member([C,sesame,butter,_,_], Sol), C \== carlos,
member([_,_,_,other,_], Sol),
member([_,_,_,_,other], Sol).
我相信 运行 查询 "bagels(X)." 应该给我解决问题的方法,但它 return 是错误的。我错过了什么吗?非常感谢!
首先,问题陈述似乎需要一些审查 - 特别是第 4 点。
你这里有一个合乎逻辑的谜题。因此你真的需要坚持 Prolog 的逻辑部分。但是,在您的代码中,我看到 (\==)/2
和 (==)/2
两者都没有完全实现它们假装表示的逻辑关系。相反,请分别使用 dif/2
和 (=)/2
。
但即使替换了那些,情况也好不到哪里去,你的程序仍然失败。但是,通过纯粹的定义,您有机会 本地化 问题。你的问题是 bagels(Sols)
失败了。因此,目前的定义过于专业、过于狭隘。因此,我将尝试通过删除您的一些要求来概括它。为此,我会在你的一些目标前加上*
。我将概括它们,使得生成的程序仍然失败。
剩下的是一个概括,向您展示您将在哪里修改您的程序。否则,错误将一直存在。
编辑:我强调了在我看来特别奇怪的地方:两个男人在喝杏仁酒。
:- op(950, fy, *).
*_.
bagels(Sol):-
Sol = [[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_]],
member([brad,X,plain,_,_], Sol),
dif(X,wheat),
member([walt,_,_,small,_], Sol),
member([_,_,_,medium1,hazelnut], Sol),
* member([_,_,peanut_butter,medium2,_], Sol),
member([_,onion,Y,Z,french_vanilla], Sol),
* dif(Y,butter),
dif(Z,small),
member([joe,Ja,Jb,Jc,Jd], Sol),
* dif(Ja,wheat), * dif(Jb,egg_bacon),
dif(Jc,large),
Jd=amaretto,
* member([La,Lb,Lc,large,Ld], Sol),
* dif(La,joe), * dif(Lb,wheat), * dif(Lc,egg_bacon), * dif(Ld,amaretto),
member([Aa,Ab,Ac,Ad,amaretto], Sol),
dif(Aa,joe),
* dif(Ab,wheat), * dif(Ac,egg_bacon), * dif(Ad,large),
member([Wa,wheat,Wb,Wc,Wd], Sol),
* dif(Wa, joe), * dif(Wb, egg_bacon),
dif(Wc, large),
dif(Wd, amaretto),
member([Ea,Eb,egg_bacon,Ec,Ed], Sol),
* dif(Ea, joe),
dif(Eb, wheat),
* dif(Ec, large),
dif(Ed, amaretto),
member([rick,R,_,_,columbian], Sol),
* dif(R,blueberry),
* member([A,cheddar,_,_,amaretto], Sol),
* dif(A,walt),
member([_,B,cream_cheese,large,_], Sol),
* dif(B,blueberry),
* member([C,sesame,butter,_,_], Sol),
* dif(C, carlos),
* member([_,_,_,other,_], Sol),
* member([_,_,_,_,other], Sol).
不过,您可能会不高兴:为什么还剩下这么多代码?这样做的原因是你忘记在开始时陈述一些一般性的观察结果。特别是他们想要所有不同的浇头。有了这些信息,程序片段就会缩小到只有突出显示的行。但是,必须使用 library(lambda)
.
从以下目标开始
bagels(Sol):-
Sol = [[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_]],
maplist(Sol+\P^member([P|_], Sol),
[brad,walt,joe,rick,carlos]),
maplist(Sol+\D^member([_,_,_,_,D], Sol),
[amaretto,french_vanilla,hazelnut,columbian,other]),
...
我试图提高可读性,使用 DCG 来传递状态(在 this page 中查找 'Implicitly passing states around'),因此此代码段与您的解决方案非常不同。
可以看到negative知识有两种不同的表达方式:涉及到人的地方,我们可以直接使用\=
,因为名字总是实例化的,但是对于其他值,比如 kind(brad, K)
,我使用 {dif(K, wheat)}
,因为 K 还没有被实例化。
state(S), [state(T)] --> [state(T)], {member(S, T)}.
kind(P, K) --> state([P, K, _, _, _]).
topping(P, T) --> state([P, _, T, _, _]).
flavor(P, F) --> state([P, _, _, F, _]).
size(P, S) --> state([P, _, _, _, S]).
hint1 -->
kind(brad, K), {dif(K, wheat)}, topping(brad, plain), size(walt, small).
hint2 -->
size(P1, medium), size(P2, medium), {P1 \= P2},
flavor(P1, hazelnut), topping(P2, peanut_butter).
hint3 -->
kind(P, onion), flavor(P, french_vanilla), size(P, S), {dif(S, small)}.
hint4 -->
size(P1, large), flavor(P2, amaretto), kind(P3, wheat), topping(P4, egg_bacon),
{forall(select(X, [joe,P1,P2,P3,P4], Ps), maplist(\=(X), Ps))}.
hint5 -->
kind(rick, K), {dif(K, blueberry)}, flavor(rick, columbian),
kind(P, cheddar), flavor(P, amaretto), {P \= walt}.
hint6 -->
topping(P1, cream_cheese), kind(P2, blueberry), {P1 \= P2}, size(P1, large),
kind(P, sesame), topping(P, butter), {P \= carlos}.
bagels(Sol):- Sol =
[[brad,_,_,_,_],
[walt,_,_,_,_],
[joe,_,_,_,_],
[rick,_,_,_,_],
[carlos,_,_,_,_]],
phrase((hint1, hint2, hint3, hint4, hint5, hint6), [state(Sol)], _).
唉,我得到了太多的解决方案...也许我的提示翻译中存在错误,或者 all_different 也应该应用于所有属性,就像提示 n.4 所做的那样
?- aggregate(count,S^bagels(S),N).
N = 7.
我试图在 Prolog 中解决以下问题,我认为我的编码是正确的,但我的查询只是 return 错误。关于更改内容的任何建议?问题如下:
“当地的百吉饼店 Bagel Alley 一直是一个令人愤怒的地方 activity 早上上下班路上,人们停下来买咖啡和百吉饼 工作方式。每天早上现场新鲜制作的百吉饼非常受欢迎, 事实上,这家商店也有很棒的咖啡,就像锦上添花!人民 在 Bagel Alley 工作的人都很开朗友好,也很能干,所以 尽管顾客众多,但等待的时间从不会很长或令人不快。乔 他的四个同事今天早上路过来看看每个人都在做什么 赞不绝口,惊喜地发现这家商店不负众望 名声。确定每个同事的名字,什么样的百吉饼 浇头,以及每种咖啡的口味和大小(小、中或大)。"
布拉德得到了他的百吉饼,它不是小麦,上面什么也没有。 Walt 点了一杯小咖啡。
得到中杯咖啡的两个同事一个得到了榛子味的,另一个得到了花生百吉饼 黄油.
得到洋葱百吉饼但没有加黄油的那个,还得到了法式香草咖啡,但不是小杯。
五个同事是乔,一个拿了一大杯咖啡,一个拿了杏仁味咖啡,一个拿了小麦百吉饼, 还有那个在他的百吉饼上放了鸡蛋和培根的人。
瑞克没有点蓝莓百吉饼,但他点了哥伦比亚咖啡。 Amaretto 咖啡是和切达百吉饼一起点的,但是 不是沃尔特。
蓝莓百吉饼没有配奶油芝士,但配了一大杯咖啡。芝麻百吉饼配黄油但是 卡洛斯没点。
我写的Prolog代码在这里:
bagels(Sol):-
Sol = [[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_]],
member([brad,X,plain,_,_], Sol), X \== wheat,
member([walt,_,_,small,_], Sol),
member([_,_,_,medium1,hazelnut], Sol),
member([_,_,peanut_butter,medium2,_], Sol),
member([_,onion,Y,Z,french_vanilla], Sol), Y \== butter, Z \== small,
member([joe,Ja,Jb,Jc,Jd], Sol),Ja\==wheat,Jb\==egg_bacon,Jc\==large,Jd==amaretto,
member([La,Lb,Lc,large,Ld], Sol), La\==joe,Lb\==wheat,Lc\==egg_bacon,Ld\==amaretto,
member([Aa,Ab,Ac,Ad,amaretto], Sol), Aa\==joe,Ab\==wheat,Ac\==egg_bacon,Ad\==large,
member([Wa,wheat,Wb,Wc,Wd], Sol), Wa\==joe,Wb\==egg_bacon,Wc\==large,Wd\==amaretto,
member([Ea,Eb,egg_bacon,Ec,Ed], Sol), Ea\==joe,Eb\==wheat,Ec\==large,Ed\==amaretto,
member([rick,R,_,_,columbian], Sol),R\==blueberry,
member([A,cheddar,_,_,amaretto], Sol), A\==walt,
member([_,B,cream_cheese,large,_], Sol), B\==blueberry,
member([C,sesame,butter,_,_], Sol), C \== carlos,
member([_,_,_,other,_], Sol),
member([_,_,_,_,other], Sol).
我相信 运行 查询 "bagels(X)." 应该给我解决问题的方法,但它 return 是错误的。我错过了什么吗?非常感谢!
首先,问题陈述似乎需要一些审查 - 特别是第 4 点。
你这里有一个合乎逻辑的谜题。因此你真的需要坚持 Prolog 的逻辑部分。但是,在您的代码中,我看到 (\==)/2
和 (==)/2
两者都没有完全实现它们假装表示的逻辑关系。相反,请分别使用 dif/2
和 (=)/2
。
但即使替换了那些,情况也好不到哪里去,你的程序仍然失败。但是,通过纯粹的定义,您有机会 本地化 问题。你的问题是 bagels(Sols)
失败了。因此,目前的定义过于专业、过于狭隘。因此,我将尝试通过删除您的一些要求来概括它。为此,我会在你的一些目标前加上*
。我将概括它们,使得生成的程序仍然失败。
剩下的是一个概括,向您展示您将在哪里修改您的程序。否则,错误将一直存在。
编辑:我强调了在我看来特别奇怪的地方:两个男人在喝杏仁酒。
:- op(950, fy, *). *_. bagels(Sol):- Sol = [[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_]], member([brad,X,plain,_,_], Sol), dif(X,wheat), member([walt,_,_,small,_], Sol), member([_,_,_,medium1,hazelnut], Sol), *member([_,_,peanut_butter,medium2,_], Sol), member([_,onion,Y,Z,french_vanilla], Sol), *dif(Y,butter), dif(Z,small), member([joe,Ja,Jb,Jc,Jd], Sol), *dif(Ja,wheat), *dif(Jb,egg_bacon), dif(Jc,large), Jd=amaretto, *member([La,Lb,Lc,large,Ld], Sol), *dif(La,joe), *dif(Lb,wheat), *dif(Lc,egg_bacon), *dif(Ld,amaretto), member([Aa,Ab,Ac,Ad,amaretto], Sol), dif(Aa,joe), *dif(Ab,wheat), *dif(Ac,egg_bacon), *dif(Ad,large), member([Wa,wheat,Wb,Wc,Wd], Sol), *dif(Wa, joe), *dif(Wb, egg_bacon), dif(Wc, large), dif(Wd, amaretto), member([Ea,Eb,egg_bacon,Ec,Ed], Sol), *dif(Ea, joe), dif(Eb, wheat), *dif(Ec, large), dif(Ed, amaretto), member([rick,R,_,_,columbian], Sol), *dif(R,blueberry), *member([A,cheddar,_,_,amaretto], Sol), *dif(A,walt), member([_,B,cream_cheese,large,_], Sol), *dif(B,blueberry), *member([C,sesame,butter,_,_], Sol), *dif(C, carlos), *member([_,_,_,other,_], Sol), *member([_,_,_,_,other], Sol).
不过,您可能会不高兴:为什么还剩下这么多代码?这样做的原因是你忘记在开始时陈述一些一般性的观察结果。特别是他们想要所有不同的浇头。有了这些信息,程序片段就会缩小到只有突出显示的行。但是,必须使用 library(lambda)
.
bagels(Sol):-
Sol = [[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_],[_,_,_,_,_]],
maplist(Sol+\P^member([P|_], Sol),
[brad,walt,joe,rick,carlos]),
maplist(Sol+\D^member([_,_,_,_,D], Sol),
[amaretto,french_vanilla,hazelnut,columbian,other]),
...
我试图提高可读性,使用 DCG 来传递状态(在 this page 中查找 'Implicitly passing states around'),因此此代码段与您的解决方案非常不同。
可以看到negative知识有两种不同的表达方式:涉及到人的地方,我们可以直接使用\=
,因为名字总是实例化的,但是对于其他值,比如 kind(brad, K)
,我使用 {dif(K, wheat)}
,因为 K 还没有被实例化。
state(S), [state(T)] --> [state(T)], {member(S, T)}.
kind(P, K) --> state([P, K, _, _, _]).
topping(P, T) --> state([P, _, T, _, _]).
flavor(P, F) --> state([P, _, _, F, _]).
size(P, S) --> state([P, _, _, _, S]).
hint1 -->
kind(brad, K), {dif(K, wheat)}, topping(brad, plain), size(walt, small).
hint2 -->
size(P1, medium), size(P2, medium), {P1 \= P2},
flavor(P1, hazelnut), topping(P2, peanut_butter).
hint3 -->
kind(P, onion), flavor(P, french_vanilla), size(P, S), {dif(S, small)}.
hint4 -->
size(P1, large), flavor(P2, amaretto), kind(P3, wheat), topping(P4, egg_bacon),
{forall(select(X, [joe,P1,P2,P3,P4], Ps), maplist(\=(X), Ps))}.
hint5 -->
kind(rick, K), {dif(K, blueberry)}, flavor(rick, columbian),
kind(P, cheddar), flavor(P, amaretto), {P \= walt}.
hint6 -->
topping(P1, cream_cheese), kind(P2, blueberry), {P1 \= P2}, size(P1, large),
kind(P, sesame), topping(P, butter), {P \= carlos}.
bagels(Sol):- Sol =
[[brad,_,_,_,_],
[walt,_,_,_,_],
[joe,_,_,_,_],
[rick,_,_,_,_],
[carlos,_,_,_,_]],
phrase((hint1, hint2, hint3, hint4, hint5, hint6), [state(Sol)], _).
唉,我得到了太多的解决方案...也许我的提示翻译中存在错误,或者 all_different 也应该应用于所有属性,就像提示 n.4 所做的那样
?- aggregate(count,S^bagels(S),N).
N = 7.