Prolog Sudoku Solver,解决任何二次数独,数字不明显

时间:2017-12-09 11:25:33

标签: prolog sudoku clpfd

解决任何二次数独,所以数量为4,9,16,25的数独......而不需要对正常数独场的子单元进行硬编码。#34;块#34; < / p>

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

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

[[_,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]]

1 个答案:

答案 0 :(得分:0)

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个空列表,因此我们必须在检查终止之前将其展平。