第22講 数独=ナンプレの自動生成
第6話 ランダムを入れて数独を自然なものにする
コード例
Dim m(9, 9), cn As Integer
Private Sub CommandButton1_Click()
  cn = 0
  f (0)
End Sub
Sub f(g As Integer)
  Dim x As Byte, y As Byte
  y = Int(g / 9)
  x = g Mod 9
  Dim i, j, k, zy, zx As Byte
  Dim cna As Integer, cns As Integer
  Dim xa As Byte, ya As Byte, xs As Byte, ys As Byte, kk As Byte, kkk As Byte
  xa = x Mod 3
  ya = y Mod 3
  xs = Int(x / 3)
  ys = Int(y / 3)
  
kk = 9 * Rnd()
  For i = 1 To 9
    
kkk = (kk + i) Mod 9 + 1
    m(x, y) =
k
    If x > 0 Then
      For j = 0 To x - 1
        If m(x, y) = m(j, y) Then GoTo tobi
      Next
    End If
    If y > 0 Then
      For j = 0 To y - 1
        If m(x, y) = m(x, j) Then GoTo tobi
      Next
    End If
    If ya > 0 Or xa > 0 Then
      For j = 0 To 2
        For k = 0 To 2
          If 3 * xs + j <> x And 3 * ys + k <> y Then
            If m(x, y) = m(3 * xs + j, 3 * ys + k) Then GoTo tobi
          End If
        Next
      Next
    End If
    If g + 1 < 81 Then
      f (g + 1)
    Else
      cna = cn Mod 9
      cns = Int(cn / 9)
      z = 0
      For j = 0 To 9
        If j Mod 3 = 0 Then
          For k = 0 To 12
            Cells(7 + 14 * cns + j + zy, 1 + 14 * cna + k) = "*"
          Next
          zy = zy + 1
        End If
        If j < 9 Then
          zx = 0
          For k = 0 To 9
            If k Mod 3 = 0 Then
              Cells(7 + 14 * cns + j + zy, 1 + 14 * cna + k + zx) = "*"
              zx = zx + 1
            End If
            If k < 9 Then Cells(7 + 14 * cns + j + zy, 1 + 14 * cna + k + zx) = m(j, k)
          Next
        End If
      Next
      cn = cn + 1
    End If
tobi:
  Next
  m(x, y) = 0
End Sub
Private Sub CommandButton2_Click()
  Cells.Select
  Selection.ClearContents
  Cells(1, 1).Select
End Sub
実行例

入門

解説
改良は、色を付けた部分だけです。
それなのに、かなり自然なものになっていますね。
  kk = 9 * Rnd()
  For i = 1 To 9
    
kkk = (kk + i) Mod 9 + 1
    m(x, y) =
k

この4行?ではありませんか。
トレースしてみましょう。
  kk = 9 * Rnd()
は、9未満の整数を発生させます。
例えば、それが4であったとしてトレースしてみましょう。
すると
i=1のとき、
kkk = (kk + i) Mod 9 + 1 = (4 + 1) Mod 9 + 1 = 5 + 1 = 6
i=2のとき、
kkk = (kk + i) Mod 9 + 1 = (4 + 2) Mod 9 + 1 = 6 + 1 = 7
i=3のとき、
kkk = (kk + i) Mod 9 + 1 = (4 + 3) Mod 9 + 1 = 7 + 1 = 8
i=4のとき
kkk = (kk + i) Mod 9 + 1 = (4 + 4) Mod 9 + 1 = 8 + 1 = 9
i=5のとき、
kkk = (kk + i) Mod 9 + 1 = (4 + 5) Mod 9 + 1 = 0 + 1 = 1

i=6のとき、
kkk = (kk + i) Mod 9 + 1 = (4 + 6) Mod 9 + 1 = 1 + 1 = 2
i=7のとき、
kkk = (kk + i) Mod 9 + 1 = (4 + 7) Mod 9 + 1 = 2 + 1 = 3
i=8のとき、
kkk = (kk + i) Mod 9 + 1 = (4 + 8) Mod 9 + 1 = 3 + 1 = 4
i=9のとき
kkk = (kk + i) Mod 9 + 1 = (4 + 9) Mod 9 + 1 = 4 + 1 = 5

というわけで、6,7,8,9,1,2,3,4,5と漏れなく再現していることがわかります。
kk = 4以外のトレースしても、始まりが異なっても結局は漏れなくすべてを再現していることを確認して下さい。

さらに、始まりだけでなくより自然なものにするには例えば、
  kk = 9 * Rnd()
  For i = 1 To 9
    
kkk = (kk + 4 * i ) Mod 9 + 1
    m(x, y) =
k

とします。kk = 3の場合でトレースしてみると
i=1のとき、
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 1) Mod 9 + 1 = 7 + 1 = 8
i=2のとき、
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 2) Mod 9 + 1 = 2 + 1 = 3
i=3のとき、
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 3) Mod 9 + 1 = 6 + 1 = 7
i=4のとき
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 4) Mod 9 + 1 = 1 + 1 = 2
i=5のとき、
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 5) Mod 9 + 1 = 5 + 1 = 6

i=6のとき、
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 6) Mod 9 + 1 = 0 + 1 = 1
i=7のとき、
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 7) Mod 9 + 1 = 4 + 1 = 5
i=8のとき、
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 8) Mod 9 + 1 = 8 + 1 = 9
i=9のとき
kkk = (kk + 4 * i) Mod 9 + 1 = (3 + 4 * 9) Mod 9 + 1 = 3 + 1 = 4

今回は、8,3,7,2,6,1,5,9,4とかなりランダム
(実際には規則性がある、4飛びになっているだけ)
に見えるように変化します。しかし、すべてが漏れなく重複なしに入っていることがわかります。
この場合で実行すると
C言語
と先ほどとは異なった結果になります。
  kk = 9 * Rnd()
  For i = 1 To 9
    kkk = (kk + 4 * i ) Mod 9 + 1
    m(x, y) = k
で選ばれる4 *の4は、任意の数字ではなく9と互いに素な数です。
9と互いに素な数とは、最大公約数が1しかない数です。
互いに素でない場合、漏れなく重複なしに再現することはできません。
試しに
  kk = 9 * Rnd()
  For i = 1 To 9
    kkk = (kk +
3 * i ) Mod 9 + 1
    m(x, y) = k
かつkk = 3の場合でトレースしてみると
i=1のとき、
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 1) Mod 9 + 1 = 6 + 1 = 7
i=2のとき、
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 2) Mod 9 + 1 = 0 + 1 = 1
i=3のとき、
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 3) Mod 9 + 1 = 3 + 1 = 4
i=4のとき
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 4) Mod 9 + 1 = 6 + 1 = 7
i=5のとき、
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 5) Mod 9 + 1 = 0 + 1 = 1

i=6のとき、
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 6) Mod 9 + 1 = 3 + 1 = 4
i=7のとき、
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 7) Mod 9 + 1 = 6 + 1 = 7
i=8のとき、
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 8) Mod 9 + 1 = 0 + 1 = 1
i=9のとき
kkk = (kk + 3 * i) Mod 9 + 1 = (3 + 3 * 9) Mod 9 + 1 = 3 + 1 = 4


となり、7,1,4,7,1,4,7,1,4と漏れもあり、重複もある結果になっています。
互いに素な数字を選べば必ず漏れなく重複なしに再現できるのに対して、
互いに素でない場合には、必ず漏れがあり重複があることを他の場合でトレースして確認してください。
以上で数独自動生成の講は終わりにします。
次は、数独問題を解くソフトVer.1に挑戦する予定です。

第5話へ 第23講第1話へ

004
  

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

数学研究室に戻る