我需要使用Prolog解决Ship Puzzle问题。以下是事实。
有5艘船。
- 希腊船6点出发,载着咖啡。
- 中间的船有一个黑色的烟囱。
英国船九点钟启航。- 有蓝色烟囱的法国船在一艘运送咖啡的船的左边。
- 可可船的右边是一艘开往马赛的船。
- 巴西船驶往马尼拉。
- 运输大米的船旁边是一艘有绿色烟囱的船。
- 一艘开往热那亚的船5点出发。
- 西班牙船7点出发,在开往马赛的船的右侧。
- 有红色烟囱的船驶往汉堡。
- 7点出发的船旁边是一艘有白色烟囱的船。
- 边境上的船运载玉米。
- 有黑色烟囱的船在八点离开。
- 运载玉米的船停靠在运载大米的船旁边。
- 开往汉堡的船6点启航。
哪条船去塞得港?哪条船运茶?
我在网上搜索答案,但我找不到任何。所以我参考了"斑马拼图",并据此安排了这个问题的代码。所以这就是我的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'。
我该如何解决这个问题呢?
谢谢
你问:
那么我怎么解决这个问题呢?
下面是一个通用的方法,它总是适用于像您这样的纯单调Prolog程序。你的实际问题是,一个特定的目标应该成功,但它失败了。所以你得到了一个意外的失败。为了使您的程序中负责的部分本地化,我们现在将系统地概括您的程序。一步一步来。直到我们得到一个小小的程序片段。这种技术称为有时程序切片和有时程序修改。
首先,在你的代码中添加以下代码::- op(950, fy, *).
*_.
:- initialization(solution(_Port, _Carrier)).
现在我们将通过在其前面添加 *
来删除一个又一个目标,然后重新运行您的程序。因此,要准备好您将多次重新运行您的程序。要加载程序,请在顶层输入:
?- [shipes].
这几乎在任何地方都有效,比如在SICStus、GNU、SWI、YAP中。您现在将得到一个关于"失败的指令"或类似的警告。所以-高兴吧-你现在可以轻松地重现这个问题了!
开始在最后一个目标处添加 *
。你可以一次试几个。要在修改后重新加载,您可以重新输入该目标,或者
在SICStus中,更好的状态
ensure_loaded(shipes).
这检查文件是否已被修改,只有在重新加载 时才重新运行它在SWI中输入
make.
所以你需要理解四行代码来理解你的问题!
正如其他人已经指出的那样,问题是一旦您使用ship/6
而在其他情况下使用ship/5
。
另一个注意事项:(_,_,_,A,B)
最好写成[_,_,_,A,B]
,这是常用的列表表示法。
第二行(在解谓词之后)中术语ship(...)
的参数数是错误的。它是:
middleShip(ship(_,_,_,_,'Black',_),Shipes),
而它应该是:
middleShip(ship(_,_,_,'Black',_),Shipes),
我还没有检查这是否有效,但这肯定会导致您的求解器失败