Prolog:通过示例学习

发布于 2024-08-11 20:26:24 字数 1620 浏览 9 评论 0原文

我正在尝试学习一些有关 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

鹊巢 2024-08-18 20:26:24

Prolog 是一种思考程序的不同方式:你必须进行逻辑思考。

首先,A :- B, C, D 表示如果 B AND C AND D 为真,则 A 为真(成功)。

您发布的代码片段检查数独谜题的正确性,有三个条件:

  • 行中的元素全部不同 列
  • 中的元素全部不同
  • 3x3 块中的元素全部不同

它是如何工作的?

sudoku(Rows) 为 true,如果:

  1. length(Rows, 9) ->行中有 9 个元素
  2. maplist(_length(9), Rows) -> maplist 检查列表中每个元素(第二个参数)的谓词(第一个参数)。这意味着每行的长度必须为 9。
  3. maplist(all_distinct, Rows) ->与之前相同,但我们检查每行是否具有不同的(不相等的成对)元素。
  4. 转置(行,列),maplist(all_distinct,列) ->我们将行转置为列,通过以垂直方式选择它们来检查它们是否全部不同
  5. Rows = [A,B,C,D,E,F,G,H,I] - >拆分行列表并将每个行放入不同的变量 A、B、C、D 中...因此 A 将是第一行,B 第二行,依此类推
  6. blocks(A, B, C), block(D, E,F),块(G,H,I) ->对于行的三元组,该谓词必须为真。

我们来谈谈blocks部分,这部分理解起来很有趣。我们想要检查每个 3x3 块是否包含不同的值。我们怎样才能做到这一点?

假设有 3 行,对于每行的前三个元素(第一个 3x3 块)、第 4 到第 6 个元素(第二个块)和第 7-9 个元素(第三个块),条件必须为真。

所以我们可以递归地思考:blocks([],[],[]) 是非常正确的,我们有空列表。

当您调用 blocks 时,会选择 case blocks([A,B,C|Bs1],[D,E,F|Bs2],[G,H,I|Bs3]) 谓词,其参数列表包含至少 3 个元素。因此,我们可以检查 A、B、C、D、E、F、G、H、I 是否都不同,然后我们使用余数列表(没有前三个元素)作为参数递归调用 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:

  • elements are all different by rows
  • elements are all different by columns
  • elements are all different by 3x3 blocks

How does it work?

sudoku(Rows) is true if:

  1. length(Rows, 9) -> there are 9 elements in rows
  2. maplist(_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.
  3. maplist(all_distinct, Rows) -> same as before, but we check if every row has distinct (not equal pairwise) elements.
  4. 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 way
  5. Rows = [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 on
  6. blocks(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 call blocks 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 call blocks 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).

心如荒岛 2024-08-18 20:26:24

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.

子栖 2024-08-18 20:26:24

关于“追加(行,Vs),Vs ins 1..9”

http ://www.swi-prolog.org/pldoc/man?predicate=append%2F2

表示列表列表的所有元素必须在域1..9内。

about "append(Rows, Vs), Vs ins 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文