マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第13章 様々な魔方陣の作成および自動生成
第8話 種についての解説


種は「たね」と読んでも「しゅ」と読んでもどちらでも結構です。

私も気分で言い換えています。

一文字の場合は「たね」と読みますし、

これから説明する一般種と特殊種では「しゅ」と読み分けています。




第1話で2本の対角線・すべて行・すべての列の合計が10なっていると申し上げました。

これを私は一般種と定義します。

実はもう一つ条件があります。

それは、使われている数字0,1,2,3,4がすべて5個ずつという条件です。

7次なら使われている数字がすべて7個であって、

2本の対角線・すべて行・すべての列の合計が同じものです。

この場合には2本の対角線・すべて行・すべての列の合計

0 + 1 + 2 + 3 + 4 + 5 + 6 = 17

は17になります。

そして、素数次では異なるずらし方をすれば異なる種となります。

ただし、5次の場合ずらし方が2ずらしと3ずらしかないので本質的には同一の魔方陣になってしまいます。

7次の場合はずらし方が2ずらし、3ずらし、4ずらしの3通りです。


0,1,2,3,4,5,6
1ずらしを行うと
6,0,1,2,3,4,5
2ずらしを行うと
5,6,0,1,2,3,4
3ずらしを行うと
4,5,6,0,1,2,3
4ずらしを行うと
3,4,5,6,0,1,2
5ずらしを行うと
2,3,4,5,6,0,1

で5通りではと思いますね。

しかし、対角線と副対角線のことを考えると1ずらしと5ずらしはないのです。

5次での例示になりますが、1つずらしだと対角線に0,0,0,0,0が並んでしまい合計は10になりません。


4ずらしだと副対角線に4,4,4,4,4が並んでしまい合計は10になりません。

4ずらしは逆1ずらしと同じなのです。

5次での例示になりましたが、7次の場合でも1ずらしと5ずらしはダメなのはご自分でエクセルなどを使って確認してください。

ですから1ずらしと5ずらしはだめなのです。


今まで作った種は実はもう一つの特徴がります。

それは、どの行・どの列・どの対角線にも0,1,2,3,4の異なる数字が並ぶのです。

このときその種を特殊種と呼びます。

もちろんすべての特殊種は一般種の条件を満たしますので、

一般種です。

一般種という集合の真部分集合として特殊種の集合があるわけです。

素数次のときの2ずらしなどはすべて一般種であり特殊種です。

素数次の言葉が連発されていますが、素数以外の奇数では成り立ちません。

ですが、ただ2つ認められる並びとずらし方があります。


先頭に真ん中の数字が配置されそれ以外は任意で素数次では禁じられていた1ずらしです。


もう1つは真ん中の数字が最後に来てそれ以外は任意でこれもそう数字では禁じられていた逆1ずらしです。

偶数ではこの様な便利な方法はありませんので、

自動生成を考えることになります。

6次で言えば0,1,2,3,4,5の数字が6個ずつで対角線の合計も行の合計も列の合計も

0 + 1 + 2 + 3 + 4 + 5 = 15になるものをコンピュータに探させるのです。

最後になりますが、もう一つ種には条件があります。

それは、2つの種はたねは直交しなければならないということです。

直交とは左の数字をy座標の数字をx座標として(プログラミングにおいては縦座標すなわりy座標、横座標すなわちx座標の順に書くことに注意!)
(0,0)、(0,1)、(0,2)、(0,3)、(0,4)
(1,0)、(1,1)、(1,2)、(1,3)、(1,4)
(2,0)、(2,1)、(2,2)、(3,3)、(4,4)
(3,0)、(3,1)、(3,2)、(3,3)、(3,4)
(4,0)、(4,1)、(4,2)、(4,3)、(4,4)
を作ったときに、重複するものがない場合です。上の2つの種は重複しないので直交しています。

ここで、なぜ2つの種が直交していなければならないのかを説明します。
魔方陣は

魔方陣=n*{種1}+{種2}+1

魔方陣=n*y+x+1

という式で作られます。
もし2つの種が直交していないと、
種1と種2の組み合わせ (y,x) がどこかで重複してしまいます。

すると

n*y+x+1

が同じ値になってしまい、
魔方陣の中に同じ数字が2回現れる ことになります。

これは魔方陣の定義に反します。
したがって、
2つの種は必ず直交していなければならない のです。
============復習=================
さて、なぜ魔方陣の種なのでしょうか。2つを並べて書いてみましょう。
  
そして左側の数字には5をかけて、対応する場所にある右側の数字を足します。

最後にすべてに1を加えます。

同じ数字の組み合わせがあれば同じ数字にってしまいます。
幸いに直交しているので1から25までの数字が一つずつ入っています。

============以上復習===============



つまり、2つ目の種をコンピュータに生成させるときに直交という条件が付け加わることです。

今回は説明ばかりになってしまい、混乱したかと思います。

ですが、プログラミングしながらここの説明を読んでいくとすべて頭に入れることができます。

ではと逆位置一ずらしを組み合わせて、

9次魔方陣を作成しましょう。これは生成ではありませんので、難しいプログラムではありません。


種1
4 0 6 7 1 3 2 8 5
5 4 0 6 7 1 3 2 8
8 5 4 0 6 7 1 3 2
2 8 5 4 0 6 7 1 3
3 2 8 5 4 0 6 7 1
1 3 2 8 5 4 0 6 7
7 1 3 2 8 5 4 0 6
6 7 1 3 2 8 5 4 0
0 6 7 1 3 2 8 5 4

種2
1 0 7 3 8 2 5 6 4
0 7 3 8 2 5 6 4 1
7 3 8 2 5 6 4 1 0
3 8 2 5 6 4 1 0 7
8 2 5 6 4 1 0 7 3
2 5 6 4 1 0 7 3 8
5 6 4 1 0 7 3 8 2
6 4 1 0 7 3 8 2 5
4 1 0 7 3 8 2 5 6


魔方陣表示
38 1 62 67 18 30 24 79 50
46 44 4 63 66 15 34 23 74
80 49 45 3 60 70 14 29 19
22 81 48 42 7 59 65 10 35
36 21 78 52 41 2 55 71 13
12 33 25 77 47 37 8 58 72
69 16 32 20 73 53 40 9 57
61 68 11 28 26 76 54 39 6
5 56 64 17 31 27 75 51 43
魔方陣です。

プロジェクト終了

難しいプログラムではありませんと書きましたが、4時間程度苦戦しました。

原因はsize_tにあったようです。

size_t は符号なし整数であるので逆順に使うときに問題を起こすようです。

今やっているのは作成ですからsize_tはすべてintでもよかったのです。

作成の場合計算量が少なくコンピュータは一瞬で計算してしまいます。

とりあえずfor文を逆順で使うときはintの方がよいことは覚えておいてよいでしょう。


        



第13章第7話へ 第13章9話へ

本講義トップへ