第4講 数独を解くソフトの開発(1)
第3話 m(i, j)への入力順を確定する

001
を実現するプログラム例
Dim n As Byte, m(8, 8) As Byte, cn As Integer, hnt As Byte 'nは数独の一辺、x(15)は数独を収納する配列、cnは数独総数をカウント、hntはヒント数
Dim iz(80) As Byte, jz(80) As Byte 'iz(80)はy座標を収納する配列、jz(80)はx座標を収納する配列
Private Sub CommandButton1_Click()
  CommandButton2_Click
  n = 9
  cn = 0
  Randomize (Timer) 'シード値を時間から取得
  dainyu 'シートのB4からJ12のセルからm(i, j)に代入することが任務
'  f (0) '数独解答作成プロシージ
  hyouji
End Sub
Sub dainyu() 'シートのB4からJ12のセルからm(i, j)に代入することが任務
  Dim i As Byte, j As Byte
, w As Byte
  hnt = 0
  
w = 0
  For i = 0 To n - 1
    For j = 0 To n - 1
      If Cells(4 + i, 2 + j) > 0 Then 'シートが空欄""でないときにシートの値を代入
        m(i, j) = Cells(4 + i, 2 + j)
        hnt = hnt + 1 'ヒント数をカウント
      End If
      If Cells(4 + i, 2 + j) = "" Then 'シートが空欄""であるときに0を代入
        m(i, j) = 0
        
iz(w) = i
        jz(w) = j
        w = w + 1

      End If
    Next
  Next
End Sub
Sub hyouji()
  Dim i As Byte, j As Byte
  
For i = 0 To n - 1
    For j = 0 To n - 1
      If m(i, j) > 0 Then Cells(14 + i, 2 + j) = "*" 'ヒントの数字があるところは*を表示
    Next
  Next

  
For i = 0 To n * n - hnt - 1
    Cells(14 + iz(i), 2 + jz(i)) = i 'ヒントの数字がないところは入力順を表示
  Next

  Cells(8, 12) = "ヒント数は"
  Cells(9, 12) = hnt
  Cells(10, 12) = "です。"
End Sub
Sub f(g As Byte)
  Dim i As Byte, j As Byte, h As Byte, w As Byte
  Dim y As Byte, x As Byte, yy As Byte, xx As Byte, ii As Byte, iii As Byte
  y = Int(g / n)
  x = g Mod n
  ii = Int(n * Rnd)
  For i = 0 To n - 1
    iii = (i + ii) Mod n '1から9までの数字を代入
    m(y, x) = iii + 1
    h = 1
    If x > 0 Then '行の重複を検査して、重複がある場合にはhを0として以下の処理をさせない。
      For j = 0 To x - 1
        If m(y, x) = m(y, j) Then
          h = 0
          Exit For
        End If
      Next
    End If
    If h = 1 And y > 0 Then '列の重複を検査して、重複がある場合にはhを0として以下の処理をさせない。
      For j = 0 To y - 1
        If m(y, x) = m(j, x) Then
          h = 0
          Exit For
        End If
      Next
    End If
    If h = 1 And y > 0 Then 'ブロックの重複を検査して、重複がある場合にはhを0として以下の処理をさせない。
      For j = 0 To n - 1
        xx = 3 * Int(x / 3) + (j Mod 3)
        yy = 3 * Int(y / 3) + Int(j / 3)
        If x = xx And y = yy Then Exit For
        If x <> xx And y <> yy Then
          If m(yy, xx) = m(y, x) Then
            h = 0
            Exit For
          End If
        End If
      Next
    End If
    If h = 1 Then
      If g + 1 < n * n Then '行・列・ブロックの重複がなく、g + 1がn * n以下のときに、次のセル番号の世界に飛ぶ
        f (g + 1)
        If cn = 10 Then Exit Sub '数独が10個生成した段階で探索をやめさせている。
      Else
        cn = cn + 1 '数独総数カウント
        If cn = 10 Then Exit Sub '数独が10個生成した段階で探索をやめさせている。
      End If
    End If
  Next
End Sub
Private Sub CommandButton2_Click()
  Rows("14:30000").Select
  Selection.ClearContents
  Range("L7:L10").Select
  Selection.ClearContents
  Cells(1, 1).Select
End Sub

参考ダウンロード添付ファイル

準備がそろいましたので、
  f (0) '数独解答作成プロシージ
を改良しから
'  f (0) '数独解答作成プロシージ
の’を外して問題を解かせてください。
001
時間のところはあえて隠してあります。
疑似数独のヒント数0数独を1個あたり0.000083秒辺りで生産しましたが、
いったいどのぐらいの時間で解けるのでしょうか。

ヒントを書いておきましょう。
ヒント数0の疑似数独解答を生成するには、
過去のみ(セル番号の若いセル)との重複の検査すればよかったのですが、
問題を解く場合にはすでに
001
セルに数字が入っていますので、
すべての行・列・ブロックのセルについて重複検査をしなければなりません。
ですから、例えば
    If h = 1 And y > 0 Then
      For j = 0 To n - 1
        xx = 3 * Int(x / 3) + (j Mod 3)
        yy = 3 * Int(y / 3) + Int(j / 3)
        
If x = xx And y = yy Then Exit For
        If x <> xx And y <> yy Then
          If m(yy, xx) = m(y, x) Then
            h = 0
            Exit For
          End If
        End If
      Next
    End If
ピンクの部分は削らなければなりませんし、
行部分と列部分にも改良が必要となります。





第2話へ 第4話へ


トップへ