如何在ECLiPSe(CLP)中将向量转换为数组?(或Prolog)

Bab*_*ger 5 arrays prolog eclipse-clp

我必须以包含9个向量(每个长度为9)的向量的格式解决数独谜题.看到矢量是Prolog中的链接列表,我认为如果我首先以2D数组格式转换谜题,搜索会更快.

示例拼图:

puzzle(P) :- P = 
[[_,_,8,7,_,_,_,_,6],
[4,_,_,_,_,9,_,_,_],
[_,_,_,5,4,6,9,_,_],

[_,_,_,_,_,3,_,5,_],
[_,_,3,_,_,7,6,_,_],
[_,_,_,_,_,_,_,8,9],

[_,7,_,4,_,2,_,_,5],
[8,_,_,9,_,5,_,2,3],
[2,_,9,3,_,8,7,6,_]].
Run Code Online (Sandbox Code Playgroud)

我正在使用ECLiPSe CLP来实现解算器.到目前为止,我提出的最好的方法是写一个这样的域:

domain(P):-
  dim(P,[9,9]),
  P[1..9,1..9] :: 1..9.
Run Code Online (Sandbox Code Playgroud)

和拼图的转换器(参数P是给定的拼图,Sudoku是具有2D阵列的新定义的网格).但是我无法将给定初始拼图中的值链接到我的2D数组.

convertVectorsToArray(Sudoku,P):-
  ( for(I,1,9),
      param(Sudoku,P)
    do
      ( for(J,1,9),
          param(Sudoku,P,I)
        do
          Sudoku[I,J] is P[I,J]
      )
  ).
Run Code Online (Sandbox Code Playgroud)

在此之前,我尝试使用array_list(http://eclipseclp.org/doc/bips/kernel/termmanip/array_list-2.html),但我一直遇到类型错误.我以前怎么做过:

convertVectorsToArray(Sudoku,P):-
  ( for(I,1,9),
      param(Sudoku,P)
    do
      ( for(J,1,9),
          param(Sudoku,P,I)
        do
          A is Sudoku[I],
          array_list(A,P[I])
      )
  ).
Run Code Online (Sandbox Code Playgroud)

当我的Sudoku最终输出以下格式的示例拼图P时:

Sudoku = []([](_Var1, _Var2, 8, 7, ..., 6), [](4, ...), ...)
Run Code Online (Sandbox Code Playgroud)

那我会很开心

更新

我再次尝试使用array_list; 它几乎与以下代码一起使用:

convertVectorsToArray(Sudoku,P):-
  ( for(I,1,9),
      param(Sudoku,P)
    do
      X is Sudoku[I],
      Y is P[I],
      write(I),nl,
      write(X),nl,
      write(Y),nl,
      array_list(X, Y)
  ).
Run Code Online (Sandbox Code Playgroud)

写入是为了查看矢量/数组的外观.由于某种原因,它在第二次迭代(而不是9次)停止,并输出示例谜题的其余部分作为向量的向量.仅正确分配第一个向量.

UPDATE2

虽然我确定jschimpf给出的答案是正确的,但我也想出了我自己的实现:

convertVectorsToArray(Sudoku,[],_).
convertVectorsToArray(Sudoku,[Y|Rest],Count):-
  X is Sudoku[Count],
  array_list(X, Y),
  NewCount is Count + 1,
  convertVectorsToArray(Sudoku,Rest,NewCount).
Run Code Online (Sandbox Code Playgroud)

感谢您之前为什么不起作用的补充说明!

jsc*_*mpf 5

最简单的解决方案是通过将拼图规范直接编写为二维数组来完全避免转换.ECLiPSe"数组"只是一个带有仿函数的结构'[]'/N,因此您可以编写:

puzzle(P) :- P = [](
    [](_,_,8,7,_,_,_,_,6),
    [](4,_,_,_,_,9,_,_,_),
    [](_,_,_,5,4,6,9,_,_),

    [](_,_,_,_,_,3,_,5,_),
    [](_,_,3,_,_,7,6,_,_),
    [](_,_,_,_,_,_,_,8,9),

    [](_,7,_,4,_,2,_,_,5),
    [](8,_,_,9,_,5,_,2,3),
    [](2,_,9,3,_,8,7,6,_)).
Run Code Online (Sandbox Code Playgroud)

然后,您可以直接使用此二维数组作为域变量的容器:

sudoku(P) :-
    puzzle(P),
    P[1..9,1..9] :: 1..9,
    ...
Run Code Online (Sandbox Code Playgroud)

但是,如果您想保留列表列表拼图规范,并将其转换为数组数组格式,则可以使用array_list/2.但由于这仅适用于1-D阵列,因此必须单独转换嵌套级别:

listoflists_to_matrix(Xss, Xzz) :-
    % list of lists to list of arrays
    ( foreach(Xs,Xss), foreach(Xz,Xzs) do
        array_list(Xz, Xs)
    ),
    % list of arrays to array of arrays
    array_list(Xzz, Xzs).
Run Code Online (Sandbox Code Playgroud)

至于你自己的代码不起作用的原因:这是由于下标符号P[I].这个

  • 需要P是一个数组(你在列表中使用它)
  • 仅适用于需要算术表达式的上下文,例如is/2算术约束中的右侧等.