节目说明
我的程序用于计算20X15尺寸平面中的形状位置.我有一个形状列表,其中包含形状类型,其id,半径或高度,以及它在平面上的预期[X,Y]位置.我有一个不同的二进制操作列表,只包含形状类型,它的id,以及它与另一个形状的位置关系.通过操作列表中的这些信息,我应该计算形状的[X,Y]位置:下面是两个列表的描述:
形状列表
我有一个形状列表:每个形状是一个表单列表:
[[shape, id],height/radius, [X,Y]]
当Prolog打印出来时,这些形状的列表看起来如下所示:
[[[diamond,1],4,[_7948,_7954]],[[circle,3],6,[_7894,_7900]],[[square,1],4,[_7840,_7846]],[[circle,1],5,[_7786,_7792]]|_7800]
Run Code Online (Sandbox Code Playgroud)
运营清单
应对每个操作的形状执行的操作列表如下:
[[[circle,1],below,[square,1]]]
Run Code Online (Sandbox Code Playgroud)
这意味着圆1应出现在X,Y平面上的方形1下方
当prolog打印出来时,这样的列表看起来如下所示:
[[[circle,1],below,[square,1]]|_8016]
Run Code Online (Sandbox Code Playgroud)
所以我有 computeShapeLocations/2.它的第一个参数是一个操作列表,第二个列表是一个形状列表.它以递归方式遍历操作列表,在操作的两侧获取形状ID.例如circle 1 - below - sqaure 1,将两个形状发送到正确的函数,以使用CLPFD计算位置.对于两个相对定位为"低于"的形状,我使用的computeShapesBelow/2形状各有两种形状[[shape, id],height/radius, [X,Y]].
ComputeShapeLocations/2中的步骤:
1.从操作列表中获取[[[circle,1],below,[square,1]]]形式的操作2.获取第一个id(圆圈1),然后获取关系类型(下面)然后是第二个id(方1).3.从形状列表中获取形状(ShapesOut)4.将形状发送到computeShapesBelow/2.这只是使用clpfd来比较半径或高度以及我的X,Y平面的尺寸.
:- use_module(library(clpfd)).
computeShapeLocations([],_ShapesOut).
computeShapeLocations([Operation|Rest],ShapesOut) :- writeln(ShapesOut),
writeln([Operation|Rest]),
nth0(0,Operation,Subject1),
nth0(1,Operation,below),
nth0(2,Operation,Subject2),
Shape1 = [Subject1,H,Loc],
Shape2 = [Subject2,H2,Loc2],
member(Shape1,ShapesOut),
member(Shape2,ShapesOut),
writeln(Shape1),
writeln(Shape2),
writeln(Subject1),
writeln(Subject2),
computeShapeBelow(Shape1,Shape2),
computeShapeLocations(Rest,ShapesOut).
computeShapeBelow(Shape1,Shape2) :- nth0(2,Shape1,Location1),
nth0(2,Shape2,Location2),
writeln(Shape1),
writeln(Shape2),
nth0(1,Shape1,Dim1),
nth0(1,Shape2,Dim2),
nth0(0,Location1,Xcord1),
nth0(0,Location2,Xcord2),
nth0(1,Location1,Ycord1),
nth0(1,Location2,Ycord2),
Ycord1 #> Dim1, Ycord1 #< 15-Dim1,
Xcord1 #> Dim1, Xcord1 #< 20-Dim1,
Ycord2 #> Dim2, Ycord2 #< 15-Dim2,
Xcord2 #> Dim2, Xcord2 #< 20-Dim2,
Ycord2 #> Ycord1+Dim2+Dim1.
Run Code Online (Sandbox Code Playgroud)
问题:
在computeShapeLocations/2我的查找中只是奇怪的(参见上面的步骤3 computeShapeLocations/2).我使用member(ShapeId,ListOFshapesList)从listofshapes中获取形状,给出它们的id [shape,id].然后我打印出结果(writeln(Shape1), writeln(Shape2)),下面的图像显示了行为是如何错误的.对于第一个形状(圆圈,1),结果很好,computeShapesBelow/2甚至可以得到其X,Y位置(6..14和6..9)的适当限制.对于第二个形状(Shape2或方形1).它的行为不符合预期,clpfd限制导致无穷大.
原因是因为[square,1]的第二次搜索忽略了一个条目[[square, 1], 4, [_2166, _2172]]在列表中,而是以某种方式添加了一个额外的 [[square, 1], _2250, [_2262|...]],然后它用来搞乱我的结果.

在我看来,你的问题的根源被两个简单的问题所掩盖。我没有你的所有代码,而且我真的不知道你想做什么,所以我只会谈谈我所看到的以及我将如何进行。
第一个问题是你没有有效地利用统一。例如,您可以替换它:
nth0(0,Operation,Subject1),
nth0(1,Operation,below),
nth0(2,Operation,Subject2),
Run Code Online (Sandbox Code Playgroud)
有了这个:
[Subject1,below,Subject2] = Operation,
Run Code Online (Sandbox Code Playgroud)
但是,此外,您实际上并不需要Operation单独使用,因此您可以将其移至子句的开头:
computeShapeLocations([[Subject1,below,Subject2]|Rest],ShapesOut) :-
Run Code Online (Sandbox Code Playgroud)
当您开始进行这些更改时,您的代码将会收缩很多,并且应该更容易看到发生了什么。使用更少的列表表示会使其更容易理解。例如,我更容易理解此命令列表中发生的情况:
[below(circle(1), square(1)), below(circle(2), square(1)), ...]
Run Code Online (Sandbox Code Playgroud)
甚至可以通过添加:- op声明来做到这一点:
[circle(1) below square(1), circle(2) below square(1), ...]
Run Code Online (Sandbox Code Playgroud)
然后你的模式匹配会看起来更简单,例如:
compute(Shape1 below Shape2) :- ...
Run Code Online (Sandbox Code Playgroud)
同样,对于你的形状,如果你有更多的结构,会更容易理解发生了什么:
shape(circle(1), 4, X@Y)
Run Code Online (Sandbox Code Playgroud)
对我来说比
[[circle,1], 4, [X,Y]]
Run Code Online (Sandbox Code Playgroud)
我发现输入列表中有未绑定的变量有点奇怪。我猜你希望他们以后能获得价值。我认为这种方法没有任何问题,我只是惊讶地看到接地和非接地的混合作为输入。
第二个麻烦来源是您将多种过程混合在一起。我很确定你在某个地方正在进行 DCG 解析步骤。通过解析其中的弱列表表示,您迫使自己在这些方法中做更多的工作来解构您的列表并获取它们的含义。考虑:
command([Shape1,below,Shape2]) --> shape(Shape1), "below", shape(Shape2).
Run Code Online (Sandbox Code Playgroud)
相对
command(Shape1 below Shape2) --> shape(Shape1), "below", shape(2).
Run Code Online (Sandbox Code Playgroud)
或者,
shape_type(circle) --> "circle". shape_type(square) --> "square".
shape_name(shape(Name, Size, X@Y)) -->
shape_type(T), integer(ID),
integer(Size),
integer(X), integer(Y),
{ Name =.. [T, ID] }.
Run Code Online (Sandbox Code Playgroud)
与你现在拥有的任何东西相比。
IOW,您可以在解析期间创建结构,这将简化处理过程中的生活。同样,做很多在我看来像是调试 I/O 的事情会让你的处理变得更加复杂。
find_shape(ShapeId, Shapes, Shape) :-
Shape = shape(ShapeId, _, _),
member(Shape, Shapes).
computeShapeLocations([], _).
computeShapeLocations([ShapeId1 below ShapeId2|Rest], Shapes) :-
find_shape(ShapeId1, Shapes, Shape1),
find_shape(ShapeId2, Shapes, Shape2),
computeShapeBelow(Shape1, Shape2),
computeShapeLocations(Rest, Shapes).
computeShapeBelow(shape(_, D1, X1@Y1), shape(_, D2, X2@Y2)) :-
Y1 #> D1, Y1 #< 15 - D1,
X1 #> D1, X1 #< 20 - D1,
Y2 #> D2, Y2 #< 15 - D2,
X2 #> D2, X2 #< 20 - D2,
Y2 #> Y1 + D2 + D1.
Run Code Online (Sandbox Code Playgroud)
我想如果我盯着这个我会发现它更容易调试。