第16講 関数の再帰的呼び出しによる3次・4次魔方陣の作成
第3話 仮屋崎さんの天才的方法の解説
void g(char n){
char i,j;
char b[10][10];
int cn=n;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
b[i][j]=-1;
}
}
for(i=0;i<n;i++){
b[i][i]=i;
}
for(i=0;i<n;i++){
if(b[i][n-1-i]==-1){
b[i][n-1-i]=cn;
cn++;
}
}
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(b[i][j]==-1){
b[i][j]=cn;
cn++;
}
}
}
for(i=0;i<n;i++){
for(j=0;j<n;j++){
x[b[i][j]]=j;
y[b[i][j]]=i;
}
}
}
では色別に順に解説していきましょう。
配列b[i][j]は、前話の「@座標から番号へ」の部分に相当します。
そして、 最初のピンクは準備です。
すべて配列の値を−1にしています。
-1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 |
そして、赤以降で配列b[i][j]の値が−1のときのみ書き換えられるようにしてあります。
これは重複を防ぐために用意されています。
尚、紺では重複の可能性がないのでif(b[i][j]==-1)が用意されていません。
重複については以下の説明を見れば分かります。
for(i=0;i<n;i++){
b[i][i]=i;
}
では
0 | -1 | -1 | -1 | -1 |
-1 | 1 | -1 | -1 | -1 |
-1 | -1 | 2 | -1 | -1 |
-1 | -1 | -1 | 3 | -1 |
-1 | -1 | -1 | -1 | 4 |
対角線に数字を入れていっています。
ここでは番号の重複は全く心配ありません。
そして、次の
for(i=0;i<n;i++){
if(b[i][n-1-i]==-1){
b[i][n-1-i]=cn;
cn++;
}
}
で逆対角線に順に番号を入れていきます。
0 | -1 | -1 | -1 | 5 |
-1 | 1 | -1 | -1 | -1 |
-1 | -1 | 2 | -1 | -1 |
-1 | -1 | -1 | 3 | -1 |
-1 | -1 | -1 | -1 | 4 |
0 | -1 | -1 | -1 | 5 |
-1 | 1 | -1 | 6 | -1 |
-1 | -1 | 2 | -1 | -1 |
-1 | -1 | -1 | 3 | -1 |
-1 | -1 | -1 | -1 | 4 |
そして、注目の場所にやってきました。
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | -1 | -1 | -1 | 5 | |
1 | -1 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | -1 | -1 | 3 | -1 | |
4 | -1 | -1 | -1 | -1 | 4 |
ここではじめて
if(b[i][n-1-i]==-1){
b[i][n-1-i]=cn;
cn++;
}
が活きます。
b[2][2]には、−1以外の番号がすでに入っています。
b[2][2]=2です。
ここは番号がすでに入っているわけですから、
入れてはいけないわけです。
そのためにif文があります。
これが重複チェックの意味です。if文が働いて b[2][2]ではなにもせず、
次に進み、
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | -1 | -1 | -1 | 5 | |
1 | -1 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | 7 | -1 | 3 | -1 | |
4 | -1 | -1 | -1 | -1 | 4 |
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | -1 | -1 | -1 | 5 | |
1 | -1 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | 7 | -1 | 3 | -1 | |
4 | 8 | -1 | -1 | -1 | 4 |
ここで注目すべきは、奇数次と偶数次に分ける必要がないということです。
もちろん偶数次の場合は、if文はすべて実行されます。偶数次の場合は、重複しませんでしたね。
さて、
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(b[i][j]==-1){
b[i][j]=cn;
cn++;
}
}
}
についてはもうお分かりでしょう。一番最初において
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | -1 | -1 | -1 | 5 | |
1 | -1 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | 7 | -1 | 3 | -1 | |
4 | 8 | -1 | -1 | -1 | 4 |
if文のチェックが早速生かされます。
b[0][0]にはすでに番号0が入っています。
すなわち、b[0][0]=0です。
よって、
if(b[i][j]==-1){
b[i][j]=cn;
cn++;
}
は実行されません。
したがって、スルーされて次に進み
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | 9 | -1 | -1 | 5 | |
1 | -1 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | 7 | -1 | 3 | -1 | |
4 | 8 | -1 | -1 | -1 | 4 |
となります。
以下
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | 9 | 10 | -1 | 5 | |
1 | -1 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | 7 | -1 | 3 | -1 | |
4 | 8 | -1 | -1 | -1 | 4 |
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | 9 | 10 | 11 | 5 | |
1 | -1 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | 7 | -1 | 3 | -1 | |
4 | 8 | -1 | -1 | -1 | 4 |
と進んでいき、
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | 9 | 10 | 11 | 5 | |
1 | 12 | 1 | -1 | 6 | -1 | |
2 | -1 | -1 | 2 | -1 | -1 | |
3 | -1 | 7 | -1 | 3 | -1 | |
4 | 8 | -1 | -1 | -1 | 4 |
再びif文のチェックが活きる場所に到達します。
b[1][1]=1です。
したがって、
if(b[i][j]==-1){
b[i][j]=cn;
cn++;
}
は実行されずスルーされます。
以下同様にして
y | ||||||
0 | 1 | 2 | 3 | 4 | x | |
0 | 0 | 9 | 10 | 11 | 5 | |
1 | 12 | 1 | 13 | 6 | 14 | |
2 | 15 | 16 | 2 | 17 | 18 | |
3 | 19 | 7 | 20 | 3 | 21 | |
4 | 8 | 22 | 23 | 24 | 4 |
と見事に重複せず番号付けが成功するのです。
最後の
for(i=0;i<n;i++){
for(j=0;j<n;j++){
x[b[i][j]]=j;
y[b[i][j]]=i;
}
}
の働きは何でしょう。
ここでは「A番号から座標へ」をやっています。
各番号にx座標とy座標を対応させています。
トレースしてみましょう。
b[0][0]=0です。
ですから、ループの最初は
x[b[0][0]]=x[0]=0
y[b[0][0]]=y[0]=0
次は、 b[0][1]=9ですから
x[b[0][1]]=x[9]=1
y[b[0][1]]=y[9]=0
以下同様に
b[0][2]=10
x[b[0][2]]=x[10]=2
y[b[0][2]]=y[10]=0
b[0][3]=11
x[b[0][3]]=x[11]=3
y[b[0][3]]=y[11]=0
b[1][0]=12
x[b[1][0]]=x[12]=0
y[b[1][0]]=y[12]=1
b[1][1]=1
x[b[1][1]]=x[1]=1
y[b[1][1]]=y[1]=1
b[1][2]=13
x[b[1][2]]=x[13]=2
y[b[1][2]]=y[13]=1
・
・
・
b[4][3]=24
x[b[4][3]]=x[24]=3
y[b[4][3]]=y[24]=4
b[4][4]=4
x[b[4][4]]=x[4]=4
y[b[4][4]]=y[4]=4
どうです。とってもシャープな方法ですよね。
番号から座標へとなっていますね。
仮屋崎さんは天才です。
第17講(再講義)第2話へ 第17講(旧講義)第8話へ
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座