Prolog 序言:猴子和香蕉,两个盒子

Prolog 序言:猴子和香蕉,两个盒子,prolog,dcg,Prolog,Dcg,说明:修改附带的程序,以便猴子能够够到香蕉,他必须站在一个较小的盒子上,他把盒子放在一个较大的盒子上。在课程开始时,盒子应位于房间中的两个不同位置。在屏幕上显示猴子的活动 我一直在阅读这本教科书(人工智能的Prolog编程),事实证明,Prolog很难掌握。虽然这本书讨论了如果有一个盒子如何解决这个问题,但没有提到如果有多个盒子如何开始解决这个问题。如有任何指导/建议,将不胜感激 move(state(middle, onbox, middle, hasnot), grasp, state(mi

说明:修改附带的程序,以便猴子能够够到香蕉,他必须站在一个较小的盒子上,他把盒子放在一个较大的盒子上。在课程开始时,盒子应位于房间中的两个不同位置。在屏幕上显示猴子的活动

我一直在阅读这本教科书(人工智能的Prolog编程),事实证明,Prolog很难掌握。虽然这本书讨论了如果有一个盒子如何解决这个问题,但没有提到如果有多个盒子如何开始解决这个问题。如有任何指导/建议,将不胜感激

move(state(middle, onbox, middle, hasnot), grasp, state(middle, onbox, middle, has)).
move(state(Pos, onfloor, Pos, H), climb, state(Pos, onbox, Pos, H)).
move(state(P1, onfloor, P1, H), push(P1, P2), state(P2, onfloor, P2, H)).
move(state(P1, onfloor, P, H), walk(P1, P2), state(P2, onfloor, P, H)).

canget(state(_ ,_ ,_ , has)).
canget(state1) :-
  move(State1, Move, State2),
  canget(State2).
问题:

canget(state(atdoor, onfloor, atwindow, hasnot)). % (monkey's horizontal position, monkey's vertical position, position of the box, and whether or not the monkey has the banana).

我唯一能想到的是为第二个框的位置的每个子句添加另一个字段,例如state(水平位置、垂直位置、box1的位置、box2的位置和香蕉状态)。

您建议的解决方案是解决这个问题的一种方法:您确实可以在表示状态的术语中再添加一个参数

然而,让我们着眼于更一般的问题:如果房间里不仅有一个或两个盒子,而且还有n盒子,你会怎么做?此外,让我们假设盒子的大小为S_1,…,S_n(S_i不一定不同),并且只有当顶部的盒子小于放置它的盒子时才能堆叠

我建议用以下表述来表示这种状态:

我们将使用一对
Pos Size
来表示每个框的位置和大小。这只是术语
-(Pos,Size)
的中缀符号,即函子
-
和arity2

我们将使用此类对的列表,即,
[Pos1-Size1,Pos2-Size2,…,Pos\u n-Size\u n]
来表示所有框

在相同位置堆放箱子时,我们需要确保已经位于相同位置的箱子允许此类堆放。这是你的练习

而且,
canget/1
真的没那么有趣,是吗?我们真正关心的是将我们带到解决方案的移动列表!因此,我们使用一个参数扩展谓词,该参数实际上可以让我们看到顶层的所有移动,并使用一个更能说明问题的名称来表示我们实际描述的内容:

moves(state(_ ,_ ,_ , has), []).
moves(State0, [Move|Moves]) :-
        move(State0, Move, State),
        moves(State, Moves).
现在,我们可以使用迭代深化来找到具体的解决方案:

?- length(Ms, _), moves(State0, Ms).
其中
State0
是拼图的初始状态

当您对Prolog有了更多的经验后,您将越来越多地使用符号来描述列表,以简化代码。我将此版本留在这里供您稍后学习:

moves(state(_ ,_ ,_ , has)) --> [].
moves(State0) --> [Move],
        { move(State0, Move, State) },
        moves(State).
用法示例,再次使用迭代深化来找到最短的解决方案:

?- length(Ms, _), phrase(moves(State0), Ms).

祝你玩得开心,还可以试试开场白的艺术

多谢各位。说到开场白,我还在小步走。因此,我继续为每个状态添加了另一个参数,而不是实现您建议的更一般的解决方案。我跟踪了我的程序,它似乎只是。然而,我只是想确保,我不必创建任何新的子句,对吗?或者我必须创建一个新的子句,以便猴子可以独立地移动小盒子或大盒子?添加一个新的子句来描述只移动新盒子的状态之间的关系,这当然是一个好主意!区分不同的“推”操作来表示哪个框被推似乎也是一个好主意。例如,要么直接在函子中是一个
push_small(…)
push_big(…)
,要么通过一个新参数,如
push(small…)
push(big…)
。后一种方法显然更容易推广到其他类型的盒子。我认为我做得不对。我编辑了我的原始程序来实现不同的“推”操作。但是,我遇到了“本地堆栈外”错误。我有以下内容:
移动(状态(P1,地板上,P1,Psmall,H),推大(P1,P2),状态(P2,地板上,P2,Psmall,H))。
移动(状态(P1,地板上,Pbig,P1,H),推小(P1,P2),状态(P2,地板上,Pbig,P2,H))。
状态如下:(猴子的位置,猴子是否在盒子上,大盒子的位置,小盒子的位置,是否有香蕉)。请参阅我上面给出的谓词:它可以让您明确地对尝试的移动进行推理。因此,您可以使用迭代深化在移动列表上施加一定的长度,正如我上面所示。目前,您可能会运行到循环中,但由于您没有使用任何参数来表示移动,因此这对您来说是不可见的。使移动列表显式化,并概括您的程序,以查看移动的尝试顺序!我想我已经。。。