第28講 細胞構成法による魔方陣の作成△

第12話 
細胞合成の解説その1

コード再掲
         void sbg(int g){
           if(ks==200)return;
           int i,j,k,h,w,ii,iii;
           ii=rand()%24;
           for(i=0;i<24;i++){
             iii=(ii+i)%24;
             for(j=0;j<2;j++){
               for(k=0;k<2;k++){
                 a3[2*y[g]+j][2*x[g]+k]=sbr[iii][j][k];
               }
             }  
             h=1;
             if(g==n-1){
               w=0;
               for(j=0;j<2*n;j++){
                 w+=a3[j][j];
               }
               if(w!=5*n)h=0;
             }
             if(h==1){
               if(g==2*n-2){
                 w=0;
                 for(j=0;j<2*n;j++){
                   w+=a3[j][2*n-1-j];
                 }
                 if(w!=5*n)h=0;
               }
             }
             if(h==1){
               if(y[g]==0 && x[g]==n-2){
                 for(j=0;j<2;j++){
                   w=0;
                   for(k=0;k<2*n;k++){
                     w+=a3[2*y[g]+j][k];
                   }
                   if(w!=5*n){
                     h=0;
                     break;
                   }
                 }
               }
             }
             if(h==1){
             if(x[g]==0 && y[g]==n-2){
               for(j=0;j<2;j++){
                 w=0;
                 for(k=0;k<2*n;k++){
                   w+=a3[k][2*x[g]+j];
                 }
                 if(w!=5*n){
                   h=0;
                   break;
                 }
               }
             }
           }
           if(h==1){
           if(g>2*n-2 && x[g]==n-1){
             for(j=0;j<2;j++){
               w=0;
               for(k=0;k<2*n;k++){
                 w+=a3[2*y[g]+j][k];
               }
               if(w!=5*n){
                 h=0;
                 break;
               }
             }
           }
         }
         if(h==1){
           if(g>2*n-2 && y[g]==n-1){
             for(j=0;j<2;j++){
               w=0;
               for(k=0;k<2*n;k++){
                 w+=a3[k][2*x[g]+j];
               }
               if(w!=5*n){
                 h=0;
                 break;
               }
             }
           }
         }
         if(h==1){
           if(g==n*n-2){
             for(j=0;j<2;j++){
               w=0;
               for(k=0;k<2*n;k++){
                 w+=a3[k][2*x[g]+j];
               }
               if(w!=5*n){
                 h=0;
                 break;
               }   
             }
           }
         }
         if(h==1){
           if(g==n*n-1){
             for(j=0;j<2;j++){
               w=0;
               for(k=0;k<2*n;k++){
                 w+=a3[2*y[g]+j][k];
               }
               if(w!=5*n){
                 h=0;
                 break;
               }
             }
           }
         }
         if(h==1){
           if(g+1<n*n){
             sbg(g+1);
           }
           else{
             array<String^>^ w=gcnew array<String^>(15);
             for(j=0;j<2*n;j++){
               for(k=0;k<2*n;k++){
                 w[k]=(a3[j][k]).ToString();
               }
               dataGridView1->Rows->Add(w);
             }
             for(j=0;j<14;j++)w[j]=L"";
             dataGridView1->Rows->Add(w);
             ks++;
             if(ks==200)return;
           }
         }
       }
     } 
難解なプログラムである細胞の合成を解説しましょう。
基本的な考え方は、24個の細胞を適当に組み合わせて、行・列・対角線の合計が同じになるものを探すです。
ですから、
第17講 関数の再帰的呼び出しによる3次・4次魔方陣ソフトの改良再講義☆ 
 第1話 プログラムの改良(旧講義と共通)
 第2話 仮屋崎さんの天才的方法
 第3話 仮屋崎さんの天才的方法の解説

第20講 一般種法による魔方陣ソフトの高速化再講義☆
 第1話 一般種とは?(旧講義と共通)
 第2話 仮屋崎さんのエレガントな方法
 第3話 仮屋崎さんのエレガントな方法の解説
 第4話 仮屋崎さんのエレガントな方法その2
などと基本的な考え方は同じです。
ただし、各セルにはめ込むでいくのは、第17講や第20講とは違い単独の数字でなく細胞です。
細胞は3次元配列になっていて、char sbr[24][2][2];
sbr[i][j][k]の最初のiが細胞の番号になっていて、0から23までとなっています。
一般種法と同じで、まず対角線上に細胞を埋めていきます。
以下、6次の場合で解説していきます。

0 * *
* 0 *
* * 0

対角線が埋まった段階で、対角線の合計が同じになっているか調べます。

1 2 * * * *
3 4 * * * *
* * 1 2 * *
* * 3 4 * *
* * * * 1 2
* * * * 3 4

対角線の合計は細胞の平均の2倍(1+2+3+4)÷4×2=5の3倍になっていればよいです。
3倍というのは、今6次で解説しているからです。対角線の合計は15で条件をクリアです。そこで、

0 * 0
* 0 *
0 * 0
1 2 * * 1 2
3 4 * * 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4

今回も、運良く一回でクリアします。

0 1 0
* 0 *
0 * 0
1 2 1 2 1 2
3 4 3 4 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4

今回は、1行目の合計が一致しません。そこで

0 1 0
* 0 *
0 * 0
1 2 1 2 1 2
3 4 4 3 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4

そこで、2番目の細胞を組み込みますが、残念ながら合計は一致しません。以下

0 2 0
* 0 *
0 * 0
1 2 1 3 1 2
3 4 2 4 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4


0 3 0
* 0 *
0 * 0
1 2 1 3 1 2
3 4 4 2 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4


0 3 0
* 0 *
0 * 0
1 2 1 4 1 2
3 4 2 3 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4

となっていき最終的には、

0 23 0
* 0 *
0 * 0
1 2 4 3 1 2
3 4 2 1 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4

となりますが、これも1行目の合計は13で15にはなりません。

0 * 0
* 0 *
1 * 0
1 2 * * 1 2
3 4 * * 3 4
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
4 3 * * 3 4

となりますが、今度は逆対角線の合計も15にならず、

0 * 0
* 0 *
2 * 0
1 2 * * 1 2
3 4 * * 3 4
* * 1 2 * *
* * 3 4 * *
1 3 * * 1 2
2 4 * * 3 4

となり、今回は逆対角線の合計が15になりクリアです。そして、次に進みますが、

0 0 0
* 0 *
2 * 0
1 2 1 2 1 2
3 4 3 4 3 4
* * 1 2 * *
* * 3 4 * *
1 3 * * 1 2
2 4 * * 3 4

左右が

0
1 2
3 4

である限りは、

0

を何に変えても合計を15にすることは出来ません。左右が0ということは、その合計は6にすぎなく、
残り1個の細胞では差9を埋めることは出来ないからです。
結局、1行目をクリアするのは

0 3 17
* 0 *
0 * 0
1 2 1 4 3 4
3 4 2 3 1 2
* * 1 2 * *
* * 3 4 * *
1 2 * * 1 2
3 4 * * 3 4

となったときです。これは、オレンジの2行目の合計を15にして薄紺の1行目をやっとクリアします。
以下同様すべてがクリアするまで、このプログラムは試行錯誤を繰り返します。







第11話へ
第13話へ

戻る

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