Prolog 如何为该";实现一个solve谓词;“移动块”;序言练习?
我正在使用Ivan Bratko的书《人工智能编程》学习Prolog,我发现在实现一个练习的最后部分时有一些困难 这个练习是一个程序,它使用图形来决定如何移动块并按顺序排列它们 这是一幅与程序必须执行的操作相关的图像: 如前所述,块A、B、C可以使用以下允许的移动次数进行移动:Prolog 如何为该";实现一个solve谓词;“移动块”;序言练习?,prolog,Prolog,我正在使用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).