Prolog逻辑测试示例

时间:2012-10-02 15:05:08

标签: prolog logic zebra-puzzle

我有一个关于Prolog的测试,我无法真正掌握它的基本思想。我有点理解我经历过的一些例子,但我不能坐下来知道如何解决具体问题。

我们的教授给了我们一些例子,我想知道是否有人可以告诉我如何做到这一点所以我有一些想法如何处理这样的事情。

这个例子来自我们的书:

Donna, Danny, David, and Doreen were seated at a table. 
The men sat across from each other, as did the women. 
They each ordered a different drink and main course.

Facts:

Doreen sat beside the person that ordered steak
The chicken came with a coke
The person with lasagna sat across from the person with milk
David never drinks coffee
Donna only drinks water
Danny could not afford to order steak

我尝试过每个人都有一个与他们相关的列表的东西,你会填充事实,但我不认为这是正确的方法。能有人带我走过这个吗?谢谢!

编辑:

这是我最终得到的代码,它完成了大部分拼图,它留下了一个主菜和一个饮料,但这应该是可以解决的:

  sat_across([X,_,Y,_], X, Y).
  sat_across([_,X,_,Y], X, Y).

  sat_beside(T, X, Y) :-  % this is tricky
      nth1(N,T,X), nth1(M,T,Y),
      (N =:= M+1 ; N =:= M-1 ; N == 1, M == 4 ; N == 4, M == 1).
      not_connected(T, Place) :- \+ member(Place, T).
  connected(T, Place) :- member(Place, T).

  solve(T) :- T = [_,_,_,_],
      sat_across(T, (danny,_,_), (david,_,_)),
      sat_across(T, (donna,_,_), (doreen,_,_)),
      sat_beside(T, (doreen,_,_), (_,_,steak)),
      connected(T, (_,coke,chicken)),
      sat_across(T, (_,_,lasagna), (_,milk,_)),
      not_connected(T, (david,coffee,_)),
      connected(T, (donna,water,_)),
      not_connected(T, (danny,_,steak)).

3 个答案:

答案 0 :(得分:0)

你应该认识到这个问题有八个变量:每个人的饮料和主菜,所以DonnaDrinkDannyFood等等。

根据给出的事实,您的程序应该使用=\=将这八个变量排除在外,可能使用额外的谓词,例如gender

(这实际上是zebra puzzle的一个简单变体,但没有全部排序。)

答案 1 :(得分:0)

使用模式匹配,每个位置都带有属性三元组:名称,饮料,食物。

然后我们有一个[N,S,W,E]表(滥用合约Bridge约定),我们必须应用所有可用的约束:我认为可以这样做......

sat_across([X,_,Y,_], X, Y).
sat_across([_,X,_,Y], X, Y).
sat_across([X,_,Y,_], Y, X).
sat_across([_,X,_,Y], Y, X).

sat_beside(T, X, Y) :-  % this is tricky
    nth1(N,T,X), nth1(M,T,Y),
    (N =:= M+1 ; N =:= M-1 ; N == 1, M == 4 ; N == 4, M == 1).

cant_afford(T, Place) :- \+ member(Place, T).

solve(T) :- T = [N,S,W,E],
      sat_across(T, (danny,_,_), (david,_,_)),
      sat_across(T, (donna,_,_), (doreen,_,_)),
      sat_beside(T, (doreen,_,_), (_,_,steak)),
      ....
      cant_afford(T, (danny,_,steak)),
      ....

答案 2 :(得分:0)

很抱歉,如果我正在追问这个帖子,但我对答案并不满意(他们看起来不够优雅/不完整)。

这是Zebra问题的变种。唯一真正的问题是“X在哪个位置”,其中X可以是人,主菜或饮料。因此,您的域名为{1,2,3,4},其中每个数字代表一个席位。

然后添加约束,确保每个项目相对于其类型的其他项目处于唯一位置(即,一个人只能在1个座位上等),并设置prolog松散。

哦,别忘了把你的负面约束放在最后。这就是我最终的结果:

%  Organize the seating, so:
%  1  2
%  3  4
%  This means that "across" is always (n+2)%4
%  and "beside" is (n+1)%2

pos(1). pos(2). pos(3). pos(4).

beside(A,B) :- pos(A), B is (A+1) mod 2.
across(A,B) :- pos(A), B is (A+2) mod 4.

zebra(Donna,Danny,David,Doreen,
     Steak,Lasagna,Pizza,Chicken,
     Coke,Milk,Coffee,Water) :-
  % Our 4 given positive constraints
  beside(Doreen,Steak),
  Chicken=Coke,
  across(Lasagna,Milk),
  Donna=Water,
  % The men and women sat across from each other
  across(David,Danny),
  across(Doreen,Donna),
  % Ensure that each item is only in 1 position
  uniq_pos(Steak,Lasagna,Pizza,Chicken),
  uniq_pos(Coke,Milk,Coffee,Water),
  uniq_pos(Donna,Danny,David,Doreen),
  % The remaining two negative constraints.
  \+ David=Coffee,
  \+ Danny=Steak.

% Ensures that all 4 items are in unique positions.
uniq_pos(A,B,C,D) :-
  pos(A), pos(B), pos(C), pos(D),
  \+ A=B, \+ A=C, \+ A=D,
          \+ B=C, \+ B=D,
                  \+ C=D.

似乎工作。 Prolog告诉我:
1号位的大卫得到了牛排和牛奶 在座位2中,多琳得到了鸡肉和可乐 3号位的Danny拿到烤宽面条和咖啡 4号位的Donna得到了披萨和水。

希望这可以帮助那些试图理解这个问题的人。