第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のとき、

10


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から始まります。
   

10

したがって、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回目のループとなり、
 

10


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入門基礎講座