Prolog:通过实例学习

时间:2009-11-20 04:05:11

标签: prolog clpfd

我正在尝试学习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]]).

3 个答案:

答案 0 :(得分:11)

Prolog 是一种不同的思考方式:你必须从逻辑上思考。

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

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

  • 元素按行
  • 不同
  • 元素各有不同的列
  • 元素因3x3块而异。

它是如何运作的?

如果符合以下条件,

数独(行)为真:

  1. length(Rows, 9) - >行中有9个元素
  2. maplist(_length(9), Rows) - > maplist检查列表中每个元素的谓词(第一个参数)(第二个参数)。这意味着每行的长度必须为9。
  3. maplist(all_distinct, Rows) - >和以前一样,但我们检查每一行是否有不同的(不相等的成对)元素。
  4. transpose(Rows, Columns), maplist(all_distinct, Columns) - >我们将行转换为列,以通过垂直方式选择它们来检查它们是否完全不同
  5. Rows = [A,B,C,D,E,F,G,H,I] - >拆分行列表并将每一个放在不同的变量A,B,C,D ......所以A将是第一行,B是第二行,依此类推
  6. blocks(A, B, C), blocks(D, E, F), blocks(G, H, I) - >对于行的三元组,此谓词必须为真。
  7. 让我们来谈谈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