为啥我无法通过 Prolog 获得 Ship Puzzle 的答案?
Posted
技术标签:
【中文标题】为啥我无法通过 Prolog 获得 Ship Puzzle 的答案?【英文标题】:Why I can't get an answer for the Ship Puzzle with Prolog?为什么我无法通过 Prolog 获得 Ship Puzzle 的答案? 【发布时间】:2015-08-24 17:36:26 【问题描述】:我需要使用 Prolog 解决 Ship Puzzle 问题。 以下是事实。
有 5 艘船。
希腊船六点出发,载着咖啡。 中间的船有一个黑色的烟囱。 英国船九点出发。 蓝色烟囱的法国船位于运送咖啡的船的左侧。 载可可的船的右侧是一艘前往马赛的船。 巴西船正驶向马尼拉。 载米的船旁边是一艘带绿色烟囱的船。 去热那亚的船五点出发。 西班牙船七点出发,在前往马赛的船的右侧。 带红色烟囱的船驶往汉堡。 七点出发的船旁边是一艘带白色烟囱的船。 边境的船载着玉米。 黑色烟囱的船八点出发。 运送玉米的船锚定在运送大米的船旁边。 去汉堡的船六点出发。
哪艘船开往塞得港?哪艘船运茶?
我在互联网上搜索答案,但找不到任何答案。所以我参考了“斑马拼图”,因此我为这个问题安排了代码。所以这是我的 Prolog 代码的问题。
exists(A,(A,_,_,_,_)).
exists(A,(_,A,_,_,_)).
exists(A,(_,_,A,_,_)).
exists(A,(_,_,_,A,_)).
exists(A,(_,_,_,_,A)).
rightOf(A,B,(B,A,_,_,_)).
rightOf(A,B,(_,B,A,_,_)).
rightOf(A,B,(_,_,B,A,_)).
rightOf(A,B,(_,_,_,B,A)).
middleShip(A,(_,_,A,_,_)).
lastShip(A,(_,_,_,_,A)).
nextTo(A,B,(B,A,_,_,_)).
nextTo(A,B,(_,B,A,_,_)).
nextTo(A,B,(_,_,B,A,_)).
nextTo(A,B,(_,_,_,B,A)).
nextTo(A,B,(A,B,_,_,_)).
nextTo(A,B,(_,A,B,_,_)).
nextTo(A,B,(_,_,A,B,_)).
nextTo(A,B,(_,_,_,A,B)).
solution(PortSaidShip, TeaCarrier) :-
Shipes = (ship(_,_,_,_,_),ship(_,_,_,_,_),ship(_,_,_,_,_),ship(_,_,_,_,_),ship(_,_,_,_,_)),
exists(ship('Greek',6,'Coffee',_,_),Shipes),
middleShip(ship(_,_,_,_,'Black',_),Shipes),
exists(ship('English',9,_,_,_),Shipes),
rightOf(ship(_,_,'Coffee',_,_),ship('French',_,_,'Blue',_),Shipes),
rightOf(ship(_,_,_,_,'Marseille'),ship(_,_,'Cocoa',_,_),Shipes),
exists(ship('Brazilian',_,_,_,'Manila'),Shipes),
nextTo(ship(_,_,_,'Green',_),ship(_,_,'Rice',_,_),Shipes),
exists(ship(_,5,_,_,'Genoa'),Shipes),
rightOf(ship('Spanish',7,_,_,_),ship(_,_,_,_,'Marseille'),Shipes),
exists(ship(_,_,_,'Red','Hamburg'),Shipes),
nextTo(ship(_,_,_,'White',_),ship(_,7,_,_,_),Shipes),
lastShip(ship(_,_,'Corn',_,_),Shipes),
exists(ship(_,8,_,'Black',_),Shipes),
nextTo(ship(_,_,'Corn',_,_),ship(_,_,'Rice',_,_),Shipes),
exists(ship(_,6,_,_,'Hamburg'),Shipes),
exists(ship(PortSaidShip,_,_,_,'Port Said'),Shipes),
exists(ship(TeaCarrier,_,'Tea',_,_),Shipes).
但是当我运行程序时它会说'false'。那么我该如何解决这个问题呢?谢谢
【问题讨论】:
您正在执行的返回 'false' 的 exact 查询是什么? 尝试分析解决方案的子目标。如果您有规则solution :- A, B, C, D, E.
,它可能会失败,因为A
失败,或B
失败,或...,或E
失败。尝试检查各个目标以及它们给您带来的结果。
@MartynA:由于使用所有其他定义的唯一谓词的最一般查询已经失败,因此只能是那个查询。
@false:我们可能有不同的目的。您假设 OP 试图执行什么查询?
solution(PortSaidShip, TeaCarrier)
这是最通用的一个。也就是说,任何更具体的方法也会失败。
【参考方案1】:
你问:
那我该如何解决呢?
以下是一种通用方法,它始终适用于像您这样的纯单调 Prolog 程序。您的实际问题是特定目标应该成功,但它失败了。所以你得到了一个意外失败。为了本地化您程序的负责部分,我们现在将系统地概括您的程序。一步步。直到我们有一个很小的程序片段。这种技术有时称为程序切片,有时称为程序修改。
首先,将以下内容添加到您的代码中:
:- op(950, fy, *).
*_.
:- initialization(solution(_Port, _Carrier)).
现在我们将通过在其前面添加 *
来逐个删除目标,然后重新运行您的程序。所以准备好你将重新运行你的程序几次。要加载程序,请在顶层输入:
?- [shipes].
这几乎适用于任何地方,例如 SICStus、GNU、SWI、YAP。您现在将收到有关“失败指令”或类似内容的警告。所以 - 开心点 - 因为您现在可以轻松重现问题!
开始在最后一个目标处添加 *
。你可以一次尝试几个。
要在修改后重新加载,您可以重新输入该目标,或者
在 SICStus 中,更好的状态 ensure_loaded(shipes).
这会检查文件是否已被修改,只有在重新加载后才会重新运行
在 SWI 中,输入 make.
最后得到如下程序片段:
中间船(A,(_,_,A,_,_))。 解决方案(PortSaidShip,TeaCarrier):- 船舶 = (船舶(_,_,_,_,_),船舶(_,_,_,_,_),船舶(_,_,_,_,_),船舶(_,_,_, _,_),船(_,_,_,_,_)), *所以你需要看懂四行代码才能理解你的问题!
正如其他人已经指出的那样,问题是一旦您使用ship/6
和在其他情况下使用ship/5
。
另外一句话:(_,_,_,A,B)
最好写成[_,_,_,A,B]
,这是常用的列表表示法。
【讨论】:
为什么不使用 % ? "Why not use %": 单例变量警告,.
之前的最后一个目标不能这样处理,也不能用圆括号括起来。
是的,看起来是合法的。一些问题可以通过 /* */ 解决,但是通常情况下 cmets 可能会导致新问题,在其他编程语言中也是如此。【参考方案2】:
第二行(在解谓词之后)术语ship(...)
的参数数量是错误的。它是:
middleShip(ship(_,_,_,_,'Black',_),Shipes),
应该是这样的:
middleShip(ship(_,_,_,'Black',_),Shipes),
我没有检查这是否有效,但这肯定会导致您的求解器失败。
【讨论】:
建议更正后,?- solution(PortSaidShip, TeaCarrier). PortSaidShip = 'Spanish', TeaCarrier = 'French' ; false.
以上是关于为啥我无法通过 Prolog 获得 Ship Puzzle 的答案?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我无法通过 Web 套接字连接获得 HubCallerContext 用户?
为啥我无法通过普通浏览器请求获得 ajax 请求的响应? [复制]