0

入力数独ボードが現在正しくないかどうかをチェックするだけの簡単なプログラムを書こうとしています。つまり、行、列、または「ボックス」に同じ番号が2つあります。行と列の部分で問題が発生したことはありません。これは、次のコードで実行する非常に単純なタスクです(「0」は、入力されていない正方形を表すことに注意してください)。

:- use_module(library(clpfd)).

%Takes a matrix, determines if any row has repeating numbers
check([H|T]):-
    all_diff(H),
    check(T).
check([]).

%takes a list, checks if it contains repetitions other than '0'.
all_diff([]).
all_diff([X|Xs]) :-
    ( X = 0 ->
    all_diff(Xs)
        ;
        \+memberchk(X, Xs),
      all_diff(Xs)

    ).

consistent(Rows):-
    check(Rows),                %verify rows are free of repeats
    transpose(Rows,Columns),    %L1 represents columns
    check(Columns),         %verify all columns are free of repeats
        [H|T] = Rows,
        length(H,M),
    K is integer(sqrt(M)).     %this will give me dimensions of each box (KxK)

ただし、KxKの「ボックス」(Kは行の長さの平方根)を表すリストを生成する方法については、あまり明確ではありません。Kの値を取得し、row1をK個のサブリストに分割し、row(K * K)に到達するまで、row2のK個のサブリストをrow1のサブリストの最後に追加します。

残念ながら、これを実現する方法が本当にわかりませんか?リストを取得し、それぞれの長さがYのXリストに分割するという方針に沿って何かを実行するために使用できるBIPはありますか?

そうでなければ、何かアイデアはありますか?私は小さなループについて知っています、そしてそれらはここで実装できると思います、しかし私はそれをどのように行うのか本当にわかりませんか?助けてくれてありがとう!

4

1 に答える 1

1

単純で非効率的な方法として、インデックス演算とループを使用できます。

...
    Sq = 3,
    findall(B, (between(1, Sq, R),
            between(1, Sq, C),
            block(M, Sq, R, C, B)), Bs).

cell(M, R,C, V) :-
    nth1(R,M,Row), nth1(C,Row,V).

block(M, Sq, R,C, B) :-
    findall(V, (between(1, Sq, X),
            between(1, Sq, Y),
            I is (R-1) * Sq + X,
            J is (C-1) * Sq + Y,
            cell(M, I, J, V)), B).

ライブラリ( clpfd )のドキュメントには、既知の標準次元に限定されたより効率的な方法があります。そのコードを一般化してみることができます。

ここで編集は私のテストケースです。行列が偽物であることに注意してください。ブロックがどこにあるかを簡単に理解できるようにしてください。

q(Bs) :-
    M = [[1,2,3,4,5,6,7,8,9],
         [a,b,c,d,_,3,_,8,5],
         [x,y,z,_,2,_,_,_,_],
         [u,v,z,e,t,y,_,_,_],
         [b,b,b,e,t,y,1,_,_],
         [c,c,c,e,t,y,_,_,_],
         [5,_,_,_,_,_,_,7,3],
         [_,_,2,_,1,_,_,_,_],
         [_,_,_,_,4,_,_,_,9]],

    Sq = 3,
    findall(B, (between(1, Sq, R),
            between(1, Sq, C),
            block(M, Sq, R, C, B)), Bs).

cell(M, R,C, V) :-
    nth1(R,M,Row), nth1(C,Row,V).

block(M, Sq, R,C, B) :-
    findall(V, (between(1, Sq, X),
            between(1, Sq, Y),
            I is (R-1) * Sq + X,
            J is (C-1) * Sq + Y,
            cell(M, I, J, V)), B).

次のコマンドでテストします。

?- q(Bs),maplist(writeln,Bs).
[1,2,3,a,b,c,x,y,z]
[4,5,6,d,_G928,3,_G934,2,_G940]
[7,8,9,_G895,8,5,_G904,_G907,_G910]
[u,v,z,b,b,b,c,c,c]
[e,t,y,e,t,y,e,t,y]
[_G796,_G799,_G802,1,_G808,_G811,_G814,_G817,_G820]
[5,_G769,_G772,_G775,_G778,2,_G784,_G787,_G790]
[_G736,_G739,_G742,_G745,1,_G751,_G754,4,_G760]
[_G706,7,3,_G715,_G718,_G721,_G724,_G727,9]
Bs = [[1, 2, 3, a, b, c, x, y|...], [4, 5, 6, d, _G928, 3, _G934|...], [7, 8, 9, _G895, 8, 5|...], [u, v, z, b, b|...], [e, t, y, e|...], [_G796, _G799, _G802|...], [5, _G769|...], [_G736|...], [...|...]].
于 2012-04-18T16:15:03.043 に答える