第16講 魔方陣汎用的生成プログラムへの挑戦
第6話 魔方陣汎用的自動生成プログラム解説その2
コード再掲
    f(0);
  }
  public static void f(int g){
    if(cn>20)return;
    int i,j,k,h;
    for(i=1;i<n*n+1;i++){
      h=1;
      m[y[g]][x[g]]=i;
      for(j=0;j<g;j++){
        if(m[y[g]][x[g]]==m[y[j]][x[j]]){
          h=0;
        }
      }
      for(j=0;j<g;j++){
        if(m[y[g]][x[g]]==m[y[j]][x[j]]){
          h=0;
        }
      }
      if(h==1){
        if(x[g]==n-1){
          w=0;
          for(j=0;j<n;j++){
            w+=m[y[g]][j];
          }
          if(w!=n*(n*n+1)/2)h=0;
        }
      }
      if(h==1){
        if(y[g]==n-1){
          w=0;
          for(j=0;j<n;j++){
            w+=m[j][x[g]];
          }
          if(w!=n*(n*n+1)/2)h=0;
        }
      }
      if(h==1){
        if(y[g]==n-1 && x[g]==0){
          w=0;
          for(j=0;j<n;j++){
            w+=m[j][n-1-j];
          }
          if(w!=n*(n*n+1)/2)h=0;
        }
      }
      if(h==1){
        if(y[g]==n-1 && x[g]==n-1){
          w=0;
          for(j=0;j<n;j++){
            w+=m[j][j];
          }
          if(w!=n*(n*n+1)/2)h=0;
        }
      }

      if(h==1){
        if(g+1<n*n){
          f(g+1);
          if(cn>20)return;
        }
        else{
          cn++;
          for(j=0;j<n;j++){
            for(k=0;k<n;k++){
              if(m[j][k]<10){
                System.out.print(" "+m[j][k]+" ");
              }
              else{
                System.out.print(m[j][k]+" ");
              }
            }
            System.out.println();
          }
          System.out.println();
          if(cn>20)return;
        }
      }
    }
  }
}
本日はいよいよこのプログラムの核=メイン=エンジンの部分の解説です。
4次魔方陣ですと、トレースに10話程度かかってしまいますので、
3次魔方陣でトレースしていきます。
それでも相当息の長いトレースになりますので、
忍耐強くお読みなってください。

この難解なプログラムを読み際に注意しなければならない点は、
第10講 関数の再帰的呼び出し
 第5話 関数の再帰的呼び出しによる汎用的順列作成プログラム解説その1

でも申し上げたとおり、giの役割の違いを明確にすることです。
この2つを明確に区別しないと、プログラムは訳のわからないものになってしまいます。
gはセル番号=空間識別番号であり、現在どこのセルを対象にしているかを示すものです。

 
0 0 1 2
1 3 4 5
2 6 7 8

つまり、上表のオレンジの番号に相当するものです。
そして、iはそこに入れる数字1から9です。
ビール瓶の例えでいえば、ビール瓶のラベルに相当するものがgであり、
瓶の中身であるビールに相当するのがiです。
引っ越しで使うダンボールを比喩とするならば、
ダンボールにマジックで下着などと書いてあるその文字に相当するのがgですし、
ダンボールの中に入っている下着に相当するのがiなのです。
iは1,2,3,4,5,6,7,8,9という数字であり、
gが0,1,2,3,4,5,6,7,8という数字なので、うっかりすると取り違えてしまいますが、
まったく別のものです。
gは空間識別番号でありセル番号です。
そして、関数の再帰的使用の場合入れ子式人形が3次魔方陣の場合9つできるわけですが、
入れ子式人形の番号です。ただし、外側から0番目、1番目、・・・というように0から数えます。
セル0と入れ子式人形0が対応しています。
セル番号と人形識別番号が一致しているのです。
ですから、gを空間を表す次元と呼びたいと思います。
9つのパラレルワールド(異世界)があり、gが変化することによってそのパラレルワールド(異世界)を行ったり来たりするのです。
gが異世界の次元番号を示すわけです。
そして、iはその異世界の中身です。
空間識別番号のgとその中身であるiを明確に区別して把握しないとこのプログラムは理解できません。
そして、各パラレルワールド(異世界)において、for文がそれぞれ実行され、iは1から9まで動くのです。
ですから、9次元ループになるのです。
理由は、入れ子式人形ですから、for文も入れ子式になるわけであるからです。

もちろん、4次魔方陣なら16次元ループ、5次魔方陣なら25次元ループ、6次魔方陣なら36次元ループ、
1000次魔方陣なら1000000次元ループになるのです。
1000000次元ループなどfor文では絶対に不可能ですね。
その高次元ループを可能にしているのが関数の再帰的使用=関数の自己再帰なのです。
関数の再帰的使用がいかに優れているかわかります。



第5話へ 第7話へ

戻る

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

初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第1部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第2部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第3部