Prolog:通过示例学习
我正在尝试学习一些有关 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]]).
I am trying to learn a little bit about swi-prolog (beyond the basic, useless programs).
Can anyone explain (perhaps in pseudocode) what this sudoku solver and the related functions are doing? If you need more reference it is found in the CLP(FD) package of swi-prolog.
Thanks!
:- 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]]).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Prolog 是一种思考程序的不同方式:你必须进行逻辑思考。
首先,
A :- B, C, D
表示如果 B AND C AND D 为真,则 A 为真(成功)。您发布的代码片段检查数独谜题的正确性,有三个条件:
它是如何工作的?
sudoku(Rows) 为 true,如果:
length(Rows, 9)
->行中有 9 个元素maplist(_length(9), Rows)
->maplist
检查列表中每个元素(第二个参数)的谓词(第一个参数)。这意味着每行的长度必须为 9。maplist(all_distinct, Rows)
->与之前相同,但我们检查每行是否具有不同的(不相等的成对)元素。转置(行,列),maplist(all_distinct,列)
->我们将行转置为列,通过以垂直方式选择它们来检查它们是否全部不同Rows = [A,B,C,D,E,F,G,H,I]
- >拆分行列表并将每个行放入不同的变量 A、B、C、D 中...因此 A 将是第一行,B 第二行,依此类推blocks(A, B, C), block(D, E,F),块(G,H,I)
->对于行的三元组,该谓词必须为真。我们来谈谈
blocks
部分,这部分理解起来很有趣。我们想要检查每个 3x3 块是否包含不同的值。我们怎样才能做到这一点?假设有 3 行,对于每行的前三个元素(第一个 3x3 块)、第 4 到第 6 个元素(第二个块)和第 7-9 个元素(第三个块),条件必须为真。
所以我们可以递归地思考:
blocks([],[],[])
是非常正确的,我们有空列表。当您调用
blocks 时,会选择 case
谓词,其参数列表包含至少 3 个元素。因此,我们可以检查 A、B、C、D、E、F、G、H、I 是否都不同,然后我们使用余数列表(没有前三个元素)作为参数递归调用blocks([A,B,C|Bs1],[D,E,F|Bs2],[G,H,I|Bs3])
blocks
)。这就是 Prolog 的意义所在!因此,首先将使用三行 9 个元素调用
blocks
,它将检查每行的前 3 个元素是否不同,并使用 3 个包含 6 个元素的列表调用自身,再次检查并使用 3 个列表调用自身包含 3 个元素,再次检查它并使用三个空列表调用自身(总是成功的简单情况)。Prolog is a different way of thinking about programs: you have to think logically.
First of all
A :- B, C, D
means A is true (succeds) if B AND C AND D are true.The snippet of code you posted checks for the correctness of a Sudoku puzzle, there are three condition:
How does it work?
sudoku(Rows) is true if:
length(Rows, 9)
-> there are 9 elements in rowsmaplist(_length(9), Rows)
->maplist
checks the predicate (first parameter) on every element of the list (second parameter). This means that every row must be of length 9.maplist(all_distinct, Rows)
-> same as before, but we check if every row has distinct (not equal pairwise) elements.transpose(Rows, Columns), maplist(all_distinct, Columns)
-> we transpose the rows into columns to check if they are all distinct also by selecting them in the vertical wayRows = [A,B,C,D,E,F,G,H,I]
-> splits rows list and place every one in a different variable A, B, C, D ... so A will be first row, B second one and so onblocks(A, B, C), blocks(D, E, F), blocks(G, H, I)
-> this predicate must be true for the triplets of rows.Let's talk about the
blocks
part, that is quite funny to understand. We want to check that every 3x3 block contains distinct values. How can we do that?Suppose to have 3 rows, the condition must be true for first three elements of every row (first 3x3 block), for elements 4th to 6th (second block) and 7th-9th (third block).
So we can think recursively:
blocks([],[],[])
is trivially true, we've got empty lists.The case
blocks([A,B,C|Bs1],[D,E,F|Bs2],[G,H,I|Bs3])
is chosen when you callblocks
predicate with parameters that are list with AT LEAST 3 elements. So we can check if A,B,C,D,E,F,G,H,I are all distinct, then we callblocks
recursively using as parameters the remainder lists (without the first three elements). This is what Prolog is about!So
blocks
will be called first with three rows of 9 elements, it will check that first 3 of every row are distinct and call itself with 3 lists of 6 elements, check it again and call itself with 3 lists of 3 elements, check it again and call itself with three empty lists (the trival case that always succeds).sudoku/1 基本上描述了数独解决方案必须满足的约束,其中棋盘表示为由九个长度为 9 的列表组成的列表。 Problem/2 将部分实例化的板分配给问题编号。要使用它,你应该做
?-问题(1,棋盘),数独(棋盘)。
您应该阅读文档中使用的谓词。
sudoku/1 basically describes the constraints a Sudoku solution must satisfy, where the board is represented as a list of nine lists of length nine. problem/2 assigns a partially instantiated board to a problem number. To use it you should do
?- problem(1, Board), sudoku(Board).
You should read up on the predicates used in the documentation.
http ://www.swi-prolog.org/pldoc/man?predicate=append%2F2
表示列表列表的所有元素必须在域
1..9
内。http://www.swi-prolog.org/pldoc/man?predicate=append%2F2
It means that all elements of the list of lists must be in the domain
1..9
.