您需要的第一件事实际上是将列表列表转换为矩阵的杠杆。二维矩阵与列表列表的区别是什么?坐标系的概念。因此,您需要一种方法将坐标对与矩阵中的相应值关联。
at(Matrix, X, Y, V) :- nth0(X, Matrix, Row), nth0(Y, Row, V).
这个谓词可以在 (X,Y) 处索引矩阵并获得值 V。事实证明,IMO 是对 Prolog 强大功能的大规模演示,因为一旦你有了这个,简单的谓词,你获得:
-
在提供的点获得值的能力:
?- at([[5,6,7,8],[10,11,12,13],[1,2,3,4],[14,15,16,17]], 1,3, V).
V = 13.
-
迭代整个矩阵的能力(仅实例化Matrix并将其他参数保留为变量):
?- at([[5,6,7,8],[10,11,12,13],[1,2,3,4],[14,15,16,17]], X,Y, V).
X = Y, Y = 0,
V = 5 ;
X = 0,
Y = 1,
V = 6 ;
...
X = 3,
Y = 2,
V = 16 ;
X = Y, Y = 3,
V = 17.
-
在矩阵中搜索值的能力:
?- at([[5,6,7,8],[10,11,12,13],[1,2,3,4],[14,15,16,17]], X,Y, 14).
X = 3,
Y = 0 ;
false.
所以这是一个非常有用的杠杆!在传统语言中,您需要三个不同的函数来完成所有这些事情,但这是不同的,因为在 Prolog 中我们只需要定义事物之间的 关系(在这种情况下,数据结构和一个坐标对),Prolog 可以完成相当多的繁重工作。
现在很容易看出我们如何生成一个特定的子矩阵,只需定义我们希望看到的 X 和 Y 值的集合。例如,要获得左上角矩阵,我们会这样做:
?- between(0,1,X), between(0,1,Y),
at([[5,6,7,8],[10,11,12,13],[1,2,3,4],[14,15,16,17]], X,Y, V).
X = Y, Y = 0,
V = 5 ;
X = 0,
Y = 1,
V = 6 ;
X = 1,
Y = 0,
V = 10 ;
X = Y, Y = 1,
V = 11.
我们当然可以使用findall/3 将解决方案收集到一个地方:
?- findall(V, (between(0,1,X), between(0,1,Y),
at([[5,6,7,8],[10,11,12,13],[1,2,3,4],[14,15,16,17]], X,Y, V)),
Vs).
Vs = [5, 6, 10, 11].
剩下的问题基本上是一些算术。让我们看看我们是否有一个方阵:
square_matrix(M, Degree) :-
length(M, Degree),
maplist(length, M, InnerDegrees),
forall(member(I, InnerDegrees), I=Degree).
这不是一个完美的谓词,因为它不会生成!但它会告诉我们一个矩阵是否为正方形,如果是,它的度数是多少:
?- square_matrix([[5,6,7,8],[10,11,12,13],[1,2,3,4],[14,15,16,17]], D).
D = 4.
一旦你有了它,你要做的就是公式化:
- 确保度数是完美的正方形
- 取度数的平方根。这就是您拥有的行数或列数(平方根 4 = 2、2 行 2 列,平方根 9 = 3、3 行和 3 列)。
- 在(行,列)坐标和该位置矩阵的(x,y)坐标的列表之间建立关系。例如,在 4x4 矩阵中,您有四个图块:(0,0)、(0,1)、(1,0) 和 (1,1)。 (0,0) 的坐标为 (0,0), (0,1), (1,0), (1,1),但 (1,1) 的坐标为 (2,2) ,(2,3),(3,2),(3,3)。如果您手动执行其中一些操作,您会发现这相当于为两个坐标从 0 到行/列计数(减一)的所有排列添加 x 和 y 偏移量。
- 现在您已经建立了这种关系,您需要进行迭代并组装您的输出。我认为
maplist/N 就足够了。
希望这会有所帮助!