第29講 細胞構成法による魔方陣の作成の普遍化△
第11話 普遍完成一歩前版コード解説
解説
18次は次の手順をたどっています。
if(nn==18)n=nn/2;→kf1(0);→ kf2(0);→
if(nn==18){
zhy();
sbs(0);
g1(n);
for(j=0;j<5;j++)rand();
sbg(0);
}→
void sbg(int g){
if(s==100)return;
int i,j,k,h,w,ii,iii,o,l;
・
・
・
if(h==1){
if(g+1<n*n){
sbg(g+1);
}
else{
if(nn!=18 && n!=3 && (n!=4 || gkh==0))f0(0);
if(nn!=18 && n==3)f1(0);
if(nn!=18 && n==4 && gkh==1)f1(0);
if(nn==18){
for(j=0;j<n;j++){
for(k=0;k<n;k++){
for(l=0;l<2;l++){
for(o=0;o<2;o++){
mah1[2*j+l][2*k+o]=4*(n*a1[j][k]+a2[j][k])+a3[2*j+l][2*k+o];
}
}
}
}
array<String^>^ w=gcnew array<String^>(30);
for(j=0;j<2*n;j++){
for(k=0;k<2*n;k++){
w[k]=(mah1[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
/*
int kr[9][9];
for(j=0;j<n*n;j++){
kr[xx[j]][yy[j]]=j;
}
for(j=0;j<n;j++){
for(k=0;k<n;k++){
w[k]=(kr[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
*/
for(j=0;j<30;j++)w[j]=L"";
dataGridView1->Rows->Add(w);
s++;
if(s==100)return;
}
まず最初に、18は2で割られ、9とされます。9は奇数で、if(h==1 && n!=3 && n%2==1 && nn!=10 && nn!=12 && nn!=14 && nn!=20)の対象とされます。
9について素数判定が行われ、素数でないのでkf1(0);が実行され1番目の種が作成されます。
続いて、kf2(0);が実行され2番目の種が作られます。
これらの種をもとに細胞構成法で倍加すれば18次ができあがりますので、細胞構成を行います。
そのため
if(nn==18){
zhy();
sbs(0);
g1(n);
for(j=0;j<5;j++)rand();
sbg(0);
}
の処理が行われます。sbgの
if(h==1){
if(g+1<n*n){
sbg(g+1);
}
else{
if(nn!=18 && n!=3 && (n!=4 || gkh==0))f0(0);
if(nn!=18 && n==3)f1(0);
if(nn!=18 && n==4 && gkh==1)f1(0);
if(nn==18){
において18次以外と18次に場合分けがされています。18次ついては
if(nn==18){
for(j=0;j<n;j++){
for(k=0;k<n;k++){
for(l=0;l<2;l++){
for(o=0;o<2;o++){
mah1[2*j+l][2*k+o]=4*(n*a1[j][k]+a2[j][k])+a3[2*j+l][2*k+o];
}
}
}
}
array<String^>^ w=gcnew array<String^>(30);
for(j=0;j<2*n;j++){
for(k=0;k<2*n;k++){
w[k]=(mah1[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
/*
int kr[9][9];
for(j=0;j<n*n;j++){
kr[xx[j]][yy[j]]=j;
}
for(j=0;j<n;j++){
for(k=0;k<n;k++){
w[k]=(kr[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
*/
for(j=0;j<30;j++)w[j]=L"";
dataGridView1->Rows->Add(w);
s++;
if(s==100)return;
}
の処理が行われます。
さて、
/*
int kr[9][9];
for(j=0;j<n*n;j++){
kr[x[j]][y[j]]=j;
}
for(j=0;j<n;j++){
for(k=0;k<n;k++){
w[k]=(kr[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
*/
の部分ですが、/*と*/で囲んであるので、現在は注釈文にされ働いていません。
なぜ、これを残しておいたかというと試行錯誤の過程を残しておきたかったからです。
コードに変更を加えるとき、
すんなりとはいきません。
スペリングミスや根本的な考え違いやケアレスミスなどがあるからです。
今回もすんなりいきませんでした。
ビルドして18を入力してから実行ボタンを押してもいつまでもデータグリッドビューに結果が表示されません。
その原因解明のためにとったのが注釈文にされている部分です。
番号付け
0 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 16 |
17 | 1 | 37 | 38 | 39 | 40 | 41 | 15 | 42 |
18 | 31 | 2 | 48 | 49 | 50 | 14 | 51 | 52 |
19 | 32 | 43 | 3 | 57 | 13 | 58 | 59 | 60 |
20 | 33 | 44 | 53 | 4 | 65 | 66 | 67 | 68 |
21 | 34 | 45 | 12 | 61 | 5 | 72 | 73 | 74 |
22 | 35 | 11 | 54 | 62 | 69 | 6 | 77 | 78 |
23 | 10 | 46 | 55 | 63 | 70 | 75 | 7 | 80 |
9 | 36 | 47 | 56 | 64 | 71 | 76 | 79 | 8 |
がうまくいっているかを確認したのです。
これによって番号付けに問題ないことがわかりました。
次に、sbgの合計チェックの部分
void sbg(int g){
if(s==100)return;
int i,j,k,h,w,ii,iii,o,l;
・
・
・
h=1;
/*
if(g==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][j];
}
if(w!=5*n)h=0;
}
if(h==1){
if(x[g]==0 && y[g]==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][2*n-1-j];
}
if(w!=5*n)h=0;
}
}
if(h==1){
if(y[g]==0 && x[g]==n-2){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a3[2*y[g]+j][k];
}
if(w!=5*n){
h=0;
break;
}
・
・
・
if(h==1){
if(g==n*n-1){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a3[2*y[g]+j][k];
}
if(w!=5*n){
h=0;
break;
}
}
}
}
*/
全体を注釈文にして動作を確認しました。
そうすると動きましたので、
if(g==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][j];
}
if(w!=5*n)h=0;
}
/*
if(h==1){
if(x[g]==0 && y[g]==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][2*n-1-j];
}
if(w!=5*n)h=0;
}
}
if(h==1){
if(y[g]==0 && x[g]==n-2){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a3[2*y[g]+j][k];
}
if(w!=5*n){
h=0;
break;
}
・
・
・
if(h==1){
if(g==n*n-1){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a3[2*y[g]+j][k];
}
if(w!=5*n){
h=0;
break;
}
}
}
}
*/
/*の位置を変更し、合計チェックの
if(g==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][j];
}
if(w!=5*n)h=0;
}
だけ有効にして動作確認をしました。
問題なく動作したので、さらに/*の位置を変更し、
if(g==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][j];
}
if(w!=5*n)h=0;
}
if(h==1){
if(x[g]==0 && y[g]==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][2*n-1-j];
}
if(w!=5*n)h=0;
}
}
/*
if(h==1){
if(y[g]==0 && x[g]==n-2){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a3[2*y[g]+j][k];
}
if(w!=5*n){
h=0;
break;
}
・
・
・
if(h==1){
if(g==n*n-1){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a3[2*y[g]+j][k];
}
if(w!=5*n){
h=0;
break;
}
}
}
}
*/
合計チェックを
if(g==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][j];
}
if(w!=5*n)h=0;
}
if(h==1){
if(x[g]==0 && y[g]==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a3[j][2*n-1-j];
}
if(w!=5*n)h=0;
}
}
まで有効にして動作を確認しました。
このようにして有効合計チェックの部分を広げていきます。
逆に言うと、無効化されている合計チェックの範囲を縮めていくと言うことです。
範囲を縮めていって、if(g>2*n+1 && yy[g]==n-1)(これは第9話の例ですが)の部分に原因があることを突き止めました。
そして、if(g>2*n+1 && yy[g]==n-1)をif(xx[g]>0 && xx[g]<n-1 && yy[g]==n-1)と変更するとうまくいことを確認したのです。
/*と*/や//などを使って、コードの1部を無効にして、動作確認をして、
動作を妨げている部分を突き止める方法是非とも覚えていただきたいと思います。
また、
/*
int kr[9][9];
for(j=0;j<n*n;j++){
kr[x[j]][y[j]]=j;
}
for(j=0;j<n;j++){
for(k=0;k<n;k++){
w[k]=(kr[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
*/
のような部分を付け加え、動作の一部(今回は番号付け)がちゃんと働いているかなどの確認も原因究明のための有効な方法です。
第10話へ 第12話へ
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)