我正在尝试学习swi-prolog(除了基本的,无用的程序之外)。
任何人都可以解释(可能是伪代码)这个数独求解器和相关函数在做什么吗?如果您需要更多参考,可以在swi-prolog的CLP(FD)包中找到。
谢谢!
:- use_module(library(clpfd)).
sudoku(Rows) :-
length(Rows, 9), maplist(length_(9), Rows),
append(Rows, Vs), Vs ins 1..9,
maplist(all_distinct, Rows),
transpose(Rows, Columns), maplist(all_distinct, Columns),
Rows = [A,B,C,D,E,F,G,H,I],
blocks(A, B, C), blocks(D, E, F), blocks(G, H, I).
length_(L, Ls) :- length(Ls, L).
blocks([], [], []).
blocks([A,B,C|Bs1], [D,E,F|Bs2], [G,H,I|Bs3]) :-
all_distinct([A,B,C,D,E,F,G,H,I]),
blocks(Bs1, Bs2, Bs3).
problem(1, [[_,_,_,_,_,_,_,_,_],
[_,_,_,_,_,3,_,8,5],
[_,_,1,_,2,_,_,_,_],
[_,_,_,5,_,7,_,_,_],
[_,_,4,_,_,_,1,_,_],
[_,9,_,_,_,_,_,_,_],
[5,_,_,_,_,_,_,7,3],
[_,_,2,_,1,_,_,_,_],
[_,_,_,_,4,_,_,_,9]]).
答案 0 :(得分:11)
Prolog 是一种不同的思考方式:你必须从逻辑上思考。
首先A :- B, C, D
表示如果B和C和D为真, A为真(成功)。
你发布的代码片段检查数独谜题的正确性,有三个条件:
它是如何运作的?
如果符合以下条件,数独(行)为真:
length(Rows, 9)
- >行中有9个元素maplist(_length(9), Rows)
- > maplist
检查列表中每个元素的谓词(第一个参数)(第二个参数)。这意味着每行的长度必须为9。maplist(all_distinct, Rows)
- >和以前一样,但我们检查每一行是否有不同的(不相等的成对)元素。transpose(Rows, Columns), maplist(all_distinct, Columns)
- >我们将行转换为列,以通过垂直方式选择它们来检查它们是否完全不同Rows = [A,B,C,D,E,F,G,H,I]
- >拆分行列表并将每一个放在不同的变量A,B,C,D ......所以A将是第一行,B是第二行,依此类推blocks(A, B, C), blocks(D, E, F), blocks(G, H, I)
- >对于行的三元组,此谓词必须为真。让我们来谈谈blocks
部分,这很难理解。我们想检查每个3x3块是否包含不同的值。我们怎么能这样做?
假设有3行,条件必须为每行的前三个元素(第一个3x3块),对于元素第4到第6(第二个块)和第7个第9个(第三个块)。
所以我们可以递归地思考:blocks([],[],[])
非常简单,我们有空列表。
当您使用至少包含至少3个元素的列表参数调用blocks([A,B,C|Bs1],[D,E,F|Bs2],[G,H,I|Bs3])
谓词时,会选择案例blocks
。所以我们可以检查A,B,C,D,E,F,G,H,I是否都是不同的,然后我们使用余数列表作为参数递归地调用blocks
(没有前三个元素)。这就是Prolog的意思!
因此blocks
将首先调用三行9个元素,它将检查每行的前3个是不同的,并使用3个6个元素的列表调用自身,再次检查并使用3个列表调用自身3个元素中,再次检查它并用三个空列表调用自身(总是成功的trival案例)。
答案 1 :(得分:3)
sudoku / 1基本上描述了Sudoku解决方案必须满足的约束,其中棋盘被表示为九个长度为九的列表。问题/ 2将部分实例化的板分配给问题编号。要使用它你应该
? - 问题(1,董事会),数独(董事会)。
您应该阅读the documentation中使用的谓词。
答案 2 :(得分:2)
关于“追加(行,Vs),Vs ins 1..9”
http://www.swi-prolog.org/pldoc/man?predicate=append%2F2
这意味着列表列表中的所有元素都必须位于域1..9
。