第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の世界
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| □ | □ | □ | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
(濃紺はx、赤はy、黄色は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のとき、
      
  | 
    
a[y][x]=i+1;から
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | □ | □ | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 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=0でx=0ですから、『x=3、y=3、x=3かつy=3、x=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の世界
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | □ | □ | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
g=1の世界はg=0の世界とは次元の違う世界です。
| 0 | 1 | 
| □ | □ | 
黄色の枠が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から始まります。
   
      
  | 
    
したがって、a[y][x]=i+1;からa[y][x]=a[0][1]=1で、
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 1 | □ | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 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=0、yy=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回目のループとなり、 
      
  | 
    
a[y][x]=i+1;からa[y][x]=a[0][1]=2より
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | □ | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 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]=2でa[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=0でx=1ですから、『x=3、y=3、x=3かつy=3、x=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の世界へと飛翔します。
以下は同様にして
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | □ | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 1 | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 2 | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | 1 | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | 2 | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | 3 | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | 4 | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 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++から
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | 5 | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 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++が行われ
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | 6 | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 12 | 13 | 14 | 15 | 
| □ | □ | □ | □ | 
以後同様にして
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 3 | 16 | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 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++により
| 0 | 1 | 2 | 3 | |
| 0 | 0 | 1 | 2 | 3 | 
| 1 | 2 | 4 | □ | |
| 1 | 4 | 5 | 6 | 7 | 
| □ | □ | □ | □ | |
| 2 | 8 | 9 | 10 | 11 | 
| □ | □ | □ | □ | |
| 3 | 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入門基礎講座