我在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)).
使用模式匹配,每个位置都带有一个属性三重:名称,饮料,食物。
然后我们有一个 [N,S,W,E] 表(滥用合同桥约定),我们必须应用所有可用的约束:我认为可以这样做......
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)),
....
你应该认识到这个问题有八个变量:每个人的饮料和主菜,所以DonnaDrink
、DannyFood
等。
你的程序应该根据给出的事实,用=
和=
来反对这八个变量,也许使用额外的谓词,如gender
。
(这实际上是斑马拼图的简单变体,但没有所有的排序。
如果我正在死灵这个线程,但我对答案并不满意(它们似乎不优雅/不完整)。
这是斑马问题的一个变体。唯一真正的问题是"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号座位上的丹尼得到了千层面和咖啡,
坐在4号座位上的唐娜得到了披萨和水。
希望这有助于其他试图理解这个问题的人。