为什么我无法用 Prolog 得到 Ship Puzzle 的答案?

Why I can't get an answer for the Ship Puzzle with Prolog?

我需要使用 Prolog 解决 Ship Puzzle 问题。 这是事实。

There are 5 ships.

  1. The Greek ship leaves at six and carries coffee.
  2. The Ship in the middle has a black chimney.
  3. The English ship leaves at nine.
  4. The French ship with blue chimney is to the left of a ship that carries coffee.
  5. To the right of the ship carrying cocoa is a ship going to Marseille.
  6. The Brazilian ship is heading for Manila.
  7. Next to the ship carrying rice is a ship with a green chimney.
  8. A ship going to Genoa leaves at five.
  9. The Spanish ship leaves at seven and is to the right of the ship going to Marseille.
  10. The ship with a red chimney goes to Hamburg.
  11. Next to the ship leaving at seven is a ship with a white chimney.
  12. The ship on the border carries corn.
  13. The ship with a black chimney leaves at eight.
  14. The ship carrying corn is anchored next to the ship carrying rice.
  15. The ship to Hamburg leaves at six.

Which ship goes to Port Said? Which ship carries tea?

我在网上搜索答案,但找不到任何答案。所以我引用 'The Zebra Puzzle' 并相应地为这个问题安排了代码。所以这是我的 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'。
那么我该如何解决这个问题呢?
谢谢

第二行(在解决谓词之后)中术语 ship(...) 的参数数量是错误的。它是:

middleShip(ship(_,_,_,_,'Black',_),Shipes),

虽然应该是:

middleShip(ship(_,_,_,'Black',_),Shipes),

我还没有检查这是否有效,但这肯定会导致您的求解器失败。

您问的是:

So how can I solve this?

以下是一种通用方法,它始终适用于像您这样的纯单调 Prolog 程序。你的实际问题是一个特定的目标应该成功,但它失败了。所以你遇到了 意外故障 。为了本地化您程序的负责部分,我们现在将系统地概括您的程序。一步步。直到我们有一个很小的程序片段。这种技术有时称为程序切片,有时称为程序修改

首先,将以下内容添加到您的代码中:

:- op(950, fy, *).
*_.

:- initialization(solution(_Port, _Carrier)).

现在我们将通过在目标前面添加 * 一个接一个地删除目标,然后重新运行您的程序。因此请做好准备,您将重新运行您的程序几次。要加载程序,请在顶层输入:

?- [shipes].

这几乎适用于任何地方,例如 SICStus、GNU、SWI、YAP。您现在将收到有关 "failed directive" 或类似内容的警告。所以 - 高兴 - 因为您现在可以轻松重现问题!

开始在最后一个目标添加 *。你可以一次尝试几个。 要在修改后重新加载,您可以重新输入该目标,或者

  • 在 SICStus 中,更好的状态ensure_loaded(shipes).这将检查文件是否已被修改,并且仅在已重新加载后才重新运行它

  • 在 SWI 中,输入 make.

最后得到如下程序片段:

middleShip(A,(_,_,A,_,_)).

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).

所以你需要看懂四行代码才能看懂你的问题!

正如其他人已经指出的那样,问题是一旦您使用 ship/6 而在其他情况下 ship/5.

另一条评论:最好写 [_,_,_,A,B] 而不是 (_,_,_,A,B),这是常见的列表表示法。