PutiDoku

ナンプレ ジョーク

短独

ヒント数25個以下で90度回転対称のナンプレを数十秒で生成する短いJavaのコードです。
現在の記録は417バイト(随時更新)

class Q{public static void main(String[]a){for(;s<82;n=-7)for(c=new int[730],c[
40]=s%3;n<l;l=730)if(c[y=n++/9]>(n<0?c[m=(int)(Math.random()*81)]=m:0))for(c[y%
9*9-y/9+8]+=s=1;l-->0;c[y]^=v,c[z]^=v)c[z=l/9+300]^=v=z>(y=c[l]|=l<84?0:511)&((
v=(y>0?1<<y%9:-1)&c[z]&c[y=84+l%9]&c[z+=y/3-z%3])&v-1)*2<v?v+=(l=84)-++s<m?n=0&
m--:0:0;for(;y-->0;)System.out.print(--c[y]%9+1+(y%9<1?"\n":" "));}static int
y,z,s,l,m,n,v,c[];}

展開したものはコチラ。少しは見やすくなっているでしょうか。(661バイトのときのものです)

//クラス定義
class Q {

    //大域変数の定義
    static int e = 81, b = 2 * e, s, k, l, m, n, c[], h[];

    //位置tから候補rを消す手続き
    static void d(int t, int r) {

        //d内で用いる局所変数の定義
        int i = r * 9 + e, o = t % 9, p = c[t + b] |= k = ~c[t + b] & 1 << r++;

        //位置tにおいて候補からrが消えていない
        //かつそこに値rが入っていなければ実行
        if (k * c[t]!=k*r)

            //候補を消した後セルに残った候補が一つだった場合
            //それがどれかを特定するためのループ
            for (
                        
                //候補の更新+問題に異常がないかどうかチェック
                s = --c[i + t / 9]% 9
                    * ((c[i + o] -= 9) | (h[i + t / 27 * 3 + o / 3] -= i = r = 9))
                    * (k = --h[t + e] % 9) < 1 ? 0 : s;
                r-->0;)
                
                //そのセルに候補が一つしかなければ実行 
                if (c[t] + k + (p >> r & 1) < 2)

                    //新たに入れられた数字の影響を受ける
                    //セル・列・ブロックから候補を消すためのループ
                    for (
                                
                    //数字が決まったセルのカウントを一つ増やす
                    s++; 

                        i-- > 0; 

                        //新たに入れられた数字の影響を受ける
                        //セル・列・ブロックから候補を消す        
                        d(i * 9 + o, r), d(t - o + i, r), d(
                            t - t % 27 + o - o % 3 + i / 3 * 6 + i, r))

                        //盤面に数字を入れ数字が入ったセルの個数が前より増えたら
                        //最大確定セル数を更新してピボットを最初の位置に戻す。
                        for (c[t] = r + 1; m < s; m = s)
                            n = 0;
    }

    //問題を生成し出力する本体
    public static void main(String[] a) {

        //問題が完成するまで繰り返す    
        for (; s < b;) {

            //ヒントの初期化
            h = new int[b];

            //ヒント位置の決定
            for (; n > 2; h[m = (int) (Math.random() * e)] = -m)
                n/=3;

            //ピボットが盤面全体を順に移動して
            //そこの数字に対する処理を行うためのループ
            for (h[40] = m % 2; n < e * 9; k = n++ / 9)

                //盤面を90度右に回転させた位置がヒントなら実行
                if (h[k % 9 * 9 - k / 9 + 8] != 0) {

                    //ヒントの数字を1だけずらす
                    h[k] += 91;

                    //数字と候補の初期化   
                    c = new int[e + b];

                    //ソルバーに用いる補助変数の初期化 
                    for (s = b; s > e; h[--s] = c[s] = e)
                        l += 9;

                    //盤面を順番に見ていきヒントの位置から
                    //そこに入っている数字以外の候補を消すためのループ  
                    for (; l-- > 0;)

                        //その位置がヒントかつ消そうとする数字が
                        //ヒントとして入っている数字と異なるなら実行
                        if ((h[l / 9] -  l) % 9 > 0)

                            //候補を消す
                            d(l / 9, l % 9);
                }
        }

        //完成した問題を出力
        for (; ++l < e;)
            System.out.print((h[l] < 1 ? 0 : c[l]) + (l % 9 > 7 ? "\n" : " "));
    }
}

Copyright(C) 2007 Time Intermedia Corporation. All Rights Reserved.

株式会社タイムインターメディア | 自動生成エンジンとは | お問い合わせ | About Us