为什么Prolog没有为福克斯,鹅和豆袋拼图找到解决方案。并显示' true'代替?

时间:2014-04-01 14:44:12

标签: prolog river-crossing-puzzle

我想用Prolog作为练习来解决“Fox, goose and bag of beans puzzle”。

所以我写了

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只访问{{1}},{{1}}是描述采取了哪些步骤。

1 个答案:

答案 0 :(得分:2)

导致失败的主要问题是拼写错误:

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

应该是:

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

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

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

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