Prolog中的逻辑难题 - 使用列表

时间:2016-04-15 15:50:38

标签: prolog zebra-puzzle program-slicing

我正在尝试解决Prolog中的以下问题,我认为我已将其编码正确,但我的查询只是返回false。关于改变什么的任何建议?问题如下:

" Bagel Alley,当地的百吉饼店,在此过程中始终是一个激烈的活动场所 上午通勤,因为人们停下来喝咖啡和面包圈 工作方式。每天早上新鲜制作,百吉饼非常受欢迎 事实上,这家商店也有很棒的咖啡,就像锦上添花!人民 在Bagel Alley工作的人既开朗又友好,也很有能力 尽管客户数量很大,但等待时间并不长或令人不愉快。乔 今天早上他的四个同事停下来看看每个人都是谁 发现并且惊喜地发现这家商店辜负了它 声誉。确定每个同事的名字,用什么样的百吉饼 打顶,以及每种咖啡的口味和大小(小,中或大)。"

  1. 布拉德得到了他的百吉饼,这不是小麦,没有任何东西。沃尔特点了一杯小咖啡。

  2. 两个喝中等咖啡的同事是榛子风味的人和拿着花生的百吉饼的人 黄油。

  3. 那个拿着洋葱百吉饼而不是黄油的人也买了法国香草咖啡,但不是那么小。

  4. 五个同事是Joe,一个拿着大咖啡的人,一个拿着Amaretto风味的咖啡,一个拿着小麦面包的人, 和那个得到鸡蛋和蛋的人培根在他的百吉饼上。

  5. Rick没有订购蓝莓面包圈,但他确实得到了哥伦比亚咖啡。 Amaretto咖啡是用切达干酪面包卷订购的 不是沃尔特。

  6. 奶油奶酪没有配蓝莓百吉饼,但确实带有一大杯咖啡。芝麻百吉饼配黄油但是 卡洛斯没有点它。

  7. 我写的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)。"应该给我解决问题的方法,但它返回false。我错过了什么吗?非常感谢提前!

2 个答案:

答案 0 :(得分:3)

首先,似乎问题陈述需要一些审查 - 特别是第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]),
    ...

答案 1 :(得分:1)

我尝试提高可读性,使用DCG传递状态(查找'隐式传递this page中的状态),所以这个代码段与你的解决方案。

您可以看到否定知识以两种不同的方式表达:人们参与其中,我们可以直接使用\=,因为名称总是被实例化,但是对于其他值,例如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.