0

我想用 Prolog 作为练习来解决“狐狸、鹅和豆袋难题”。

所以我写了

p(left).
p(right).
valid((Man, Goose, Fox, Beans)) :- p(Man),p(Goose),p(Fox),p(Beans), Man == Goose.
valid((Man, Goose, Fox, Beans)) :- p(Man),p(Goose),p(Fox),p(Beans), Man == Beans, Goose \= Fox.
valid((Man, Goose, Fox, Beans)) :- p(Man),p(Goose),p(Fox),p(Beans), Man == Fox, Goose \= Beans.

step((Man1, Goose, Fox, Beans), "Man", (Man2, Goose, Fox, Beans)) :- 
    valid((Man1, Goose, Fox, Beans)), valid((Man2, Goose, Fox, Beans)),
    Man1 \= Man2.

step((Man1, Goose1, Fox, Beans), "Goose", (Man2, Goose2, Fox, Beans)) :- 
    valid((Man1, Goose1, Fox, Beans)), valid((Man2, Goose2, Fox, Beans)),
    Man1 \= Man2, Goose1 \= Goose2.

step((Man1, Goose, Fox1, Beans), "Fox", (Man2, Goose, Fox2, Beans)) :- 
    valid((Man1, Goose, Fox1, Beans)), valid((Man2, Goose, Fox2, Beans)),
    Man1 \= Man2, Fox1 \= Fox2.

step((Man1, Goose, Fox, Beans1), "Beans", (Man2, Goose, Fox, Beans1)) :- 
    valid((Man1, Goose, Fox, Beans1)), valid((Man2, Goose, Fox, Beans2)),
    Man1 \= Man2, Beans1 \= Beans2.

reachable(S, _,[], S).
reachable(S, Visited, [Step|Steps], Z) :- 
    step(S,Step,Tmp),valid(Tmp), not(member(Tmp,Visited)),
    reachable(Tmp, [Tmp|Visited], Steps, Z).

start((left,left,left,left)).
goal((right,right,right,right)).

solve(Steps) :- start(S), goal(Z), reachable(S, [], Steps, Z).

问题

我想solve(X).我会得到一系列有效的步骤。但相反,我得到

?- solve(X).
false.

为什么我没有得到从开始到目标的步骤列表?

代码解释

valid检查一个 4 元组,其中第一个元素是“Man”的位置,第二个是“Goose”的位置,第三个是“Beans”的位置,如果没有人被吃掉。

step(Situation1, Description, Situation2)从一个有效的情境迈向另一个有效的情境。

reachable(Start, SituationList, Steps, Goal)检查是否Goal可以从情境中到达情境Goal,而每个情境SituationList都只被访问一次,并且Steps描述了按顺序采取了哪些步骤。

4

1 回答 1

2

导致失败的主要问题是错字:

step((Man1, Goose, Fox, Beans1), "Beans", (Man2, Goose, Fox, Beans1)) :- 

应该:

step((Man1, Goose, Fox, Beans1), 'Beans', (Man2, Goose, Fox, Beans2)) :- 

这将产生正确的解决方案。还有一些其他的清理点:

  • 您在字符串上使用双引号,在 Prolog 中,它实际上是一个 ASCII 代码序列(prolog 列表)。如果你想要一个字符串显示为一个字符串,你可以使用用单引号括起来的 Prolog 原子。因此,例如,'Man'而不是"Man".
  • valid(Tmp)您的子句中的目标reachable/2是多余的,因为先前的目标step确保Tmp根据valid规则有效。
  • 在这个特定的应用程序中,每个子句中的两个valid目标中的step/3第一个不是必需的,因为您的第一个参数来自先前验证的步骤。(这取决于您想要step/3表现的“一般”程度)。

除此之外,solve/1仍然会产生许多重复的结果,但它们都是正确的,并且发现了所有正确的解决方案。

于 2014-04-01T18:03:01.330 回答