Prolog 如何为该";实现一个solve谓词;“移动块”;序言练习?

Prolog 如何为该";实现一个solve谓词;“移动块”;序言练习?,prolog,Prolog,我正在使用Ivan Bratko的书《人工智能编程》学习Prolog,我发现在实现一个练习的最后部分时有一些困难 这个练习是一个程序,它使用图形来决定如何移动块并按顺序排列它们 这是一幅与程序必须执行的操作相关的图像: 如前所述,块A、B、C可以使用以下允许的移动次数进行移动: 仅当块位于堆栈顶部时,才可以移动块 可以在地面上移动块(在空堆上) 一个块可以移动到另一个块上(在另一个堆栈的顶部) 其中包含一些其他块) 因此,这些可容许的移动会产生一个图,图中一个状态和另一个状态之间可能的转换

我正在使用Ivan Bratko的书《人工智能编程》学习Prolog,我发现在实现一个练习的最后部分时有一些困难

这个练习是一个程序,它使用图形来决定如何移动块并按顺序排列它们

这是一幅与程序必须执行的操作相关的图像:

如前所述,块A、B、C可以使用以下允许的移动次数进行移动:

  • 仅当块位于堆栈顶部时,才可以移动块

  • 可以在地面上移动块(在空堆上)

  • 一个块可以移动到另一个块上(在另一个堆栈的顶部) 其中包含一些其他块)

因此,这些可容许的移动会产生一个图,图中一个状态和另一个状态之间可能的转换,类似这样:

solve([[c,a,b],[],[]], Situation)

因此,正如您在前面的图中所看到的,我可以使用3个子列表来表示一种情况

每个子列表提供一个堆栈,我可以根据前面的约束放置块

例如,前一个图的中心节点的情况可以表示为:

[[A]、[B]、[C]]

因为每个堆栈包含一个块

由左上角的节点表示的情况,其中我将一个节点堆叠在其他块C、A、B的下方,可表示为:

好的,我的程序如下:

del(X, [X|Tail], Tail).

del(X, [Y|Tail], [Y|Tail1]) :- del(X, Tail, Tail1).

/* s(CurrentState, SuccessorState): Predicate that calculate a legal move from
                                    the CurrentState to the SuccessorState:
*/
s(Stacks, [Stack1, [Top1|Stack2] | OtherStacks]) :- 
                                     del( [Top1|Stack1], Stacks, Stacks1),
                                     del( Stack2, Stacks1, OtherStacks).

goal(Situation) :- member([a,b,c], Situation).
在过去的几天里,我对它进行了深入的研究,我了解它是如何工作的

实质上,s/3谓词是我的后继函数
s(CurrentState,SuccessorState)
,它计算从
CurrentState
SuccessorState的合法移动

事实上,如果我启动以下查询,该谓词运行良好:

[debug]  ?- s([[a,b,c],[],[]],R).
R = [[b, c], [a], []] 
我得到[[b,c],[a],[]]状态的继承状态[[a,b,c],[]],这很好,因为我已经将
a
块从第一个堆栈的顶部移动到第二个堆栈的顶部(这是无效的),这是一个完全合法的移动

好的,接下来我有一个
目标/1
谓词,当我到达最终状态时(当计算必须停止时):

如果在相关堆栈列表中有一个堆栈是[a,b,c]列表,则表示一种情况(特定堆栈列表配置)是目标情况

因此,以下情况是目标情况:

[[a,b,c],[],[]]
[[], [a,b,c],[]]
[[],[], [a,b,c]]
好的,现在我的问题是:我必须像这样实现
solve/2
谓词:

solve([[c,a,b],[],[]], Situation)

从一个经过的情况开始(在这种情况下,在第一个栈中的所有栈的列表中,在地面上有“代码> c>代码>,<代码> b <代码>中间,代码< A/<代码>顶部,到达目标状态。

我不知道我必须做什么以及如何解决它(不幸的是我没有老师)

我试图启发自己,看看这个版本的8皇后问题,它使用了类似的编程技术(我有一个要满足的目标和解决谓词):


在空间搜索图中会有循环,然后可以切换到某种形式的绑定搜索。我越容易知道它是有界深度搜索:

?- length(Situation,_), solve([[c,a,b],[],[]], Situation).
Situation = [[[c, a, b], [], []], [[a, b], [c], []], [[b], [a], [c]], [[], [b, c], [a]], [[], [a, b|...], []]] .
length/2枚举长度不断增长的未绑定列表。所以我们得到了一个结果

请注意,如果从初始状态到目标/1没有解决方案,这仍然会循环。 如果这不好,我认为solve/2将需要一个服务solve2/2谓词,该谓词将获取路径,以便在不确定的s/2调用后启用通常的
\+memberchk(NewState,Visited)
。那么它将(未经测试)


我是以皇后区为例的
?- length(Situation,_), solve([[c,a,b],[],[]], Situation).
Situation = [[[c, a, b], [], []], [[a, b], [c], []], [[b], [a], [c]], [[], [b, c], [a]], [[], [a, b|...], []]] .
solve(N, SearchPath) :- solve2([N], SearchPath).

solve2([N|Visited], [N|Visited]) :- goal(N).
solve2([N|Visited], Path) :-
   s(N,N1),
   \+ memberchk(N1, Visited),
   solve2([N1,N|Visited], Path).