第15講 3次魔方陣と4次魔方陣の作成

第4話 3次魔方陣と4次魔方陣の自動生成コード解説その1

コード再掲
Dim mah(4, 4) As Byte, x(16) As Byte, y(16) As Byte
Dim n As Byte, cn As Integer
Private Sub CommandButton1_Click()

  n = Cells(3, 8)
  cn = 0
  zhy
  ms (0)
  Cells(4, 12) = cn

End Sub


Sub zhy()

  Dim i As Byte
  For i = 0 To n * n - 1
    x(i) = i Mod n
    y(i) = Int(i / n)
  Next

End Sub


Sub ms(g As Byte)

  Dim i As Byte, j As Byte, k As Byte, a As Byte, b As Byte, w As Byte
  a = x(g)
  b = y(g)

  For i = 0 To n * n - 1
    mah(b, a) = i + 1
    If g > 0 Then
      For j = 0 To g - 1
        If mah(b, a) = mah(y(j), x(j)) Then GoTo tobi
      Next
    End If
    If a = n - 1 Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(b, j)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If
    If b = n - 1 Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(j, a)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If
    If (a = n - 1) And (b = n - 1) Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(j, j)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If
    If (a = 0) And (b = n - 1) Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(j, n - 1 - j)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If
    If g + 1 < n * n Then
      ms (g + 1)
    Else
      For j = 0 To n - 1
        For k = 0 To n - 1
          Cells(6 + j + Int(cn / 10) * (n + 1), 1 + k + (cn Mod 10) * (n + 1)) = mah(j, k)
        Next
      Next
      cn = cn + 1
    End If
tobi:
  Next

End Sub

Private Sub CommandButton2_Click()

  Rows("6:2000").Select
  Selection.ClearContents
  Cells(4, 12).Select
  Selection.ClearContents
  Cells(1, 1).Select

End Sub

では、コード解説を5話程度に渡って述べていきます。
非常に息の長い解説になりますので、粘り強くついてきていただければと思います。
基本は、第11講 Subプロシージャの再帰的使用の学習第3話 Subプロシージャ版順列作成
で行った順列作成と同じです。違いは、1次元の順列を2次元に並び直している点です。
また、順列の場合は重複がないかどうかのチェック以外ありませんでしたが、
魔方陣の場合は、

2 7 6
9 5 1
4 3 8

対角線や各列・各行の終わりにおいて、合計がn×(n×n+1)/2になっているかどうかをチェックします。
色違いになっているのは、ピンクは各行・各列の合計だけでなく、対角線の合計もチェックしなければならないからです。
n×(n×n+1)/2は何かというと、
方陣の中のすべての数字の和1+2+3+4+・・・+n×n=n×n×(n×n+1)/2をnで割ったものです。
nは行数や列数に中で結局は各行・各列の合計ということになります。
3次魔方陣を例にとれば、
3×3×(3×3+1)/2=45を3で割ったもので、3×(3×3+1)/2=15です。

例えば、
    If a = n - 1 Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(b, j)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If

2 7 6
9 5 1
4 3 8

各行の最後の列に達したとき、行合計が15になっているかをチェックしています。
同様に、
    If b = n - 1 Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(j, a)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If

2 7 6
9 5 1
4 3 8

各列の最後の行に到達したときに、列合計が15になっているかをチェックしています。

    If (a = n - 1) And (b = n - 1) Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(j, j)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If

2 7 6
9 5 1
4 3 8

対角線の最後に到達したとき、対角線の合計が15になるかを検査しています。

最後、
    If (a = 0) And (b = n - 1) Then
      w = 0
      For j = 0 To n - 1
        w = w + mah(j, n - 1 - j)
      Next
      If w <> Int(n * (n * n + 1) / 2) Then GoTo tobi
    End If

2 7 6
9 5 1
4 3 8

逆対角線の末項に来たとき、逆対角線の最後合計が15になっているかを調べています。







第3話へ 第5話へ

004
  


VBA講義第1部へ
vc++講義へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ

数学研究室に戻る