1、代码实现
:- use_module(library(clpfd)).
:- use_module(library(lists)).
%求解函数
sudoku(Puzzle, Solution) :-
length(Puzzle, L),
Size is floor(sqrt(L)), %计算矩阵大小
Solution = Puzzle,
Puzzle ins 1..Size, %输入必须符合规范(比如9阶Sudoku,元素必须在1到9之间)
slice(Puzzle, Rows, Size, 'row'), %将输入拆分为行,
slice(Puzzle, Cols, Size, 'col'), %列,
slice(Puzzle, Squares, Size, 'square'), %方格。
valid(Rows), %每行,每列,每个方格不可重复
valid(Cols),
valid(Squares),
pretty_print(Rows). %输出
%校验,一个List不可重复
valid([]).
valid([Head | Tail]) :- all_different(Head), valid(Tail).
%List截取
sublist_length([], _).
sublist_length([Head | Tail], Length) :- length(Head, Length), sublist_length(Tail, Length).
%List拼接
insert_into_slice(Item, Values, X, Y) :-
nth0(X, Values, Bucket),
nth0(Y, Bucket, Item).
%按行分割坐标
slice_position('row', Size, I, X, Y) :-
X is I // Size,
Y is I mod Size.
%按列分割坐标
slice_position('col', Size, I, X, Y) :-
X is I mod Size,
Y is I // Size.
%按方格分割坐标
slice_position('square', Size, I, X, Y) :-
Size_Sqrt is floor(sqrt(Size)),
X is (I mod Size // Size_Sqrt) + (Size_Sqrt * (I // (Size * Size_Sqrt))),
Y is (I mod Size_Sqrt) + (Size_Sqrt * ((I mod (Size * Size_Sqrt)) // Size)).
%数据分割函数
slice(Puzzle, Slice, Size, Type) :- slice(Puzzle, Slice, Size, Type, 0).
slice(_, Slice, Size, _, I) :- I is Size * Size, length(Slice, Size), sublist_length(Slice, Size).
slice([Head | Tail], Slice, Size, Type, I) :-
slice_position(Type, Size, I, X, Y),
insert_into_slice(Head, Slice, X, Y),
I1 is I + 1,
slice(Tail, Slice, Size, Type, I1).
%输出函数
pretty_print([Head | Tail]) :-
print(Head),
nl,
pretty_print(Tail).
2、测试一下
1 ?- sudoku([5, 3, _, _, 7, _, _, _, _,
6, _, _, 1, 9, 5, _, _, _,
_, 9, 8, _, _, _, _, 6, _,
8, _, _, _, 6, _, _, _, 3,
4, _, _, 8, _, 3, _, _, 1,
7, _, _, _, 2, _, _, _, 6,
_, 6, _, _, _, _, 2, 8, _,
_, _, _, 4, 1, 9, _, _, 5,
_, _, _, _, 8, _, _, 7, 9],
Solution).
[5,3,4,6,7,8,9,1,2]
[6,7,2,1,9,5,3,4,8]
[1,9,8,3,4,2,5,6,7]
[8,5,9,7,6,1,4,2,3]
[4,2,6,8,5,3,7,9,1]
[7,1,3,9,2,4,8,5,6]
[9,6,1,5,3,7,2,8,4]
[2,8,7,4,1,9,6,3,5]
[3,4,5,2,8,6,1,7,9]
false.