第12講 プロシージャの再帰的使用によって魔方陣を自動生成する
第7話 複雑なセル番号付けはいかにしたら可能か。
n=3のとき
| 0 | 5 | 3 |
| 6 | 1 | 7 |
| 4 | 8 | 2 |
n=4のとき
| 0 | 8 | 9 | 4 |
| 10 | 1 | 5 | 11 |
| 12 | 6 | 2 | 13 |
| 7 | 14 | 15 | 3 |
n=5のとき
| 0 | 9 | 10 | 11 | 5 |
| 12 | 1 | 13 | 6 | 14 |
| 15 | 16 | 2 | 17 | 18 |
| 19 | 7 | 20 | 3 | 21 |
| 8 | 22 | 23 | 24 | 4 |
n=6のとき
| 0 | 12 | 13 | 14 | 15 | 6 |
| 16 | 1 | 17 | 18 | 7 | 19 |
| 20 | 21 | 2 | 8 | 22 | 23 |
| 24 | 25 | 9 | 3 | 26 | 27 |
| 28 | 10 | 29 | 30 | 4 | 31 |
| 11 | 32 | 33 | 34 | 35 | 5 |
n=7のとき
| 0 | 13 | 14 | 15 | 16 | 17 | 7 |
| 18 | 1 | 19 | 20 | 21 | 8 | 22 |
| 23 | 24 | 2 | 25 | 9 | 26 | 27 |
| 28 | 29 | 30 | 3 | 31 | 32 | 33 |
| 34 | 35 | 10 | 36 | 4 | 37 | 38 |
| 39 | 11 | 40 | 41 | 42 | 5 | 43 |
| 12 | 44 | 45 | 46 | 47 | 48 | 6 |
偶数次のときと奇数次の場合では、番号付けの規則が違います。
その理由は、奇数次の場合対角線が交差するからです。
| 0 | 13 | 14 | 15 | 16 | 17 | 7 |
| 18 | 1 | 19 | 20 | 21 | 8 | 22 |
| 23 | 24 | 2 | 25 | 9 | 26 | 27 |
| 28 | 29 | 30 | 3 | 31 | 32 | 33 |
| 34 | 35 | 10 | 36 | 4 | 37 | 38 |
| 39 | 11 | 40 | 41 | 42 | 5 | 43 |
| 12 | 44 | 45 | 46 | 47 | 48 | 6 |
対角線以外でも数字の重複をいかに防ぐかが、
この番号割り振りの最大の攻防点になります。
そして、番号と座標をいかに対応させるかも、
非常に困難な課題です。
番号と座標を対応させるために
仮屋崎さんは
配列a(10, 10)とiz(100)とjz(100)の3つを用意します。
a(i, j)に番号を割り振ってから、
座標iz(100)とjz(100)との逆対応を考えるという手法をとる訳です。
(今回のプログラムは、
理論的には何時の魔方陣でも可能ですが、
実際的なところは4次が限界です。
ですから、配列の要素数は
a(3, 3)とiz(15)とjz(15)でも良い訳ですが、
一応将来のことを考えて10次まで作成可能なように、
配列の要素数を多めに取ってある訳です。
改良を加えていくと、
100次でも200次でも可能になります。
ですが、それは根本的な改良を加えてからの話です。
ですから、10次までの前提で話を進めます。)
数字の重複を防ぐために、
仮屋崎さんは次のような工夫をされます。
最初に
For文を使いすべてのa(i, j)に対してあり得ない番号
128などを割り振ります。
10次までの前提ですから、
あり得る数字は100までです。
そして、以下の手順でa(i, j)に番号を割り振っていきます。
① 右下がり対角線
② 左下がり対角線
③ 残りのセル
あり得ない番号128(Byte型の最大数)を割り振るのは、
②③のためです。
つまり、重複して番号を割り振らないためです。
どうするかお分かりですか。
ヒントはIf文を使います。
②③についてはカウンター(数を数える変数)を用意しておいて、
nに初期化しておきます。
初期化とは最初に設定しておきたい数字を代入することです。
つまり、カウンターの最初の値をnにしておくのです。
| 0 | 13 | 14 | 15 | 16 | 17 | 7 |
| 18 | 1 | 19 | 20 | 21 | 8 | 22 |
| 23 | 24 | 2 | 25 | 9 | 26 | 27 |
| 28 | 29 | 30 | 3 | 31 | 32 | 33 |
| 34 | 35 | 10 | 36 | 4 | 37 | 38 |
| 39 | 11 | 40 | 41 | 42 | 5 | 43 |
| 12 | 44 | 45 | 46 | 47 | 48 | 6 |
(7次の場合)
その理由は、左下がり対角線の始まりがnであるからです。
a(i, j)の番号割り振りができたら、
a(i, j)とiz(g)、jz(g)との逆対応を考えます。
といっても初心者の人にとっては難しすぎますから、
iz(a(i, j)) = i
jz(a(i, j)) = j
の部分を示しておきましょう。
さて、以上の考え方を聞いてもさっぱりわからない
という方がたくさんいらっしゃると思いますが、
一応、最低でも30分は試行錯誤をされてから、
どうしてもわからないときだけ、
次話をお読みください。
プログラミングをするには、
ときには何時間も考えなければならないときもあるものです。
粘り強く挑戦して頂きたいと思います。
初心者のためのc++ vc++ c言語 入門 基礎から応用までへ
初心者のための excel 2007 2010 2013 vba マクロ 入門 基礎から応用まで
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
vb講義トップへ
VB講義基礎へ
専門用語なしのC++入門へ
専門用語なしのJava入門へ
専門用語なしのVBA入門
数独のページ
魔方陣のページ
数学研究室に戻る
本サイトトップへ