第29講 細胞構成法による魔方陣の作成の普遍化△
第8話 普遍暫定版2コード解説
コード再掲
#pragma once
#include<stdlib.h>
#include<math.h>
int n,nn;
int a1[30][30],a2[30][30],a3[30][30],mah[30][30],a4[30][30],mah1[30][30],p[30][30],cn1[30],cn2[30];
int x[400],y[400],xx[400],yy[400];
int s;
char sbr[24][2][2];
char sb[2][2];
char sx[4],sy[4];
char cn;
char gkh;
namespace sbk1 {
・
・
・
#pragma endregion
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^
e) {
label2->Text=L"";
DateTime^ hj=DateTime::Now;
n=int::Parse(textBox1->Text);
char h=1,hh;
if(nn<3 || nn>=20 || nn==8 || nn==18){
label2->Text=L"TextBoxには3以上20未満で8,18以外の整数\r\nを入力し再度実行ボタンを\r\n押して下さい。";
h=0;
}
if(h==1){
if(nn==3 || nn==4 || nn%2==1)n=nn;
if(nn%4==2)n=nn/2;
if(nn!=4 && nn%4==0)n=nn/4;
}
・
・
・
if(h==1 && n!=3 && n%2==1 && nn!=10 && nn!=12 && nn!=14 && nn!=18){
・
・
・
if(h==1 && (nn==6 || nn==10 || nn==12 || nn==14 || nn==16)){
gkh=1;
s=0;
cn=0;
syokika();
if(n%2==1)g1(n);
if(n%2==0)g2(n);
zhy();
sbs(0);
sbg(0);
array<String^>^ w=gcnew array<String^>(31);
int i;
w[25]=nn.ToString();w[26]=L"次";w[27]=L"魔";w[28]=L"方";w[29]=L"陣";w[30]=s.ToString();
for(i=0;i<25;i++)w[i]=L"";
dataGridView1->Rows->Add(w);
DateTime^ ow=DateTime::Now;
TimeSpan sa=ow->Subtract(*hj);
w[25]=L"時";w[26]=L"間";w[27]=L"計";w[28]=L"則";w[29]=L":";w[30]=(sa.TotalSeconds).ToString();
for(i=0;i<25;i++)w[i]=L"";
dataGridView1->Rows->Add(w);
}
}
・
・
・
void g21(int n){
int i,j,m;
m=n/2;
for(i=0;i<n*n;i++){
if(i<n){
xx[i]=i;
yy[i]=i;
}
if(i>=n && i<2*n){
xx[i]=2*n-i-1;
yy[i]=i-n;
}
for(j=1;j<m+1;j++){
if((i>=2*n*j-j*j-j+2) && (i<2*n*j+n-j*j-2*j+1)){
yy[i]=j-1;
xx[i]=i-(2*n*j-j*j-j+2)+j;
if(xx[i]>=n-yy[i]-1)xx[i]++;
}
}
for(j=1;j<m+1;j++){
if((i>=2*n*j+n-j*j-2*j+1) && (i<2*n*j+2*n-j*j-3*j)){
xx[i]=j-1;
yy[i]=i-(2*n*j+n-j*j-2*j+1)+j;
if(xx[i]>=n-yy[i]-1)yy[i]++;
}
}
for(j=1;j<m;j++){
if((i>=3*m*m+m+(j-1)*(n-j)) && (i<3*m*m+j*(n-j))){
yy[i]=j+m-1;
xx[i]=i-(3*m*m+m+(j-1)*(n-j))+j+m;
}
}
for(j=2;j<m+1;j++){
if((i>=3*m*m+(j-1)*(n-(j-1))) && (i<3*m*m+m+(j-1)*(n-j))){
xx[i]=j+m-2;
yy[i]=i-(3*m*m+(j-1)*(n-(j-1)))+j+m-1;
}
}
}
}
void sbg(int g){
・
・
・
if(h==1){
if(g+1<n*n){
sbg(g+1);
}
else{
if(n!=3 && (n!=4 || gkh==0))f0(0);
if(n!=3 && (n!=4 || gkh==0))f0(0);
if(n==3)f1(0);
if(n==4 && gkh==1)f1(0);
}
}
}
}
void sbg1(int g){
if(s==1)return;
int i,j,k,h,w,ii,iii,l,o;
ii=rand()%24;
for(i=0;i<24;i++){
iii=(ii+i)%24;
for(j=0;j<2;j++){
for(k=0;k<2;k++){
a4[2*yy[g]+j][2*xx[g]+k]=sbr[iii][j][k];
}
}
h=1;
if(g==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a4[j][j];
}
if(w!=5*n)h=0;
}
if(h==1){
if(xx[g]==0 && yy[g]==n-1){
w=0;
for(j=0;j<2*n;j++){
w+=a4[j][2*n-1-j];
}
if(w!=5*n)h=0;
}
}
if(h==1){
if(yy[g]==0 && xx[g]==n-2){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a4[2*yy[g]+j][k];
}
if(w!=5*n){
h=0;
break;
}
}
}
}
if(h==1){
if(xx[g]==0 && yy[g]==n-2){
for(j=0;j<2;j++){
w=0;
for(k=0;k<2*n;k++){
w+=a4[k][2*xx[g]+j];
}
if(w!=5*n){
h=0;
break;
}
}
}
}
・
・
・
void f2(int g){
・
・
・
if(g<n*n-1){
f2(g+1);
}
else{
if(gkh==1){
for(j=0;j<n;j++){
for(k=0;k<n;k++){
for(l=0;l<2;l++){
for(o=0;o<2;o++){
mah[2*j+l][2*k+o]=4*(n*a1[j][k]+a2[j][k])+a3[2*j+l][2*k+o];
}
}
}
}
if(nn!=12 && nn!=16){
array<String^>^ w=gcnew array<String^>(30);
for(j=0;j<2*n;j++){
for(k=0;k<2*n;k++){
w[k]=(mah[j][k]).ToString();
}
dataGridView1->Rows->Add(w);
}
for(j=0;j<30;j++)w[j]=L"";
dataGridView1->Rows->Add(w);
s++;
if(s==1)return;
}
if(nn==12 || nn==16){
n=nn/2;
if(nn==12)for(j=0;j<1;j++)rand();
if(nn==16)for(j=0;j<1;j++)rand();
if(nn==20)for(j=0;j<8;j++)rand();
g21(n);
sbg1(0);
}
}
・
・
・
解説
nnは、今までn=n/2でもとのデータを保存しておかなかったので、もとのデータを残すために新しくグローバル変数として用意しました。
このnnによって、結局次のように場合分けされています。
Ⅰ nn=3またはnn=4
Ⅱ nnが奇数の場合
ⅰ 素数のとき
ⅱ 素数以外の奇数のとき
Ⅲ nnを4で割ったときの余りが2の場合
Ⅳ nnが4の倍数の場合
そして、まだコードを書いていませんが、
Ⅴ nnが8の場合
Ⅵ nnが20の場合
Ⅶ nnが18の場合
なぜ、この6つの場合に場合分けがなされるのでしょうか。
ⅠⅡについては、
Ⅰは、末項確定法を
Ⅱのⅰは、素数専用のf0とf00を
Ⅱのⅱは、奇数専用のkf1とfk2を
直接利用するからです。
Ⅲは、具体的には6,10,14ですがこれは2で割ったとき、素数です。
したがって、素数専用のf0とf00が利用でき、それを細胞構成法で倍加すれば完成します。
Ⅶは、2で割ったとき9で素数以外の奇数ですからkf1とfk2が利用できます。
そして、それを細胞構成法で倍加する点はⅢと同じです。
Ⅳは、具体的には12,16です。これは4で割ると、3または4であり末項確定法を利用してから、
細胞構成法で倍加を2回繰り返して、4倍化すればできます。
Ⅵの20もⅣに入りそうに思えますが、4で割ったとき5です。
もちろんこれも末項確定法を利用してもいいわけですが、
素数なので素数専用のf0とf00を利用した方が遙かに高速です。
最後Ⅴの8が残りました。これは2で割った4について末項確定法を利用してから、
細胞構成法で倍加すれば出来るというのが私の考えですが、
これについてはなぜかうまくいきません。
実行中に6次を作らせてから、8次を作らせるとうまくいくのですが、
実行してからすぐに8次を作らせようとすると出来ないのです。
今のところ原因がまったく解明できていません。
以上の説明から
Ⅰ 3または4
Ⅱⅰ 5,7,11,13,17,19
Ⅱⅱ 9,15
Ⅲ 6,10,14
Ⅳ 12,16
Ⅴ 8
Ⅵ 20
Ⅶ 18
の7群に分かれることがわかります。
そして、今回追加したのがⅣというわけです。
Ⅳにおいては、4で割ってから末項確定法を利用してから、細胞構成法を2回適用して4倍化しています。
最初の倍加をsbgが担当し、2回目の倍加をsbg1が担当しています。
両方ともsbgに担当させる手もあったのですが、
2回目の細胞合成のとき、sbgに担当させると、1回目の作った細胞合成が壊れてしまいます。
100個程度作らせるときには、1回目まで遡及することはありませんので、
それでもよかったのですが、理論的にはすべての場合を作るものにしたかったので、
1回目と2回目を別の関数に担当させたわけです。
そして、sbg1専用の座標作成関数g21も用意されたわけです。
第7話へ 第9話へ
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)