如何在Prolog中生成谓词网格?
我正在尝试用Prolog创建一个程序,但我对它还是新手,不确定在Prolog中生成网格状结构的最佳方法是什么 例如,假设我有一个谓词如何在Prolog中生成谓词网格?,prolog,swi-prolog,Prolog,Swi Prolog,我正在尝试用Prolog创建一个程序,但我对它还是新手,不确定在Prolog中生成网格状结构的最佳方法是什么 例如,假设我有一个谓词cell/4,它有4个参数北部,西部,南部和东部。我要创建的是谓词cell/4的NxN网格,它根据它们在网格中的位置相互连接 例如,我可以手动创建2x2网格。预期结果如下: North_1 North_2 |
cell/4
,它有4个参数<代码>北部,西部
,南部
和东部
。我要创建的是谓词cell/4
的NxN网格,它根据它们在网格中的位置相互连接
例如,我可以手动创建2x2网格。预期结果如下:
North_1 North_2
| |
+---------+----------+ +---------+----------+
| North | | North |
| | Interconnect_1 | |
West_1 -+ West cell/4 East +----------------+ West cell/4 East +- East_1
| | | |
| South | | South |
+---------+----------+ +---------+----------+
| |
Interconnect_2 Interconnect_3
| |
+---------+----------+ +---------+----------+
| North | | North |
| | Interconnect_4 | |
West_2 -+ West cell/4 East +----------------+ West cell/4 East +- East_2
| | | |
| South | | South |
+---------+----------+ +---------+----------+
| |
South_1 South_2
所以我的问题是,如何将这个过程推广到NxN网格?我相信可以有很好的方法来处理问题的参数
谓词,使其成为更一般的问题(北、西、南、东)
,其中每个参数都是一个列表。我正在努力生成这种类似网格的结构。假设单元(X,Y)
表示坐标X
和Y
处的网格单元,其中X
和Y
大于0
。现在,你可以写一些关于网格单元的有趣的东西了。例如,您可以捕获单元格有效的含义
valid(cell(X, Y)) :- X > 0, Y > 0.
或者捕获关系,如右邻居
,左邻居
,等等
right_neighbor(cell(X, Y1), cell(X, Y2)) :-
Y2 is Y1 + 1,
valid(cell(X, Y1)),
valid(cell(X, Y2)).
left_neighbor(cell(X, Y1), cell(X, Y2)) :-
Y1 is Y2 + 1,
valid(cell(X, Y1)),
valid(cell(X, Y2)).
您可以定义具有N
列的网格的R
第行,如下所示
grid_row(R, 1, [cell(R, 1)]) :-
valid(cell(R, 1)).
grid_row(R, N, [cell(R, N) | Row]) :-
M is N - 1,
valid(cell(R, M)),
grid_row(R, M, Row).
problem_row([N], W, [S], E, [cell(N, W, S, E)]).
problem_row([N|Ns], W, [S|Ss], E, [cell(N, W, S, I)|Cs]) :-
problem_row(Ns, I, Ss, E, Cs).
problem(Ns, [W], Ss, [E], Cs) :-
problem_row(Ns, W, Ss, E, Cs).
problem(Ns, [W|Ws], Ss, [E|Es], Cs) :-
problem_row(Ns, W, Is, E, R),
problem(Is, Ws, Ss, Es, Rs),
append(R, Rs, Cs).
然后,通过N
列定义一个由M
行组成的网格就很简单了
grid(1, N, [Row]) :-
grid_row(1, N, Row).
grid(M, N, [Row | Rows]) :-
grid_row(M, N, Row),
P is M - 1,
grid(P, N, Rows).
例如,查询网格(3,2,X)。
生成:
X = [[cell(3, 2), cell(3, 1)], [cell(2, 2), cell(2, 1)], [cell(1, 2), cell(1, 1)]]
R = [cell(n1, w1, s1, _1428), cell(n2, _1428, s2, e1)]
G = [cell(n1, w1, _1460, _1462), cell(n2, _1462, _1476, e1),
cell(_1460, w2, s1, _1494), cell(_1476, _1494, s2, e2)]
如果我们使用表示法单元(北、西、南、东)
其中北
,西
,南
和东
分别是其北、西、南和东单元的单元连接点(如果有),则解决方案类似。我们首先定义一行的单元格,如下所示
grid_row(R, 1, [cell(R, 1)]) :-
valid(cell(R, 1)).
grid_row(R, N, [cell(R, N) | Row]) :-
M is N - 1,
valid(cell(R, M)),
grid_row(R, M, Row).
problem_row([N], W, [S], E, [cell(N, W, S, E)]).
problem_row([N|Ns], W, [S|Ss], E, [cell(N, W, S, I)|Cs]) :-
problem_row(Ns, I, Ss, E, Cs).
problem(Ns, [W], Ss, [E], Cs) :-
problem_row(Ns, W, Ss, E, Cs).
problem(Ns, [W|Ws], Ss, [E|Es], Cs) :-
problem_row(Ns, W, Is, E, R),
problem(Is, Ws, Ss, Es, Rs),
append(R, Rs, Cs).
查询问题行([n1,n2],w1[s1,s2],e1,R)。产生:
X = [[cell(3, 2), cell(3, 1)], [cell(2, 2), cell(2, 1)], [cell(1, 2), cell(1, 1)]]
R = [cell(n1, w1, s1, _1428), cell(n2, _1428, s2, e1)]
G = [cell(n1, w1, _1460, _1462), cell(n2, _1462, _1476, e1),
cell(_1460, w2, s1, _1494), cell(_1476, _1494, s2, e2)]
我们将问题
谓词定义如下
grid_row(R, 1, [cell(R, 1)]) :-
valid(cell(R, 1)).
grid_row(R, N, [cell(R, N) | Row]) :-
M is N - 1,
valid(cell(R, M)),
grid_row(R, M, Row).
problem_row([N], W, [S], E, [cell(N, W, S, E)]).
problem_row([N|Ns], W, [S|Ss], E, [cell(N, W, S, I)|Cs]) :-
problem_row(Ns, I, Ss, E, Cs).
problem(Ns, [W], Ss, [E], Cs) :-
problem_row(Ns, W, Ss, E, Cs).
problem(Ns, [W|Ws], Ss, [E|Es], Cs) :-
problem_row(Ns, W, Is, E, R),
problem(Is, Ws, Ss, Es, Rs),
append(R, Rs, Cs).
查询问题([n1,n2],[w1,w2],[s1,s2],[e1,e2],G)
产生:
X = [[cell(3, 2), cell(3, 1)], [cell(2, 2), cell(2, 1)], [cell(1, 2), cell(1, 1)]]
R = [cell(n1, w1, s1, _1428), cell(n2, _1428, s2, e1)]
G = [cell(n1, w1, _1460, _1462), cell(n2, _1462, _1476, e1),
cell(_1460, w2, s1, _1494), cell(_1476, _1494, s2, e2)]
您应该注意,我已经将您的
单元格
谓词具体化为一个函子,以避免在运行时必须向程序中添加子句,这很可能不是您想要的。另外,请注意,网格答案包含问题中要求的未绑定变量。你可以为它们创造原子。例如,通过连接北原子和西原子的每一个组合。我很难想象你会喜欢单元格/4
,因为你有四个指向其他方向的指针,但这些单元格中的内容只是指向其他单元格的指针,而这些单元格只是指向其他单元格的指针。。。我想你可能真的想要单元格/5
,它更像是某个值加上每个方向的指针
通常,如果您想要大小为N的列表,可以使用length/2
为您生成一个如下所示的列表:
?- length(L, 3).
L = [_772, _778, _784].
然后你可以传递变量列表。假设你正在制作一个迷宫或其他东西,你想把你的网格传递给一个进程,这个进程会在其中放置一些东西,比如说,壁虎,墙等等,这就是你想要这个网格的原因。我上面的评论是想说,在Mx1安排中,这种结构类似于一个双链接列表:
+--------------------+ +--------------------+
| | Interconnect_1 | |
West_1 -+ West cell/2 East +----------------+ West cell/2 East +- East_1
| | | |
+--------------------+ +--------------------+
您可以通过类似的方式手动构建此结构:
?- West = cell(West_1, East), East = cell(West, East_1).
West = cell(West_1, cell(West, East_1)),
East = cell(West, East_1).
@false正确地指出这将是递归的,因为West等于某个结构,其中包含West。我和他一样对此感到担忧,因为无限项带来了有趣的问题,而且,通常在遍历过程中,您只需保持前面的值,就可以避免问题。(在你的例子中,这将形成一个网格,我猜只有东指针和南指针,或者一个纬度和一个纵向的组合,而不是两者都有)
在任何情况下,您都可以按照length/2
的示例,输入所需的长度,然后一次构建一个节点,从而构建一个双链接列表:
generate(0, Prev, cell(Prev, _)).
generate(N, Prev, cell(Prev, Next)) :-
succ(N0, N),
generate(N0, cell(Prev, Next), Next).
这是N=3的情况:
?- generate(3, Start, X).
X = cell(Start, cell(_S1, cell(_S2, _S3))), % where
_S1 = cell(Start, cell(_S1, cell(_S2, _S3))),
_S2 = cell(_S1, cell(_S2, _S3)),
_S3 = cell(cell(_S2, _S3), _656)
再次,让我指出,单链表中的cons单元格类似于cell/2
,因为有一个值和一个下一个指针,所以我们可能需要向其添加一个值槽,并返回cell/3
结构
因此,回到网格,生成NxN网格可能需要做的事情类似于一次生成一行,保留每次生成的前一行,并将其传递给某种压缩过程,该过程将前一行的南
指针等同于当前行的北
指针
我这里有一个单链接网格的解决方案。我希望这足以满足您的需要。这是一个有点棘手的想出
首先,我们需要能够生成一行:
generate_row(1, cell(_, nil, _)).
generate_row(N, cell(_, Next, _)) :-
succ(N0, N),
generate_row(N0, Next).
这里的计划是我们有一个单元(Value,NextRight,NextDown)
结构。NextRight
和NextDown
都是单元格,分别是网格中的东方向和南方向。我使用nil
表示空列表的作用;它终止递归并表示空指针。这是一个重要的东西,因为否则我的缝合过程将有无限递归
现在我们有了一行,让我们来考虑如何组合上一行和下一行。我们在这里真正做的就是从左到右遍历两行,将上一行的下一行与第二个列表中它下面的单元格相等。读起来有点奇怪,但它确实有用:
stitch(cell(_, NextAbove, Below), Below) :-
Below = cell(_, NextBelow, _),
stitch(NextAbove, NextBelow).
stitch(cell(_, nil, Below), Below).
因为我们需要下面的来保持完整,所以我们把它从身体而不是头部分开。我在这里匹配nil
以终止递归
现在我们有了所有我们需要的东西