第30講 数独(ナンバープレイス)問題解決ソフトVer.1の制作
(数独(ナンバープレイス)問題作成ソフトに挑戦する人は☆☆)


第16話 数独(ナンバープレイス)問題解決ソフトVer.1の完成
コード変更部分
                     ・
                     ・
                     ・
         void f(char g){
           if(s==2)return;
           char x,y;
           x=g%9;
           y=g/9;
           char h,i,j,k,k1,k2,ii,iii;
           if(a[y][x]>0){
             if(g+1<81){
               f(g+1);
             }
             else{
               k1=0;
               for(i=0;i<13;i++){
                 if(i%4==0){
                   k1++;
                   for(j=0;j<13;j++)dataGridView1[j,i+14]->Value=L"*";
                 }
                 if(i%4>0){
                   k2=0;
                   for(j=0;j<13;j++){
                     if(j%4==0){
                       dataGridView1[j,i+14]->Value=L"*";
                       k2++;
                     }
                     if(j%4>0){
                       dataGridView1[j,i+14]->Value=a[i-k1][j-k2];
                     }
                   }
                 }
               }
               s++;
               if(s==2)return;
             }
           }
           if(a[y][x]==0){
             ii=rand()%9;
             for(i=1;i<10;i++){
               iii=(i+ii)%9+1;
               h=1;
               if(x>0){
                 for(j=0;j<x;j++){
                   if(a[y][j]==iii){
                     h=0;
                     break;
                   }
                 }
               }
               if(h==1){
                 if(x+1<8){
                   for(j=x+1;j<9;j++){
                     if(a[y][j]==iii){
                       h=0;
                       break;
                     }
                   }
                 }
               }
               if(h==1){
                 if(y>0){
                   for(j=0;j<y;j++){
                     if(a[j][x]==iii){
                       h=0;
                       break;
                     }
                   }
                 }
               }
               if(h==1){
                 if(y+1<8){
                   for(j=y+1;j<9;j++){
                     if(a[j][x]==iii){
                       h=0;
                       break;
                     }
                   }
                 }
               }
               if(h==1){
                 for(j=0;j<3;j++){
                   if(j!=ya){
                     for(k=0;k<3;k++){
                       if(k!=xa){
                         if(a[3*ys+j][3*xs+k]>0){
                           if(a[3*ys+j][3*xs+k]==iii){
                             h=0;
                             break; 
                           }
                         }
                       }
                     }
                     if(h==0)break;
                   }
                 }
               }
               if(h==1){
                 a[y][x]=iii;
                 if(g+1<81){
                   f(g+1);
                 }
                 else{
                   k1=0;
                   for(i=0;i<13;i++){
                     if(i%4==0){
                       k1++;
                       for(j=0;j<13;j++)dataGridView1[j,i+14]->Value=L"*";
                     }
                     if(i%4>0){
                       k2=0;
                       for(j=0;j<13;j++){
                         if(j%4==0){
                           dataGridView1[j,i+14]->Value=L"*";
                           k2++;
                         }
                         if(j%4>0){
                           dataGridView1[j,i+14]->Value=a[i-k1][j-k2];
                         }
                       }
                     }
                   }
                   s++;
                   if(s==2)return;
                 }
                 a[y][x]=0;
               }
             }
           }
         }

                     ・
                     ・
                     ・
解説
iをiii(=(ii+i)%9+1さらにiiはrand()%9で9未満のランダムな正の整数)に変更するだけで、
入門
変更前にには1時間かけても解けなかった問題が、なんと0.004秒程度で解けてしまいました。
プログラムとは、本当に面白いものです。
ほんのちょっとした小改良で、3600÷0.004=9000000倍の速さになってしまいました。
実験を途中で打ち切ってしまいましたから、改良前は1時間と仮定してです。
実際には、1時間では解けないでしょうから、それ以上でしょう。
900万倍以上の速さになったのです。
ですが、今度はvc++の方の問題を解くのに52秒も要してしまいました。
22秒から52秒になってしまったのです。
もちろん、rand();を無駄打ちしたり、srand(0);によってシード値を変更すればもっと短い時間で出来るようになるでしょう。
シード値とは、srand(・);の括弧内の数値です。シード値を変えると、乱数系列自体が変わります。
後で数独(ナンバープレイス)問題作成ソフトの制作に挑戦しますが、シード値を変更しないと毎回同じ問題を作ってしまいます。
毎回異なる問題を作らせるためには、srand(static_cast<unsigned int>(time(0)));とすればよいのです。
static_cast<unsigned int>(time(0))は現在の時間を、整数に変更したものです。
実行ボタンを押すタイミングは毎回ずれますから、決して同じ問題を作ってしまうことはありません。
同じ問題を作ってしまう確率は1/1京(兆の1万倍)より遙かに小さいので、実質0です。

シード値を変更すれば、vc++が0.001秒以内で解けるようになる可能性はありますが、
すべての問題に対して、0.001秒以内で解けるようにするためには、そのような小手先の変更ではだめです。
どんな問題でも0.001秒以内で解けるソフトを作るのが目的です。
したがって、抜本的な改良が必要になってきます。
Verの変更が必要なわけです。

Ver.2では、問題全体構造解析を付け加え、そして問題全体構造解析に基づいた番号付け変更を行います。
Ver.1では、

* 0 1 2 3 4 * 5 6
7 8 * * 9 * 10 11 12
13 14 15 16 17 18 19 20 21
22 23 24 25 26 * 27 28 29
30 31 * 32 33 34 35 36 *
37 38 39 40 * * 41 * 42
43 44 45 * 46 47 48 * *
* 49 50 51 52 53 54 55 56
* 57 58 * 59 60 61 62 63

の順にセルに値を入れていっています。これだと20秒以上かかってしまうわけですが、問題全体構造解析を行い、
入力順番を次にのように変更すると

* 48 21 1 22 7 * 23 24
2 25 * * 26 * 27 8 28
29 59 49 30 50 31 63 51 52
32 60 53 3 54 * 33 55 34
9 61 * 0 10 11 35 56 *
12 36 13 4 * * 37 * 14
5 15 16 * 17 6 38 * *
* 62 39 40 41 18 42 43 57
* 58 19 * 44 20 45 46 47

1秒もかからず解けるようになります。問題全体構造解析とは、次のものです。

* 6 5 3 5 4 * 5 5
3 5 * * 5 * 5 4 5
5 7 6 5 6 5 8 6 6
5 7 6 3 6 * 5 6 5
4 7 * 1 4 4 5 6 *
4 5 4 3 * * 5 * 4
3 4 4 * 4 3 5 * *
* 7 5 5 5 4 5 5 6
* 6 4 * 5 4 5 5 5

いったいこれは何を意味するのでしょうか。


第15話へ 第31講第1話へ

戻る

VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)