第18講 一般種法×末項確定法(魔方陣作成マクロVer.4)への挑戦

第8話 番号付けのコード解説その4(水平思考の世界)

4
-1 -1 -1
-1 -1 -1
-1 -1 -1 -1
-1 -1 -1
4 -1 -1 -1

今回は一番難解な
Private Sub CommandButton1_Click()
  Dim i, j As Integer
  n = Cells(3, 8)
  Rnd (-1)
  syokika
  zhy
  zhy1 (0)
  zhykakunin
  'ms (0)
End Sub
      ・
      ・
Sub zhy1(g As Byte)
  Dim i As Byte
  For i = g + 1 To n - 1
    If a(g, i) = -1 Then
      a(g, i) = gk
      gk = gk + 1
    End If
  Next
  zhy2 (g)
End Sub

Sub zhy2(g As Byte)
  Dim i As Byte
  Dim j As Byte
  For i = g + 1 To n - 1
    If a(i, g) = -1 Then
      a(i, g) = gk
      gk = gk + 1
    End If
  Next
  If g + 1 < n Then
    zhy1 (g + 1)
  Else
    For i = 0 To n - 1
      For j = 0 To n - 1
        y(a(i, j)) = i
        x(a(i, j)) = j
      Next
    Next
    tm = 1
    Exit Sub
  End If
End Sub
を解説します。これで番号付けコードの解説は終わりです。
次話から、Subプロシージャmsの改良に取りかかります。
Subプロシージャzhy1は行を、zhy2は列を担当します。
行数と列数は、それぞれnです。
5次魔方陣の場合は、それぞれ5です。

4
-1 -1 -1
-1 -1 -1
-1 -1 -1 -1
-1 -1 -1
4 -1 -1 -1

0行目と0列目もちゃんと数えてください。
対角線と逆対角線の番号付けが終わった後、
Sub CommandButton1_Clickのzhy1 (0)によって、
行専用Subプロシージャzhy1の0行目に飛びます。
zhy1 (0)の括弧内の数字は、行数を表します。
そして、ループ処理
  For i = g + 1 To n - 1
    If a(g, i) = -1 Then
      a(g, i) = gk
      gk = gk + 1
    End If
  Next
によって、1行目に番号が割り振られますが、
番号が割り振られるのは、If文
    If a(g, i) = -1 Then
      a(g, i) = gk
      gk = gk + 1
    End If
から、仮番号−1のセルのみですから、順に9,10,11と割り振られます。
逆対角線の処理によってgk=9になっていたからです。

4
10 11
-1 -1 -1
-1 -1 -1 -1
-1 -1 -1
4 -1 -1 -1

ループ処理が終わると、
zhy2 (g)によって列専用Subプロシージャzhy1の0列目に飛びます。
g=0であったからです。
Sub zhy2(g As Byte)
  Dim i As Byte
  Dim j As Byte
  For i = g + 1 To n - 1
    If a(i, g) = -1 Then
      a(i, g) = gk
      gk = gk + 1
    End If
  Next
  If g + 1 < n Then
    zhy1 (g + 1)
  Else
    For i = 0 To n - 1
      For j = 0 To n - 1
        y(a(i, j)) = i
        x(a(i, j)) = j
      Next
    Next
    tm = 1
    Exit Sub
  End If
End Sub
ループ処理
  For i = g + 1 To n - 1
    If a(i, g) = -1 Then
      a(i, g) = gk
      gk = gk + 1
    End If
  Next
によって番号が割り振られますが、If文がありますので、
仮番号−1のセルのみに本番号が割り振られ、

4
10 11
12 -1 -1
13 -1 -1 -1
14 -1 -1
4 -1 -1 -1


となります。
ループ処理の後If文
  If g + 1 < n Then
    zhy1 (g + 1)
  Else
    For i = 0 To n - 1
      For j = 0 To n - 1
        y(a(i, j)) = i
        x(a(i, j)) = j
      Next
    Next
    tm = 1
    Exit Sub
  End If
に到達します。
  If g + 1 < n Then
    zhy1 (g + 1)
がこのコーティングのミソです。
g+1が5未満ならzhy1 (g + 1)へ飛びなさいです。
現在g=0でしたからzhy1 (g + 1)はzhy1 (1)で、行専用Subプロシージャzhy1の1行目に飛ぶことになります。
ループ処理の始まりに注目して下さい。
Sub zhy1(g As Byte)
  Dim i As Byte
  For i = g + 1 To n - 1
    If a(g, i) = -1 Then
      a(g, i) = gk
      gk = gk + 1
    End If
  Next
  zhy2 (g)
End Sub
g+1です。つまり、今は1です。
1列目からの番号付けになっています。
0列目は番号がついていますので、
0列目から処理したのでは、明らかに時間の無駄です。
速さが絶対条件である魔方陣作成においては、
少しの無駄も許されません。
ここでも、If文によって仮番号−1のセルだけが書き直されます。

4
10 11
12 15 16
13 -1 -1 -1
14 -1 -1
4 -1 -1 -1

そして、zhy2 (g)によって再び列専用Subプロシージャzhy2に飛びますが、
今回はg=1ですから、1列目に飛ぶわけです。
そして、ここでも−1のセルだけが書き換わり、

4
10 11
12 15 16
13 17 -1 -1
14 -1 -1
4 18 -1 -1




















以下同様に進み

4
10 11
12 15 16
13 17 19 20
14 21 23
4 18 22 24


となって番号付けが完成するのです。
この見事なコードを考えた人も仮屋崎さんです。
私は、最初に考えたコードは数列を使う複雑なものでしたが、
この方法は実にすっきりしています。
私のコードが垂直思考だったのに対して、
仮屋崎さんの方法は、水平思考といえます。
垂直思考と水平思考ではどちらが創造的な思考であるかはいうまでもありません。
プログラミングには、水平思考が必要です。
水平思考によって、飛躍的なプログラミングが可能になります。
水平思考は無限の可能性をプログラミンに開きます。
創造的プログラミング=水平思考です。
水平思考が出来たとき、
プログラミングは本当に楽しくなります。
油田でない場所をいくら垂直に掘っていっても、
石油に遭遇することはありません。
掘る場所を少し変更するだけで、新しい可能性が開かれるのです。






第7話へ 第9話へ

004
  

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

数学研究室に戻る