Prolog - 猴子和香蕉问题


在这个序言示例中,我们将看到一个非常有趣且著名的问题,猴子和香蕉问题。

问题陈述

假设问题如下 -

  • 房间里有一只饥饿的猴子,它靠近门。

  • 猴子在地板上。

  • 房间天花板中央挂着香蕉。

  • 房间里靠近窗户的地方有一个木块(或椅子)。

  • 猴子想要香蕉,但够不到。

猴子和香蕉问题

那么猴子怎样才能得到香蕉呢?

因此,如果猴子足够聪明,他可以来到积木面前,将积木拖到中心,爬上积木,然后得到香蕉。以下是这种情况下的一些观察结果 -

  • 如果猴子和猴子在同一水平线上,猴子就能到达方块。从上图中,我们可以看到猴子和木块都在地板上。

  • 如果方块位置不在中心,那么猴子可以将其拖动到中心。

  • 如果猴子和木块都在地板上,并且木块位于中心,那么猴子可以爬上木块。这样猴子的垂直位置就会改变。

  • 当猴子在方块上,并且方块在中心时,猴子就可以得到香蕉。

现在,让我们看看如何使用 Prolog 解决这个问题。我们将创建一些谓词如下 -

我们有一些谓词通过执行操作从一种状态转移到另一种状态。

  • 当方块在中间,而猴子在方块上方,而猴子没有香蕉(即没有状态)时,那么使用抓取动作,它会从没有状态变为状态。

  • 通过执行爬升动作,它可以从地板移动到方块的顶部(即顶部状态)。

  • 推或操作将块从一个位置移动到另一个位置

  • 猴子可以使用walkmove子句从一个地方移动到另一个地方。

另一个谓词是 canget()。这里我们传递一个状态,因此这将使用不同的操作执行从一个状态到另一个状态的移动谓词,然后在状态 2 上执行 canget()。当我们到达状态“has>”时,这表示“香蕉。我们将停止执行。

程序

move(state(middle,onbox,middle,hasnot),
   grasp,
   state(middle,onbox,middle,has)).
move(state(P,onfloor,P,H),
   climb,
   state(P,onbox,P,H)).
move(state(P1,onfloor,P1,H),
   drag(P1,P2),
   state(P2,onfloor,P2,H)).
move(state(P1,onfloor,B,H),
   walk(P1,P2),
   state(P2,onfloor,B,H)).
canget(state(_,_,_,has)).
canget(State1) :-
   move(State1,_,State2),
   canget(State2).

输出

| ?- [monkey_banana].
compiling D:/TP Prolog/Sample_Codes/monkey_banana.pl for byte code...
D:/TP Prolog/Sample_Codes/monkey_banana.pl compiled, 17 lines read - 2167 bytes written, 19 ms

(31 ms) yes
| ?- canget(state(atdoor, onfloor, atwindow, hasnot)).

true ?

yes
| ?- trace
.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- canget(state(atdoor, onfloor, atwindow, hasnot)).
      1 1 Call: canget(state(atdoor,onfloor,atwindow,hasnot)) ?
      2 2 Call: move(state(atdoor,onfloor,atwindow,hasnot),_52,_92) ?
      2 2 Exit:move(state(atdoor,onfloor,atwindow,hasnot),walk(atdoor,_80),state(_80,onfloor,atwindow,hasnot)) ?
      3 2 Call: canget(state(_80,onfloor,atwindow,hasnot)) ?
      4 3 Call: move(state(_80,onfloor,atwindow,hasnot),_110,_150) ?
      4 3 Exit: move(state(atwindow,onfloor,atwindow,hasnot),climb,state(atwindow,onbox,atwindow,hasnot)) ?
      5 3 Call: canget(state(atwindow,onbox,atwindow,hasnot)) ?
      6 4 Call: move(state(atwindow,onbox,atwindow,hasnot),_165,_205) ?
      6 4 Fail: move(state(atwindow,onbox,atwindow,hasnot),_165,_193) ?
      5 3 Fail: canget(state(atwindow,onbox,atwindow,hasnot)) ?
      4 3 Redo: move(state(atwindow,onfloor,atwindow,hasnot),climb,state(atwindow,onbox,atwindow,hasnot)) ?
      4 3 Exit: move(state(atwindow,onfloor,atwindow,hasnot),drag(atwindow,_138),state(_138,onfloor,_138,hasnot)) ?
      5 3 Call: canget(state(_138,onfloor,_138,hasnot)) ?
      6 4 Call: move(state(_138,onfloor,_138,hasnot),_168,_208) ?
      6 4 Exit: move(state(_138,onfloor,_138,hasnot),climb,state(_138,onbox,_138,hasnot)) ?
      7 4 Call: canget(state(_138,onbox,_138,hasnot)) ?
      8 5 Call:   move(state(_138,onbox,_138,hasnot),_223,_263) ?
      8 5 Exit: move(state(middle,onbox,middle,hasnot),grasp,state(middle,onbox,middle,has)) ?
      9 5 Call: canget(state(middle,onbox,middle,has)) ?
      9 5 Exit: canget(state(middle,onbox,middle,has)) ?
      7 4 Exit: canget(state(middle,onbox,middle,hasnot)) ?
      5 3 Exit: canget(state(middle,onfloor,middle,hasnot)) ?
      3 2 Exit: canget(state(atwindow,onfloor,atwindow,hasnot)) ?
      1 1 Exit: canget(state(atdoor,onfloor,atwindow,hasnot)) ?
      
true ?

(78 ms) yes