第10講 プロシージャの再帰的使用による魔方陣の自動生成
第5話 n次魔方陣自動生成ソフト
n次魔方陣生成ソフトコード例
Module Module1

  Dim cn, x(25), n As Integer
  Sub Main() '私は社長だ。
    Console.WriteLine ("これはすべてのn次方陣を求めるソフトです。")
    Console.WriteLine ("何次の方陣を発生させるのかをnに入力し")
    Console.WriteLine ("エンターするとn次方陣がすべて生成されます。")
    Console.Write ("n=")
    n = Console.ReadLine()
    cn = 0
    f (0)
    Console.WriteLine("生成された{0:d}次方陣は{1:d}個です。", n, cn)
  End Sub

  Sub f(g As Integer)
    Dim i, j, k, h, hh, w As Integer
    For i = 0 To n * n - 1
      If g = 0 Then x(g) = i + 1
      h = 1
      If g > 0 Then
        For j = 0 To g - 1
          If x(j) = i + 1 Then
            h = 0
            Exit For
          End If
        Next
        If h = 1 Then x(g) = i + 1
      End If
      If h = 1 Then
        If g + 1 < n * n Then
          f (g + 1)
        Else
          hh = 1
          For j = 0 To n - 1
            w = 0
            For k = 0 To n - 1
              w += x(n * j + k)
            Next
            If w <> Int(n * (n * n + 1) / 2) Then
              hh = 0
              Exit For
            End If
          Next
          If hh = 1 Then
            For j = 0 To n - 1
              w = 0
              For k = 0 To n - 1
                w += x(n * k + j)
              Next
              If w <> Int(n * (n * n + 1) / 2) Then
                hh = 0
                Exit For
              End If
            Next
          End If
          
If hh = 1 Then
            w = 0
            For j = 0 To n - 1
              w += x(n * j + n - 1 - j)
            Next
            If w <> Int(n * (n * n + 1) / 2) Then
              hh = 0
              Exit For
            End If
          End If
          If hh = 1 Then
            w = 0
            For j = 0 To n - 1
              w += x(n * j + j)
            Next
            If w <> Int(n * (n * n + 1) / 2) Then
              hh = 0
              Exit For
            End If
          End If

          If hh = 1 Then
            cn += 1
            For j = 0 To n - 1
              For k = 0 To n - 1
                Console.Write("{0:d} ", x(n * j + k))
              Next
              Console.WriteLine()
            Next
            Console.WriteLine()
          End If
        End If
      End If
    Next
  End Sub

End Module


実行結果例
これはすべてのn次魔方陣を求めるソフトです。
何次の魔方陣を発生させるのかをnに入力し
エンターするとn次魔方陣がすべて生成されます。
n=3
2 7 6
9 5 1
4 3 8

2 9 4
7 5 3
6 1 8

4 3 8
9 5 1
2 7 6

4 9 2
3 5 7
8 1 6

6 1 8
7 5 3
2 9 4

6 7 2
1 5 9
8 3 4

8 1 6
3 5 7
4 9 2

8 3 4
1 5 9
6 7 2

生成された3次魔方陣は8個です。


              w += x(n * j + n - 1 - j)
が大変わかりにくいと思いますが、
トレースするとわかります。n = 3 を前提にトレースします。
j = 0 とき、
              w += x(3 * 0 + 3 - 1 - 0)
              w += x(0 + 3 - 1 - 0)
              w += x(2)
j = 1 とき、
              w += x(3 * 1 + 3 - 1 - 1)
              w += x(3 + 3 - 1 - 1)
              w += x(4)
j = 2 とき、
              w += x(3 * 2 + 3 - 1 - 2)
              w += x(6 + 3 - 1 - 2)
              w += x(6)
ですから、

0 1 2
3 4 5
6 7 8

(数字はgを示す。)
見事に逆対角線上を動いています。
              w += x(n * j + j)
についても各自でレースして下さい。


粘り強く待ち続ければ、4次魔方陣でもすべて生成して、
7040個をコンソール画面に表示します。
前に20分程度で全部が生成出来ると書きましたが、
私の記憶違いのようで、実際には今の段階では全部生成するには、
10時間ぐらいかかりそうです。

これからいろいろと改善していく最終的には、
26次魔方陣でさえ1秒で数百の単位で生成できるようにもって行きます。
そこでどのぐらいスピードアップしているのかがわかるように計算にかかった時間がわかるように改善します。
コードは次のようになります。
Module Module1

  Dim cn, x(25), n As Integer
  Sub Main() '私は社長だ。
    Console.WriteLine("これはすべてのn次方陣を求めるソフトです。")
    Console.WriteLine("何次の方陣を発生させるのかをnに入力し")
    Console.WriteLine("エンターするとn次方陣がすべて生成されます。")
    Console.Write("n=")
    n = Console.ReadLine()
    cn = 0
    
Dim hj, ow As Object
    hj = Timer
    f(0)
    ow = Timer
    
Console.WriteLine("魔方陣生成にかかった時間は{0:f6}秒です。", ow - hj)
    Console.WriteLine("生成された{0:d}次方陣は{1:d}個です。", n, cn)
  End Sub
以下は同じ

で実行結果は
これはすべてのn次魔方陣を求めるソフトです。
何次の魔方陣を発生させるのかをnに入力し
エンターするとn次魔方陣がすべて生成されます。
n=3
2 7 6
9 5 1
4 3 8

2 9 4
7 5 3
6 1 8

4 3 8
9 5 1
2 7 6

4 9 2
3 5 7
8 1 6

6 1 8
7 5 3
2 9 4

6 7 2
1 5 9
8 3 4

8 1 6
3 5 7
4 9 2

8 3 4
1 5 9
6 7 2

魔方陣生成にかかった時間は0.203130秒です。
生成された3次魔方陣は8個です。

となります。
このできの悪いプログラムでも3次ならおよそ0.2秒ですべて生成できます。

少しずつ改良していって最終的には26次魔方陣でも、
1秒で数百の単位で生成できるように持って行きますが、
この第10講の改良では、4次魔方陣が
021
(時間計測はC言語プログラミングの場合)
すべてを約10分程度生成するのが関の山です。
5次魔方陣はおそらく1時間待っても1個も出てこないでしょう。
尚、4次以降では上図のように二桁になりますので、
表示も二桁対応に変更して下さい。

このコードがわかりにくい最大の理由は、
グローバル配列が
  Dim cn, x(25), n As Integer
と1元配列になっているということです。
皆さん、これを2次元配列
  Dim cn, mah(5, 5), n As Integer
にしてソフトを作り直して下さい。
x座標とy座標を導入しますので、
いままで魔方陣の各値を入力する配列名をxとしてきましたが、
以降はmahに変更します。

第4話へ   第6話へ

002

初心者のための excel 2016 マクロ VBA 入門講義 基礎から応用まで
vc** c言語 c** 入門 初心者 基礎から応用まで
eclipse c** 入門
魔方陣 数独で学ぶ VBA 入門

数独のシンプルな解き方・簡単な解法の研究
VB講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C**入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)
初心者のための VC**による C言語 C++ 入門 基礎から応用まで第1部
eclipse java 入門
java 入門 サイト 基礎から応用まで
本サイトトップへ