第16講 関数の再帰的呼び出しによる3次・4次魔方陣の作成
第6話 ソース解説その3

ここでは具体的にトレースしていきましょう。
#pragma endregion
  private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
           DateTime^ hj=DateTime::Now;
           n=int::Parse(textBox1->Text);
           s=0;
           f(0);
           int i;
           array<String^>^ x=gcnew array<String^>(16);
           x[9]=L"魔";x[10]=L"方";x[11]=L"陣";x[12]=L"総";x[13]=L"数";x[14]=L":";x[15]=s.ToString();
           for(i=0;i<9;i++)x[i]=L"";
           dataGridView1->Rows->Add(x);
           DateTime^ ow=DateTime::Now;
           TimeSpan sa=ow->Subtract(*hj);
           x[10]=L"時";x[11]=L"間";x[12]=L"計";x[13]=L"則";x[14]=L":";x[15]=(sa.TotalSeconds).ToString();
           for(i=0;i<10;i++)x[i]=L"";
           dataGridView1->Rows->Add(x);
        }
        void f(char
g){
           if(s==10)return;
           int i,j,k,h,x,y,xx,yy,wa;
           array<String^>^ w=gcnew array<String^>(16);
           x=g%n;
           y=g/n;
           for(
i=0;i<n*n;i++){
             a[y][x]=i+1;
             h=1;
             if(g>0){
               for(j=0;j<g;j++){
                 xx=j%n;
                 yy=j/n;
                 if(a[y][x]==a[yy][xx]){
                   h=0;
                   break;
                 }
               }
             }
             if(h==1){
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][x];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==n-1 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==0 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[n-j-1][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(g<n*n-1){
                 f(g+1);
               }
               else{
                 for(j=0;j<n;j++){
                   for(k=0;k<n;k++){
                      w[k]=(a[j][k]).ToString();
                   }
                   dataGridView1->Rows->Add(w);
                   }
                   for(j=0;j<16;j++)w[j]=L"";
                   dataGridView1->Rows->Add(w);
                   s++;
                   if(s==10)return;
                 }
               }
             }

          }
  };
}


g=0の世界

10 11
12 13 14 15


濃紺xy黄色gに対応)


g=0のときにいる世界は、
左の枠(セル)です。
枠(セル)番号gとセルの中に入る数字
明確に区別しないと、プログラムは訳の分からないものになります。
ソースで対応を確認しますと、
        void f(char g){
           if(s==10)return;
           int i,j,k,h,x,y,xx,yy,wa;
           array<String^>^ w=gcnew array<String^>(16);
           x=g%n;
           y=g/n;
           for(
i=0;i<n*n;i++){

             a[y][x]=i+1;
gが枠(セル)番号であり、iはその枠(セル)に入る数字です。


   i
=0のとき、

10


a[y][x]=i+1;から

10 11
12 13 14 15


となります。
g=0なので
             if(g>0){
               for(j=0;j<g;j++){
                 xx=j%n;
                 yy=j/n;
                 if(a[y][x]==a[yy][xx]){
                   h=0;
                   break;
                 }
               }
             }

は無視され、h=1は変わりませんから







             if(h==1){
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][x];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==n-1 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==0 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[n-j-1][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

    はすべて実行されますが、現在y=0x=0ですから、『x=3y=3x=3かつy=3x=0かつy=3』のいずれの条件も満たしません。
    したがって、
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

               if(y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][x];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

               if(x==n-1 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

               if(x==0 && y==n-1){
                 
wa=0;
                 for(j=0;j<n;j++)wa+=a[n-j-1][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

   はすべて実施されません。ですからh=1のままで、
             if(h==1){
               if(
g<n*n-1){
                 
f(g+1);
               }
               else{
                 for(j=0;j<n;j++){
                   for(k=0;k<n;k++){
                      w[k]=(a[j][k]).ToString();
                   }
                   dataGridView1->Rows->Add(w);
                   }
                   for(j=0;j<16;j++)w[j]=L"";
                   dataGridView1->Rows->Add(w);
                   s++;
                   if(s==10)return;
                 }
               }
             }

   が実行されます。g=0でg<n*n-1がクリアされf(g+1);が実行されg=1となります。
g=1の世界

10 11
12 13 14 15


g=1の世界はg=0の世界とは次元の違う世界です。


黄色の枠がg=0の世界であり、
ピンクの枠がg=1の世界です。
gが変わる度に異なる世界に移動するのです。

左の図を見れば全部で16異世界があることが分かります。
g=1ではピンクの世界のいるです。
この点をしっかりわきまえてトレースして下さい。
        void f(char g){
           if(s==10)return;
           int i,j,k,h,x,y,xx,yy,wa;
           array<String^>^ w=gcnew array<String^>(16);
           x=g%n;
           y=g/n;
           
for(i=0;i<n*n;i++){

             a[y][x]=i+1;
g=0とは異なる世界でから、for文はi=0から始まります。
   

10

したがって、a[y][x]=i+1;からa[y][x]=a[0][1]=1で、

   

10 11
12 13 14 15


となります。
g=1なので、今度は
             if(g>0){
               for(j=0;j<g;j++){
                 xx=j%n;
                 yy=j/n;
                 if(
a[y][x]==a[yy][xx]){
                   h=0;
                   break;
                 }
               }
             }

が実行さます。
g=1ですから、(j=0;j<g;j++)(j=0;j<1;j++)でfor文は一回だけ実施されます。
つまりj=0だけが実施されます。j=0より
xx=j%n=0%4=1=0yy=j/n=0/4=0
ですからa[y][x]==a[yy][xx]a[0][1]==a[0][0]です。

    ですから、if文          

                 if(a[y][x]==a[yy][xx]){
                   h=0;
                   break;
                 }              

    は実行されてしまい、h=0とりますから
             if(h==1){
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][x];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==n-1 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==0 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[n-j-1][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(g<n*n-1){
                 f(g+1);
               }
               else{
                 for(j=0;j<n;j++){
                   for(k=0;k<n;k++){
                      w[k]=(a[j][k]).ToString();
                   }
                   dataGridView1->Rows->Add(w);
                   }
                   for(j=0;j<16;j++)w[j]=L"";
                   dataGridView1->Rows->Add(w);
                   s++;
                   if(s==10)return;
                 }
               }
             }

     はすべて実行されず、i++によりi=1となり2回目のループとなり、
 

10


a[y][x]=i+1;からa[y][x]=a[0][1]=2より   

10 11
12 13 14 15


となります。
g=1なので、今度も
             if(g>0){
               for(j=0;j<g;j++){
                 xx=j%n;
                 yy=j/n;
                 if(
a[y][x]==a[yy][xx]){
                   h=0;
                   break;
                 }
               }
             }

は実行さますが、
a[0][1]=2a[0][0]=1ですから
if(a[y][x]==a[yy][xx])は行われず、h=1は書き換えられません。




     したがいまして、
             if(h==1){
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][x];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==n-1 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

             if(h==1){
               if(x==0 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[n-j-1][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }
    
は実行されますが前回と同じで現在y=0x=1ですから、『x=3y=3x=3かつy=3x=0かつy=3』のいずれでもありません。
    したがって、
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

               if(y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][x];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

               if(x==n-1 && y==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[j][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

               if(x==0 && y==n-1){
                 
wa=0;
                 for(j=0;j<n;j++)wa+=a[n-j-1][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }

    はすべて無視されまして、
             if(h==1){
               if(
g<n*n-1){
                 
f(g+1);
               }

    がf(g+1);遂行されてg=2の世界へと飛翔します。

以下は同様にして

10 11
12 13 14 15


   

10 11
12 13 14 15


10 11
12 13 14 15


10 11
12 13 14 15






















10 11
12 13 14 15


10 11
12 13 14 15


10 11
12 13 14 15


10 11
12 13 14 15


10 11
12 13 14 15






















    となっていきます。ここまで来てはじめて
             if(h==1){
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

    が実行されてh=0となり、以降はすべて無視されi++から

10 11
12 13 14 15

             

これも再び
             if(h==1){
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

に抵触し、i++が行われ

10 11
12 13 14 15


以後同様にして

16
10 11
12 13 14 15


まで来ても
             if(h==1){
               if(x==n-1){
                 wa=0;
                 for(j=0;j<n;j++)wa+=a[y][j];
                 if(wa!=n*(n*n+1)/2)h=0;
               }
             }

をクリアせずg=3の世界は終了してしまい、g=2の世界に戻り、
g=2の世界のi++により

10 11
12 13 14 15


となります。



















第6話も大分長くなりましたので、第6話これで閉め以降は第7話に譲ることにします。




第11講第6話へ
 第12講第1話へ 第14講第10話へ 第15講第10話へ 第16講第5話へ 第16講第7話へ




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