第30講 数独(ナンバープレイス)問題解決ソフトVer.1の制作
(数独(ナンバープレイス)問題作成ソフトに挑戦する人は☆☆)
第6話 問題データ以外の欄に数字をランダムに入れるコードの解説その2
コード再掲
#pragma endregion
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^
e) {
int i,j;
array<String^>^ x=gcnew array<String^>(15);
for(i=1;i<14;i++){
if(i%4==1)for(j=0;j<13;j++)x[j]=L"*";
if(i%4!=1)for(j=1;j<13;j++){
if(j%4==1)x[j]=L"*";
if(j%4!=1)x[j-1]=L"";
}
dataGridView1->Rows->Add(x);
}
}
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^
e) {
int i,j;
for(i=0;i<15;i++)dataGridView1->Rows->Add();
array<String^,2>^ w=gcnew array<String^,2>(15,100);
for(i=0;i<14;i++){
for(j=0;j<14;j++){
w[i,j]=static_cast<String^>(dataGridView1[j,i]->Value);
}
}
for(i=0;i<14;i++){
for(j=0;j<14;j++){
dataGridView1[j,15+i]->Value=w[i,j];
}
}
char k1=0,k2,a[9][9];
for(i=0;i<13;i++){
if(i%4==0)k1++;
if(i%4!=0){
k2=0;
for(j=0;j<13;j++){
if(j%4==0)k2++;
if(j%4!=0){
if(w[i,j]!=L"")a[i-k1][j-k2]=int::Parse(w[i,j]);
if(w[i,j]==L"")a[i-k1][j-k2]=0;
}
}
}
}
k1=0;
for(i=0;i<13;i++){
if(i%4==0)k1++;
if(i%4!=0){
k2=0;
for(j=0;j<13;j++){
if(j%4==0)k2++;
if(j%4!=0){
if(a[i-k1][j-k2]==0)dataGridView1[j,15+i]->Value=rand()%9+1;
}
}
}
}
}
}
};
}
解説の続き
for(i=0;i<14;i++){
for(j=0;j<14;j++){
w[i,j]=static_cast<String^>(dataGridView1[j,i]->Value);
}
}
については解説はいりませんね。
のデータを丸ごと読み取っています。
次の5行では、読み取ったデータをその2行下にコピー(ペーストといった方がよいでしょうか)しています。
for(i=0;i<14;i++){
for(j=0;j<14;j++){
dataGridView1[j,15+i]->Value=w[i,j];
}
}
さて、難解なのが最後の部分
char k1=0,k2,a[9][9];
for(i=0;i<13;i++){
if(i%4==0)k1++;
if(i%4!=0){
k2=0;
for(j=0;j<13;j++){
if(j%4==0)k2++;
if(j%4!=0){
if(w[i,j]!=L"")a[i-k1][j-k2]=int::Parse(w[i,j]);
if(w[i,j]==L"")a[i-k1][j-k2]=0;
}
}
}
}
k1=0;
for(i=0;i<13;i++){
if(i%4==0)k1++;
if(i%4!=0){
k2=0;
for(j=0;j<13;j++){
if(j%4==0)k2++;
if(j%4!=0){
if(a[i-k1][j-k2]==0)dataGridView1[j,15+i]->Value=rand()%9+1;
}
}
}
}
}
です。
k1やk2の役割、if(i%4==0)k1++;とif(j%4==0)k2++;の意味、さらにif(i%4!=0){とif(j%4!=0){の意味が把握できないとこのコードは理解することが出来ません。
その前にa[9][9]はなぜ9行9列の2次元配列にされているのでしょうか。
数独は、本来9×9の2次元データです。
for(i=0;i<14;i++){
for(j=0;j<14;j++){
w[i,j]=static_cast<String^>(dataGridView1[j,i]->Value);
}
}
において、14行14列の2次元データとして扱われているのは、外との境界やブロックの境界を示す『*』が入っているからです。
その境界線を除くと、9行9列のデータになります。
14行14列と9行9列の違いから、k1とk2が必要となってきます。
つまり、k1とk2は行数と列数の違いを埋める役割を持っています。
では、if(i%4==0)k1++;とif(j%4==0)k2++;の意味はなんでしょうか。
をご覧になればお分かりのように境界線は、4行ごとそして4列ごとに引かれています。
そして、dataGridViewの場合は、行も列も0から始まります。つまり、0行目、0列目から始まります。
そうすると、境界線は0行目・4行目・8行目・12行目、0列目・4列目・8列目・12列目に引かれています。
0・4・8・12は、すべて4で割ったとき余りは0です。
ですから、if(i%4==0)k1++;とif(j%4==0)k2++;は余計な行数と列数をカウントしています。
すると、if(i%4!=0){とif(j%4!=0){の役割は明らかですね。
0・4・8・12の数字のとき以外、つまり1・2・3・5・6・7・9・10・11のときに実行しなさいという意味です。
1・2・3までのときは、余計な行数や列数は1ですよね。
したがって、if(w[i,j]!=L"")a[i-k1][j-k2]=int::Parse(w[i,j]);とif(w[i,j]==L"")a[i-k1][j-k2]=0;はそれぞれ、
if(w[i,j]!=L"")a[i-1][j-1]=int::Parse(w[i,j]);とif(w[i,j]==L"")a[i-1][j-1]=0;です。
5・6・7のときには、余計な行数および列数は2です。このときは、
if(w[i,j]!=L"")a[i-k1][j-k2]=int::Parse(w[i,j]);とif(w[i,j]==L"")a[i-k1][j-k2]=0;はそれぞれ、
if(w[i,j]!=L"")a[i-2][j-2]=int::Parse(w[i,j]);とif(w[i,j]==L"")a[i-2][j-2]=0;です。
最後9・10・11のときは、余計な行数と列数は3で、
if(w[i,j]!=L"")a[i-k1][j-k2]=int::Parse(w[i,j]);とif(w[i,j]==L"")a[i-k1][j-k2]=0;はそれぞれ、
if(w[i,j]!=L"")a[i-3][j-3]=int::Parse(w[i,j]);とif(w[i,j]==L"")a[i-3][j-3]=0;です。
以上から
for(i=0;i<13;i++){
if(i%4==0)k1++;
if(i%4!=0){
k2=0;
for(j=0;j<13;j++){
if(j%4==0)k2++;
if(j%4!=0){
if(w[i,j]!=L"")a[i-k1][j-k2]=int::Parse(w[i,j]);
if(w[i,j]==L"")a[i-k1][j-k2]=0;
}
}
}
}
によって、14行14列から必要な9行9列のデータだけを拾っていることがわかります。
k1=0;
for(i=0;i<13;i++){
if(i%4==0)k1++;
if(i%4!=0){
k2=0;
for(j=0;j<13;j++){
if(j%4==0)k2++;
if(j%4!=0){
if(a[i-k1][j-k2]==0)dataGridView1[j,15+i]->Value=rand()%9+1;
}
}
}
}
の部分はご自分で考えてください。
では次の課題です。今回は空いてるセルにランダムに数字を入れたので、まったく数独(ナンバープレイス)になっていませんでした。
そこで、次回では行の条件(横の条件)、行に同じ数字が入ってはいけないを加えましょう。
第5話へ 第7話へ
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)