第16講 魔方陣汎用的生成プログラムへの挑戦
第7話 魔方陣汎用的自動生成プログラム解説その3
コード再掲
    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;
        }
      }
    }
  }
}

ではトレースの旅を始めましょう。
f(0);で

   0 1  2
0
1
2

のピンク世界にとびます。

    for(i=1;i<n*n+1;i++){
      h=1;
      m[y[g]][x[g]]=i;

によって、ピンクのセル0に1から9まで入れていきます。最初の試行で、

   0 1  2
0
1
2

となります。
      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;
        }
      }
では何をしているでしょうか。まず、
      for(j=0;j<g;j++){
        if(m[y[g]][x[g]]==m[y[j]][x[j]]){
          h=0;
        }
      }
は数字の重複チェックです。各セルに同じ数字が入ってはいけないのでこれが入っています。
ただし、現時点ではf(0);ですからg=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(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;
        }
      }

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

の対象セルは、上の

 2
6
1
8



になります。
if(x[g]==n-1)
であるからです。
n-1は現在3次魔方陣を対象にしていますから2ですね。
 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;
        }
      }
では行合計(横合計)がn*(n*n+1)/2=3*(3*3+1)/2=15になっているかどうかをチェックしているのです。
次の
      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;
        }
      }
対象セルは

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

は上表の

2 4 3 8

です。if(y[g]==n-1)であるかです。
ここでも合計が15になるかどうかを調べているます。

      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;
        }
      }
の対象セルは

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

です。ここでは逆対角線

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

の合計が15になるかをチェックしています。
最後の
      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;
        }
      }
はもうお分かりですね。

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

対象セルは(2,2)であり、

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

対角線のセルの数字が合計され、それが15になっているかチェックしています。

ただし、現時点では

   0 1  2
0
1
2

ですから、
      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;
        }
      }
はいずれも実行されず、hは1のままで、
      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;
        }
      }
が実行されるわけです。g=0ですので、if文の肯定側が遂行され、

   0 1  2
0
1
2

の世界f(1)へと跳躍するのです。





第6話へ 第8話へ

戻る

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

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