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

第4話 細胞の作成の解説その2
コード例

               ・
               ・
            cn=0;
            zhy(); //細胞作成用座標の作成
            sbs(0); //細胞の作成
                 ・
                 ・
          }
        }
        //細胞の座標作成関数
        void zhy(){
          char i;
          for(i=0;i<4;i++){
             sx[i]=i%2;
             sy[i]=i/2;
          }
        }
        //細胞の作成関数
        void sbs(char
g){
          char i,j,k,h;
          for(i=1;i<5;i++){
             sb[sy[g]][sx[g]]=i;
             h=1;
             if(g>0){
               for(j=0;j<g;j++){
                 if(sb[sy[g]][sx[g]]==sb[sy[j]][sx[j]])h=0;
               }
             }
             if(h==1){
               if(g+1<4){
                 sbs(g+1);
               }
               else{
                 for(j=0;j<2;j++){
                   for(k=0;k<2;k++){
                     sbr[cn][j][k]=sb[j][k];
                   }
                 }
                 cn++;
               }
             }
           }
         }

              ・
              ・
解説の続き
再度強調します。セル番号
0123(世界の次元番号)

  0  1 

と、その世界に入る内容を明確に区別されてトレースをお読みになってください。
        void sbs(char g){
          char i,j,k,h;
          for(
i=1;i<5;i++){
とその世界(そのセル)に入る数字1234は次元番号0123に似ていますが、
1234はビール瓶のビールに相当するものですし、gである0123はビール瓶のラベルに相当するものです。

この自己再帰(関数の再帰的呼び出し)型プログラムでは、
『ライラの冒険』のように異なる次元の世界を行ったり来たりします。
その次元を示すものが、gなのです。
いま、どの次元世界(どのセル)にいるのかを明確に把握しないと、関数の再帰的呼び出しは理解できません。

異常に注意しながら、トレースをしてみます。
まず、
            cn=0;
は細胞総数カウンタの初期化です。

次の
            zhy(); //細胞作成用座標の作成

  0  1 

座標作成が行われます。1次元の次元番号gを2次元に並べるための座標と座標が作られます。
        //細胞の座標作成関数
        void zhy(){
          char i;
          for(i=0;i<4;i++){
             sx[i]=i%2;
             sy[i]=i/2;
          }
        }

ここのトレースは前話の通りです。
さて、
            sbs(0); //細胞の作成
によって細胞作成関数

        //細胞の作成関数
        void sbs(char
g){
          char i,j,k,h;
          for(i=1;i<5;i++){
             sb[sy[g]][sx[g]]=i;
             h=1;
             if(g>0){
               for(j=0;j<g;j++){
                 if(sb[sy[g]][sx[g]]==sb[sy[j]][sx[j]])h=0;
               }
             }
             if(h==1){
               
if(g+1<4){
                 sbs(g+1);
               }

               else{
                 for(j=0;j<2;j++){
                   for(k=0;k<2;k++){
                     sbr[cn][j][k]=sb[j][k];
                   }
                 }
                 cn++;
               }
             }
           }
         }
が呼び出され、いよいよ細胞の作成に入ります。

このコードを読む際に、注意しなければならない点は、
               if(g+1<4){
                 sbs(g+1);
               }
       

と再帰的に自分が呼び出されていることです。
自分が自分を呼び出していますが、呼び出す自分と呼び出される自分は異なる自分です。
入れ子式の人形の例えでは、呼び出される自分は呼び出す自分の内側にある人形です。
入れ子式人形が、さらに自分の内側の人形を呼び出すわけです。
入れ子式人形の例えで説明されたことを正確に説明し直しましょう。それは、

  0  1 

次元番号の世界から次元番号g+1の世界の呼び出しです。
最初、private: System::Void button1_Clickから
            sbs(0); //細胞の作成
によって、次元番号
の世界が呼び出されます。
次に、
               if(g+1<4){
                 sbs(g+1);
               }
 
によって、次元番号
の世界が次元番号の世界を呼び出します。   
さらに、次元番号
の世界は
               if(g+1<4){
                 sbs(g+1);
               }      
       
によって次元番号の世界を呼び出します。
ですから自分が自分を呼び出しているといっても、呼び出している自分と呼び出されている自分は次元の違う自分なのです。

では、再帰的呼び出しのトレースはどうなるのでしょう。次話を乞うご期待! 


                

第3話へ
第5話へ

戻る

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