Prolog的迷宫求解算法(Prolog maze solving algorithm)

2019-08-31 10:31发布

我想实现的Prolog迷宫求解算法。 因此,我搜索了一些解决迷宫算法和发现如下: http://www.cs.bu.edu/teaching/alg/maze/

FIND-PATH(X,Y):

if (x,y outside maze) return false
if (x,y is goal) return true
if (x,y not open) return false
mark x,y as part of solution path
if (FIND-PATH(North of x,y) == true) return true
if (FIND-PATH(East of x,y) == true) return true
if (FIND-PATH(South of x,y) == true) return true
if (FIND-PATH(West of x,y) == true) return true
unmark x,y as part of solution path
return false 

我已经建立在序言一个矩阵,它代表一个迷宫,其中0是打开的,而1是壁,例如(开始位置将是(2 | 1)和目标位于(4 | 1)):

11111
10001
10101

进一步更我定义的命名子句mazeDataAt(Coord_X, Coord_Y, MazeData, Result) ,这使我基质上的特定位置的值。

至今。 但现在我已经实现在序言中说的算法有问题。 我已经尝试过的“肮脏的方式”(通过使用嵌套的if语句翻译一个一个),但升级的复杂性,我不认为这是你应在序言的方式。

所以我想这:

isNotGoal(X, Y) :- 
    X = 19, Y = 2.

notOpen(X, Y, MazeData) :-
    mazeDataAt(X, Y, MazeData, 1). 

findPath(X, Y, MazeData) :- 
    isNotGoal(X, Y),
    notOpen(X, Y, MazeData),
    increase(Y, Y_New),
    findPath(X, Y_New, MazeData),
    increase(X, X_New),
    findPath(X_New, Y, MazeData),
    decrease(Y, Y_New),
    findPath(X, Y_New, MazeData),
    decrease(X, X_New),
    findPath(X, Y_New, MazeData).

但是,这种尝试并没有工作像预期。

其实,这是一个正确的序言实现上述算法的? 我怎么可以看到,如果这个方法真的穿过迷宫找到一个路径? 因此如何录制路径或得到解决途径(什么是标记/取消标记的路径在上述算法做)?

非常感谢您的帮助!

// UPDATE

感谢您的解答! 我喜欢采用的解决方案更序言(见这里 )来解决我的问题。 所以,我现在有:

d([2,1], [2,2]).
d([2,2], [1,2]).
d([2,2], [2,3]).

go(From, To, Path) :-
go(From, To, [], Path).

go(P, P, T, T).
go(P1, P2, T, NT) :-
    (d(P1, P3) ; d(P3, P2)),
    \+ member(P3, T),
    go(P3, P2, [P3|T], NT).

到目前为止,这个工程。 我想我明白了为什么前序的方式要好得多。 但现在我已经离开了一个小问题。

我希望我的知识基础是“动态的”。 我不能定义为在迷宫中的每一个航点的所有边缘。 因此我写命名子句is_adjacent([X1, Y1], [X2, Y2])的值为真时[X1, Y1]是邻居[X2, Y2]

我也有一个列表Waypoints = [[2, 1], [2, 2]| ...] Waypoints = [[2, 1], [2, 2]| ...]其中包含我迷宫的所有可能的航点。

现在的问题是:我怎么可以用它来使我的知识基础“动态”? 这样我可以使用它在go子句寻找路径?

谢谢你的帮助!

//更新2

好了,现在我把所有航点的事实:

w(2, 1).
w(2, 2).
...

我从鲍里斯的解决方案,他的答案之一:

d(X0, Y0, X , Y) :-
    w(X0, Y0),
    next_w(X0, Y0, X, Y),
    w(X, Y).

next_w(X0, Y0, X0, Y) :- Y is Y0 + 1.
next_w(X0, Y0, X0, Y) :- Y is Y0 - 1.
next_w(X0, Y0, X, Y0) :- X is X0 + 1.
next_w(X0, Y0, X, Y0) :- X is X0 - 1.

在那之后,我更新了go子句,因此它适合:

go(X1, Y1, X2, Y2, Path) :-
go(X1, Y1, X2, Y2, [], Path).

go(X, Y, X, Y, T, T).
go(X1, Y1, X2, Y2, T, NT) :-
   (d(X1, Y1, X3, Y3) ; d(X3, Y3, X1, Y1)),
\+ member([X3, Y3], T),
go(X3, Y3, X2, Y2, [[X3, Y3]|T], NT).

但是,如果我要问go(2, 1, 19, 2, R)序言进入一个无限循环。 如果我尝试一些更容易喜欢go(2, 1, 3, 8, R)它的工作原理和我得到的解决途径R

我究竟做错了什么? 我忘记什么?

Answer 1:

(这个答案使用相同的路径寻找算法这个答案 )

编辑2

事实上,如果你输入的只是其中长方形矩阵的细胞没有围墙,你就需要以某种方式把这种那种的规则,“你可以从A到B”。 如果您的航点是那么:

w(2,1).
w(2,2).

等等,那么你就可以转换你原来指向到这样的Prolog的规则算法:

% it is possible to move from (X0,Y0) to (X,Y)
d(X0,Y0,X,Y) :-
    w(X0,X0), % you can skip this check if you know for sure
              % that your starting point is a valid waypoint
              % or if you want to be able to start from inside
              % a wall :)
    next_w(X0,Y0,X,Y),
    w(X,Y).
% neighboring waypoints
next_w(X0,Y0,X0,Y) :- Y is Y0+1. % go up I guess
next_w(X0,Y0,X0,Y) :- Y is Y0-1. % go down
next_w(X0,Y0,X,Y0) :- X is X0+1. % go left
next_w(X0,Y0,X,Y0) :- X is X0-1. % go right

注意两件事情:

  1. 我使用的可能的移动的4参数规则从一个正方形(因此相应地调整)
  2. 魔术发生在next_w 。 当d被调用时,它使用next_w产生四种可能的邻居广场(假设你只能去上/下/左/右),然后检查此方是否确实是一个航点。 你不会需要检查两种方式了。

第二个编辑:全码

w(0,0).
w(0,1). w(1,1). w(2,1). w(3,1). w(4,1). w(5,1).
        w(1,2).         w(3,2).         w(5,2).
        w(1,3).         w(3,3).         w(5,3).
w(0,4). w(1,4). w(2,4).         w(4,4). w(5,4).
                w(2,5). w(3,5). w(4,5).

d(X0,Y0,X,Y) :- next_w(X0,Y0,X,Y), w(X,Y).
next_w(X0,Y0,X0,Y) :- Y is Y0+1.
next_w(X0,Y0,X,Y0) :- X is X0+1.
next_w(X0,Y0,X0,Y) :- Y is Y0-1.
next_w(X0,Y0,X,Y0) :- X is X0-1.

go(X,Y,X,Y,Path,Path).
go(X0,Y0,X,Y,SoFar,Path) :-
    d(X0,Y0,X1,Y1),
    \+ memberchk( w(X1,Y1), SoFar ),
    go(X1,Y1,X,Y,[w(X1,Y1)|SoFar],Path).

你可以把它与

? go(0,0,5,4,[],Path).

你应该得到的两个可能的解决方案。

换句话说,我认为你的问题是分号; 它不再是必要的,因为你明确地创造一切可能的行动。



文章来源: Prolog maze solving algorithm