第16講 関数の再帰的呼び出しによる3次・4次魔方陣の作成
第6話 ソース解説その3
ここでは具体的にトレースしていきましょう。
#pragma endregion
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^
e) {
DateTime^ hj=DateTime::Now;
n=int::Parse(textBox1->Text);
s=0;
f(0);
int i;
array<String^>^ x=gcnew array<String^>(16);
x[9]=L"魔";x[10]=L"方";x[11]=L"陣";x[12]=L"総";x[13]=L"数";x[14]=L":";x[15]=s.ToString();
for(i=0;i<9;i++)x[i]=L"";
dataGridView1->Rows->Add(x);
DateTime^ ow=DateTime::Now;
TimeSpan sa=ow->Subtract(*hj);
x[10]=L"時";x[11]=L"間";x[12]=L"計";x[13]=L"則";x[14]=L":";x[15]=(sa.TotalSeconds).ToString();
for(i=0;i<10;i++)x[i]=L"";
dataGridView1->Rows->Add(x);
}
void f(char g){
if(s==10)return;
int i,j,k,h,x,y,xx,yy,wa;
array<String^>^ w=gcnew array<String^>(16);
x=g%n;
y=g/n;
for(i=0;i<n*n;i++){
a[y][x]=i+1;
h=1;
if(g>0){
for(j=0;j<g;j++){
xx=j%n;
yy=j/n;
if(a[y][x]==a[yy][xx]){
h=0;
break;
}
}
}
if(h==1){
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][x];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==n-1 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==0 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[n-j-1][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(g<n*n-1){
f(g+1);
}
else{
for(j=0;j<n;j++){
for(k=0;k<n;k++){
w[k]=(a[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
for(j=0;j<16;j++)w[j]=L"";
dataGridView1->Rows->Add(w);
s++;
if(s==10)return;
}
}
}
}
};
}
g=0の世界
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
□ | □ | □ | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
(濃紺はx、赤はy、黄色はgに対応)
□ |
g=0のときにいる世界は、
左の枠(セル)です。
枠(セル)番号gとセルの中に入る数字
明確に区別しないと、プログラムは訳の分からないものになります。
ソースで対応を確認しますと、
void f(char g){
if(s==10)return;
int i,j,k,h,x,y,xx,yy,wa;
array<String^>^ w=gcnew array<String^>(16);
x=g%n;
y=g/n;
for(i=0;i<n*n;i++){
a[y][x]=i+1;
gが枠(セル)番号であり、iはその枠(セル)に入る数字です。
i=0のとき、
|
a[y][x]=i+1;から
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | □ | □ | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
となります。
g=0なので
if(g>0){
for(j=0;j<g;j++){
xx=j%n;
yy=j/n;
if(a[y][x]==a[yy][xx]){
h=0;
break;
}
}
}
は無視され、h=1は変わりませんから
if(h==1){
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][x];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==n-1 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==0 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[n-j-1][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
はすべて実行されますが、現在y=0でx=0ですから、『x=3、y=3、x=3かつy=3、x=0かつy=3』のいずれの条件も満たしません。
したがって、
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
if(y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][x];
if(wa!=n*(n*n+1)/2)h=0;
}
if(x==n-1 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][j];
if(wa!=n*(n*n+1)/2)h=0;
}
if(x==0 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[n-j-1][j];
if(wa!=n*(n*n+1)/2)h=0;
}
はすべて実施されません。ですからh=1のままで、
if(h==1){
if(g<n*n-1){
f(g+1);
}
else{
for(j=0;j<n;j++){
for(k=0;k<n;k++){
w[k]=(a[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
for(j=0;j<16;j++)w[j]=L"";
dataGridView1->Rows->Add(w);
s++;
if(s==10)return;
}
}
}
が実行されます。g=0でg<n*n-1がクリアされf(g+1);が実行されg=1となります。
g=1の世界
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | □ | □ | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
g=1の世界はg=0の世界とは次元の違う世界です。
0 | 1 |
□ | □ |
黄色の枠がg=0の世界であり、
ピンクの枠がg=1の世界です。
gが変わる度に異なる世界に移動するのです。
左の図を見れば全部で16異世界があることが分かります。
g=1ではピンクの世界のいるです。
この点をしっかりわきまえてトレースして下さい。
void f(char g){
if(s==10)return;
int i,j,k,h,x,y,xx,yy,wa;
array<String^>^ w=gcnew array<String^>(16);
x=g%n;
y=g/n;
for(i=0;i<n*n;i++){
a[y][x]=i+1;
g=0とは異なる世界でから、for文はi=0から始まります。
|
したがって、a[y][x]=i+1;からa[y][x]=a[0][1]=1で、
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 1 | □ | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
となります。
g=1なので、今度は
if(g>0){
for(j=0;j<g;j++){
xx=j%n;
yy=j/n;
if(a[y][x]==a[yy][xx]){
h=0;
break;
}
}
}
が実行さます。
g=1ですから、(j=0;j<g;j++)は(j=0;j<1;j++)でfor文は一回だけ実施されます。
つまりj=0だけが実施されます。j=0より
xx=j%n=0%4=1=0、yy=j/n=0/4=0
ですからa[y][x]==a[yy][xx]はa[0][1]==a[0][0]です。
ですから、if文
if(a[y][x]==a[yy][xx]){
h=0;
break;
}
は実行されてしまい、h=0とりますから
if(h==1){
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][x];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==n-1 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==0 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[n-j-1][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(g<n*n-1){
f(g+1);
}
else{
for(j=0;j<n;j++){
for(k=0;k<n;k++){
w[k]=(a[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
for(j=0;j<16;j++)w[j]=L"";
dataGridView1->Rows->Add(w);
s++;
if(s==10)return;
}
}
}
はすべて実行されず、i++によりi=1となり2回目のループとなり、
|
a[y][x]=i+1;からa[y][x]=a[0][1]=2より
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | □ | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
となります。
g=1なので、今度も
if(g>0){
for(j=0;j<g;j++){
xx=j%n;
yy=j/n;
if(a[y][x]==a[yy][xx]){
h=0;
break;
}
}
}
は実行さますが、
a[0][1]=2でa[0][0]=1ですから
if(a[y][x]==a[yy][xx])は行われず、h=1は書き換えられません。
したがいまして、
if(h==1){
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][x];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==n-1 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
if(h==1){
if(x==0 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[n-j-1][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
は実行されますが前回と同じで現在y=0でx=1ですから、『x=3、y=3、x=3かつy=3、x=0かつy=3』のいずれでもありません。
したがって、
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
if(y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][x];
if(wa!=n*(n*n+1)/2)h=0;
}
if(x==n-1 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[j][j];
if(wa!=n*(n*n+1)/2)h=0;
}
if(x==0 && y==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[n-j-1][j];
if(wa!=n*(n*n+1)/2)h=0;
}
はすべて無視されまして、
if(h==1){
if(g<n*n-1){
f(g+1);
}
がf(g+1);遂行されてg=2の世界へと飛翔します。
以下は同様にして
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | □ | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 1 | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 2 | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | 1 | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | 2 | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | 3 | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | 4 | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
となっていきます。ここまで来てはじめて
if(h==1){
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
が実行されてh=0となり、以降はすべて無視されi++から
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | 5 | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
これも再び
if(h==1){
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
に抵触し、i++が行われ
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | 6 | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
以後同様にして
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 3 | 16 | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
まで来ても
if(h==1){
if(x==n-1){
wa=0;
for(j=0;j<n;j++)wa+=a[y][j];
if(wa!=n*(n*n+1)/2)h=0;
}
}
をクリアせずg=3の世界は終了してしまい、g=2の世界に戻り、
g=2の世界のi++により
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 2 | 4 | □ | |
1 | 4 | 5 | 6 | 7 |
□ | □ | □ | □ | |
2 | 8 | 9 | 10 | 11 |
□ | □ | □ | □ | |
3 | 12 | 13 | 14 | 15 |
□ | □ | □ | □ |
となります。
第6話も大分長くなりましたので、第6話これで閉め以降は第7話に譲ることにします。
第11講第6話へ 第12講第1話へ 第14講第10話へ 第15講第10話へ 第16講第5話へ 第16講第7話へ
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座