编写一个Prolog程序来模拟在网格中移动的大猩猩

时间:2014-12-07 02:28:26

标签: prolog

我在Prolog中做了很少的编程,到目前为止发现它很难。

我被问到:大猩猩沿着8x8网格移动,只能向右或向上移动。它必须保持在网格内,并且必须从(8,8)开始,从任意位置开始。

编写描述所有可能移动的移动谓词。

我的尝试:

move(X,Y,X+1,Y).
move(X,Y,X,Y+1).

编写一个路径谓词,使用移动谓词来确定机器人所采用的路径。

我的尝试:

path('right'):-
    move(X,Y,X+1,Y).
path('up'):-
    move(X,Y,X,Y+1).

编写prolog谓词,模拟(1,2),(4,2)和(4,1)的阻塞。

到目前为止,从我发现的情况来看,似乎我需要建立一个能够提供所有可能位置的列表。

我写了一份可能的职位清单,但不明白如何实施:

[(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),
 (2,1),(2,2),(2,3),(2,4),(2,5),(2,6),(2,7),(2,8),
 (3,1),(3,2),(3,3),(3,4),(3,5),(3,6),(3,7),(3,8),
 (4,1),(4,2),(4,3),(4,4),(4,5),(4,6),(4,7),(4,8),
 (5,1),(5,2),(5,3),(5,4),(5,5),(5,6),(5,7),(5,8),
 (6,1),(6,2),(6,3),(6,4),(6,5),(6,6),(6,7),(6,8),
 (7,1),(7,2),(7,3),(7,4),(7,5),(7,6),(7,7),(7,8),
 (8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8)]

这似乎是一个简单的程序,但我似乎无法掌握这些概念,或者至少将它们整合到一个可行的程序中。

非常感谢任何指导方面的帮助。

2 个答案:

答案 0 :(得分:1)

所以你可能想在你做这件事时说出你在哪里。所以我会建议这样的谓词move/3

% move(From_Position, To_Position, Direction).

move((X,Y),(X,Y1), up)   :- 
    grid(G), 
    member((X,Y1),G),
    Y1 is Y + 1.
move((X,Y),(X1,Y), rigth):- 
    grid(G), 
    member((X1,Y),G),
    X1 is X + 1.

网格调用是为了确保您始终保持在网格上。您还可以使用更智能的谓词in_grid并避免member调用(这非常耗时)。

grid([(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),
 (2,1),(2,2),(2,3),(2,4),(2,5),(2,6),(2,7),(2,8),
 (3,1),(3,2),(3,3),(3,4),(3,5),(3,6),(3,7),(3,8),
 (4,1),(4,2),(4,3),(4,4),(4,5),(4,6),(4,7),(4,8),
 (5,1),(5,2),(5,3),(5,4),(5,5),(5,6),(5,7),(5,8),
 (6,1),(6,2),(6,3),(6,4),(6,5),(6,6),(6,7),(6,8),
 (7,1),(7,2),(7,3),(7,4),(7,5),(7,6),(7,7),(7,8),
 (8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8)]).

路径应该是方向列表:

path((8,8), []).
path(Position, [Direction| Before]):-
    \+ Position = (8,8),
    move(Position, NewPosition, Direction),
    path(NewPosition,Before).

要累积,您可以使用bagofsetof

all_paths(Position,Paths):-
    setof(Path,path(Position,Path),Paths).

答案 1 :(得分:1)

您的代码存在一些问题。让我们一次一个地完成它。

<强> 1。可能的职位

虽然你的可能位置列表没问题,但我不会像那样硬编码。如果一个位置在网格上,检查是非常容易的:

grid_position(X, Y) :- 
    X >= 1,
    X =< 8,
    Y >= 1,
    Y =< 8.

请注意,这只能用于验证给定的位置。如果您希望能够生成所有可能的职位,可以使用in/2中的library(clpfd)

<强> 2。允许的职位

如果对于被阻止的位置没有如上所述的简单逻辑,除了自己枚举之外别无他法。

blocked(1, 2).
blocked(4, 2).
blocked(4, 1).

使用这个,我们可以确定我们的大猩猩允许的位置:网格上的任何位置,但不会被阻挡。

allowed_position(X, Y) :-
    grid_position(X, Y),
    \+blocked(X, Y).

第3。移动

这里的主要问题是在条款的开头写X+1并不能完成您的想法。要评估算术表达式,您需要使用is谓词。

此外,如果允许下一个位置,我只允许移动。由于大猩猩已经在当前位置,我不会检查是否确实允许这个位置。

move(X, Y, X2, Y) :- 
    X2 is X + 1, 
    allowed_position(X2, Y).
move(X, Y, X, Y2) :- 
    Y2 is Y + 1, 
    allowed_position(X, Y2).

<强> 4。路径

以下是我对该要求的解释:给定一个起始位置,返回用于到达终点位置的移动列表。

为此,我们需要3个参数:X和Y位置以及输出。这里的输出将是一个位置列表而不是一个移动列表,如果需要,我会留给您更改。

那么我们的道路是什么?好吧,首先你做一个动作,然后你从下一个位置找到剩下的路径。

path(X, Y, [(X,Y)|Ps]) :- 
    move(X, Y, X2, Y2), 
    path(X1, Y1, Ps).

当然,我们必须确保它在目标位置结束,因此对于基本情况我们可以使用:

path(8, 8, (8, 8)).

您可能还想验证初始位置是否为允许的位置,我已经遗漏了。


结合一切,你得到如下的输出。

?- path(5,6,L).        
L = [(5,6),(6,6),(7,6),(8,6),(8,7)|(8,8)] ? ;
L = [(5,6),(6,6),(7,6),(7,7),(8,7)|(8,8)] ? ;
L = [(5,6),(6,6),(7,6),(7,7),(7,8)|(8,8)] ? ; 
...

这可能不是您正在寻找的,但我希望它能帮助您顺利完成。