第16講 関数の再帰的呼び出しによる3次・4次魔方陣の作成
第4話 ソース解説その1
さて、いよいよソースの解説です。
#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;
}
}
}
}
};
}
まず、
x=g%n;
y=g/n;
が1次元セル(枠)番号gを2次元に配置するために必要なものです。
g%nはgをnで割ったときの余り、g/nはgをnで割ったときの商ですが、yはint型なので小数部分は切り捨てられます。
n=4の場合でトレースしてみましょう。
g=0のときx=0%4=0、y=0/4=0より、a[y][x]はa[0][0]です。
g=1のときx=1%4=1、y=0/4=0より、a[y][x]はa[0][1]です。
g=2のときx=2%4=2、y=0/4=0より、a[y][x]はa[0][2]です。
g=3のときx=3%4=3、y=3/4=0より、a[y][x]はa[0][3]です。
g=4のときx=4%4=0、y=4/4=1より、a[y][x]はa[1][0]です。
g=5のときx=5%4=1、y=5/4=1より、a[y][x]はa[1][1]です。
g=6のときx=6%4=2、y=6/4=1より、a[y][x]はa[1][2]です。
g=7のときx=7%4=3、y=7/4=0より、a[y][x]はa[1][3]です。
g=8のときx=8%4=0、y=8/4=2より、a[y][x]はa[2][0]です。
g=9のときx=9%4=1、y=9/4=2より、a[y][x]はa[2][1]です。
g=10のときx=10%4=2、y=10/4=2より、a[y][x]はa[2][2]です。
g=11のときx=11%4=3、y=11/4=2より、a[y][x]はa[2][3]です。
g=12のときx=12%4=0、y=12/4=3より、a[y][x]はa[3][0]です。
g=13のときx=13%4=1、y=13/4=3より、a[y][x]はa[3][1]です。
g=14のときx=14%4=2、y=14/4=3より、a[y][x]はa[3][2]です。
g=15のときx=15%4=3、y=15/4=3より、a[y][x]はa[3][3]です。
結局gが次のように割り振られています。
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が2次元に配置し直されていることが分かります。
次の
xx=j%n;
yy=j/n;
ももうお分かりでしょう。これも番号j(<g)を2次元に割り振っています。
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 4 | 5 | 6 | 7 |
2 | 8 | 9 | 10 | 11 |
3 | 12 | 13 | 14 | 15 |
(赤の番号はxx、紺の番号はyy、水色の番号はjに対応)
つまり、
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=10なら
0 | 1 | 2 | 3 | |
0 | 0 | 1 | 2 | 3 |
1 | 4 | 5 | 6 | 7 |
2 | 8 | 9 | 10 | 11 |
3 | 12 | 13 | 14 | 15 |
0,1,2,3,4,5,6,7,8,9と比較して同じものがないかチェックしているのです。
同じ数字が入ってはいけないことは、魔方陣や順列の基本的な条件でした。
同じものがあるとき、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つ進みます。すなわち、a[y][x]=i+1も1つ進みます。
重複がなくなるまでa[y][x]=i+1は進んでいくのです。
このようにして数字の重複はなくなります。
第11講第6話へ 第12講第1話へ 第14講第10話へ 第15講第10話へ 第16講第3話へ 第16講第5話へ
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座