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