第10講 関数の学習
第8話 重複判定プログラムの改良と解説

関数f2は次のようにすることもできます。
void f2(void){
  char i;
  char j;
  char k;
  char l;
  String^ w=L"";
  char h=0;

  for(i=0;i<4;i++){
    for(j=0;j<4;j++){
      for(k=0;k<4;k++){
        for(l=0;l<4;l++){
          if((k!=i) | (l!=j)){
            if(a[i][j]==a[k][l]){
              h=1;
              break;
            }
          }
        }
        if(h==1)break;
      }
      if(h==1)break;
    }
    if(h==1)break;
  }
  if(h==0)label2->Text=L"数字の重複はありませんでした。";
  if(h==1)label2->Text=L"数字の重複がありました。";
}

(コピーペースト用

void f2(void){
char i;
char j;
char k;
char l;
String^ w=L"";
char h=0;

for(i=0;i<4;i++){
for(j=0;j<4;j++){
for(k=0;k<4;k++){
for(l=0;l<4;l++){
if((k!=i) | (l!=j)){
if(a[i][j]==a[k][l]){
h=1;
break;
}
}
}
if(h==1)break;
}
if(h==1)break;
}
if(h==1)break;
}
if(h==0)label2->Text=L"数字の重複はありませんでした。";
if(h==1)label2->Text=L"数字の重複がありました。";
}



これはかなり複雑です。
4次元ループになっているからです。

重複判定プログラムは、
私がコンピュータに魔法陣を作らせるということに精力的に取り組んでいた頃、
必要に迫られました。
単に人間が発見した魔方陣を再現させるのではなく、コンピュータに思考させ、自ら魔方陣を発見させるということ、
法則によってではなく、本当にコンピュータに試行錯誤で魔方陣を探し出させることに取り組み始めて、
比較的早い時期に基本的な発想を得ました。
しかし、その際に問題になったのが疑似魔方陣が生成してしまうという問題でした。
疑似魔方陣というのは、確かに縦横対角線の合計がすべて一致するのですが、
同じ数字が重複してしまっているものです。例を挙げると、

9 6 15 4
12 8 13 1
7 11 2 14
6 9 4 15

4次魔方陣は、1から16までの数字が1個ずつ入り、数字の重複のないものをいいます。
上の方陣は、ピンク薄緑の数字が重複してしまっています。
だから、本当の魔方陣ではなく疑似魔方陣です。
そこでプログラムを工夫して、重複がないようにするのかなり苦労しました。
私が作ったソフトは、26次魔方陣などを1秒で数百個の速さで作り、1分で1000以上作り出しました。
26次魔方陣当たりになると、できた魔方陣が疑似魔方陣でないかを人間の手で調べるのは、非常に大変な作業でした。
1から676までの数字がもれなく1個ずつ入っているかを調べなければならないからです。
自分が作った重複を避けるためのプログラムが本当に正しいものかを調べるのに、
手作業でやったのでは1個調べるのにも数分を要しました。これは本当に肩の凝る作業でした。
数千も数万もプログラムは立ち所に作り出しましたが、それがすべて正しいものであるか手作業で調べるのは当然不可能でした。
そこで、この重複判定プログラムが必要になったのです。
そして、最初に思いついたのが、4次元ループ
void f2(void){
  char i;
  char j;
  char k;
  char l;
  String^ w=L"";
  char h=0;

  for(i=0;i<4;i++){
    for(j=0;j<4;j++){
      for(k=0;k<4;k++){
        for(l=0;l<4;l++){
          if((k!=i) | (l!=j)){
            if(a[i][j]==a[k][l]){
              h=1;
              break;
            }
          }
        }
        if(h==1)break;
      }
      if(h==1)break;
    }
    if(h==1)break;
  }
  if(h==0)label2->Text=L"数字の重複はありませんでした。";
  if(h==1)label2->Text=L"数字の重複がありました。";
}
プログラムだったのです。後に、もっと簡単に重複をチェックするプログラムを考え出しました。
それが前話で紹介したものです。
この4次元ループプログラムを考えたときには、頭が爆発しそうになりました。
BASICからはじめて、パスカル、C言語、Quick Basicなどのプログラムの修行を積んできた私にとっても難問だったのです。
ですから、初心者の方がこれを読んでも理解できないのは、恥ずかしいことではありません。
もし、何の解説も受けずこれを理解できる初心者であったなら、あなたは天才ですし、是非ともプログラマーになるべきです。
初心者の方が理解できるように、かなり時間をかけて詳しく解説していきましょう。

プログラムが複雑すぎるので、
まず次のように改良したいと思います。
void f2(void){
  char i;
  char j;
  String^ w=L"";
  char h;

  for(i=0;i<4;i++){
    for(j=0;j<4;j++){
      h=f3(i,j);
      if(h==1)break;
    }
    if(h==1)break;
  }
  if(h==0)label2->Text=L"数字の重複はありませんでした。";
  if(h==1)label2->Text=L"数字の重複がありました。";
}

char f3(char s,char t){
  char i;
  char j;
  char h=0;
  for(i=0;i<4;i++){
    for(j=0;j<4;j++){
      if((i!=s) | (j!=t)){
        if(a[i][j]==a[s][t]){
          h=1;
          break;
        }
      }
    }
    if(h==1)break;
  }
  return(h);
}


(コピーペースト用

void f2(void){
char i;
char j;
String^ w=L"";
char h;

for(i=0;i<4;i++){
for(j=0;j<4;j++){
h=f3(i,j);
if(h==1)break;
}
if(h==1)break;
}
if(h==0)label2->Text=L"数字の重複はありませんでした。";
if(h==1)label2->Text=L"数字の重複がありました。";
}
char f3(char s,char t){
char i;
char j;
char h=0;
for(i=0;i<4;i++){
for(j=0;j<4;j++){
if((i!=s) | (j!=t)){
if(a[i][j]==a[s][t]){
h=1;
break;
}
}
}
if(h==1)break;
}
return(h);
}

関数char f3(char s,char t)は引数2個、戻り値1個の関数です。
戻り値は関数の性質から考えて何時でも1個ですが、引数は2個以上が可能だということはすでに学んでいます。
例えば、という関数は引数がx、y、zの3つですが戻り値は1個です。これは原点からその点(x,y,z)までの距離を返す関数です。
関数char f3(char s,char t)は、戻り値としては0か1のみを帰します。
0のときは重複なしを意味し、逆に1のときは重複ありを意味します。

4次元ループであったものが、それぞれ2次元ループになっています。
f2とf3の全体では、2×2=4で4次元ループなのですが、
単独では2次元ループです。
4次元が2次元に落ちただけで、プログラムはかなりわかりやすくなりました。
そして、f2とf3の役割の違いが明確になりました。
改良前だと、
for(i=0;i<4;i++){
  for(j=0;j<4;j++){
    for(k=0;k<4;k++){
      
for(l=0;l<4;l++){
        if((k!=i) | (l!=j)){
          if(a[i][j]==a[k][l]){
            h=1;
            break;
          }
        }
      }

      if(h==1)break;
    }
    if(h==1)break;
  }
  if(h==1)break;
}

ピンク紺色の役割の違いです。
改良前だと、役割の違いが見えなかったのですが、関数にすることによって役割に違いがあることが明確になったのです。

では、それぞれの役割とは何でしょうか。


第7話へ 第9話へ



初心者のためのJava 入門 基礎から応用まで
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第1部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第2部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第3部

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