【问题标题】:Prolog Sudoku Solver, Solve any quadratic Sudoku, elements not distinctProlog Sudoku Solver,求解任何二次数独,元素不明显
【发布时间】:2017-12-09 19:27:32
【问题描述】:

求解任何二次数独,因此大小为 4、9、16、25 的数独...无需对那些“块”(普通数独字段的子单元)进行硬编码。

使用 SWI-Prolog 和 clp(FD) 库。

以这样的格式给出的数独(列表列表):

[[_,1,3,_],
 [2,_,_,_],
 [_,_,_,3],
 [_,2,1,_]]

程序调用使用:

solve_sudoku([[_,1,3,_],[2,_,_,_],[_,_,_,3],[_,2,1,_]],L).
L = [[4, 1, 3, 2], [2, 3, 4, 1], [1, 4, 2, 3], [3, 2, 1, 4]]

【问题讨论】:

    标签: prolog sudoku clpfd


    【解决方案1】:

    来自this link的顶级。

    sudoku(Rows) :-
      length(Rows,N),
      D is integer(sqrt(N)),
      append(Rows,Vs),Vs ins 1..N,
      maplist(all_distinct,Rows),
      transpose(Rows,Columns),
      maplist(all_distinct,Columns),
      check_blocks(Rows,D),
      maplist(label,Rows).
    

    检查行和列没有重复后,我们需要检查块,是D×D的方块。

    过程check_blocks/2 一次获取D 行并将它们传递给block_columns/4

    check_blocks(Rows,D) :-
      length(BlockRows,D), append(BlockRows,Rest,Rows),
      block_columns(BlockRows,D,[],[]),
      check_blocks(Rest,D).
    check_blocks([],_).
    

    现在我们有 D 行,假设每行包含一定数量(即 D)的 D 列。但是我们需要获取所有行的前 D 列才能检查块。

    所以block_columns/4 中的第一个子句循环遍历所有行并将它们拆分为前缀(D 列)和其余部分。当 Rows 为空时,Bs 为当前块,Rs 为每一行的其余列。

    block_columns([Row|Rows],D,Bs,Rs) :-
      length(Cols,D), append(Cols,Rest,Row),
      block_columns(Rows,D,[Cols|Bs],[Rest|Rs]).
    block_columns([],D,Bs,Rs) :-
      flatten(Bs,Ns), all_distinct(Ns),
      flatten(Rs,Xs),
      ( Xs = [] ->
        true
      ; block_columns(Rs,D,[],[]) ).
    

    第二个子句检查块,然后重新开始。当我们到达列的末尾时,Rs 将不是空的,而是包含 D 个空列表,因此我们必须在检查终止之前将其展平。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多