第6講 数独を作ろう!
第5話 数独プログラムソース解説

では核心部分を再掲しましょう。
    ia = i Mod n
    ja = j Mod n
    If ia > 0 Then
      For l = 0 To ia - 1
        For m = 0 To n - 1
          If (j - ja + m) <> j And (i - ia + l) <> i Then
            If mah(i, j) = mah(i - ia + l, j - ja + m) Then GoTo owari
          End If
        Next
      Next
    End If

n=3の場合を例に説明しましょう。
ia=i mod nはiを3で割った余りです。
ja=j mod nも同様にjを3で割った余りです。
条件(j - ja + m) <> j And (i - ia + l) <> iは何を意味するでしょうか。
それは
mah(i, j)
mah(i - ia + l, j - ja + m)の比較は
それぞれが同じ行でも同じ列でもないときにのみ行いなさいという意味です。
なぜなら同じ行や列のときには同じ数字が入らないことは
   If j > 0 Then
      For l = 0 To j - 1
        If mah(i, l) = mah(i, j) Then GoTo owari
      Next
    End If
    If i > 0 Then
      For l = 0 To i - 1
        If mah(l, j) = mah(i, j) Then GoTo owari 
      Next
    End If
によって保証されているからです。
したがって、比較は行も列も異なっているときのみ行われます。
そして、比較してイコールならGoTo owariによって
    If g + 1 < n * n * n * n Then
      sakusei (g + 1)
    Else
      cn = cn + 1
      hyouji
    End If
の部分は実行されずNextによって、mah(i, j)には1つ大きくなった数字が入ります。
つまり、異なる行でかつ異なる列と比較して数字が異なるときにみ条件をクリアして
    If g + 1 < n * n * n * n Then
      sakusei (g + 1)
    Else
      cn = cn + 1
      hyouji
    End If
が実行され、gの次の世界に進みます。

具体例がないとわかりにくいと思いますので、

1 2 3 * 4 5 6 * 7 8 9
2 * *

具体例を出して再度説明しましょう。
現在青の世界にいるとします。
するとi=1,j=0ですからiaはiを3で割った余りなので
ia=1で
    If ia > 0 Then
      For l = 0 To ia - 1
        For m = 0 To n - 1
          If (j - ja + m) <> j And (i - ia + l) <> i Then
            If
mah(i, j) = mah(i - ia + l, j - ja + m) Then GoTo owari
          End If
        Next
      Next
    End If

が実行されます。
l=0,m=0のとき、
mah(i - ia + l, j - ja + m)
はi=1,ia=1,j=0,ja=0なので、
mah(0, 0)です。mah(i, j)mah(1, 0)なので同じ列であってはいけないという条件
(j - ja + m) <> j And (i - ia + l) <> i
を満たしませんから
          If (j - ja + m) <> j And (i - ia + l) <> i Then
            If
mah(i, j) = mah(i - ia + l, j - ja + m) Then GoTo owari
          End If

は実行されずNextによってm=1となります。このとき、
mah(i - ia + l, j - ja + m)mah(0, 1)です。mが1つ増えたのだから当然ですよね。
これは、mah(1, 0)と行も列も違いますから
If mah(i, j) = mah(i - ia + l, j - ja + m) Then GoTo owariが実行されます。

1 2 3 * 4 5 6 * 7 8 9
2 * *

ところがmah(1, 0)mah(0, 1) GoTo owariが実行されNextによって、
mah(1, 0)は次の値3が入り

1 2 3 * 4 5 6 * 7 8 9
3 * *

となります。そして、再び
      For l = 0 To ia - 1
        For m = 0 To n - 1
          If (j - ja + m) <> j And (i - ia + l) <> i Then
            If
mah(i, j) = mah(i - ia + l, j - ja + m) Then GoTo owari
          End If
        Next
      Next

が実行され前回と同様にmah(1, 0)mah(0, 1)の比較が行われます。
今回はmah(1, 0)=3,mah(0, 1)=2でIf mah(i, j) = mah(i - ia + l, j - ja + m) Then GoTo owari
はクリアしてm=2となります。

1 2 3 * 4 5 6 * 7 8 9
3 * *

そしてmah(1, 0)mah(0, 2)が比較されますが、残念ながら両方とも値は3ですから
GoTo owariが実行されNextによって、mah(1, 0)=4

1 2 3 * 4 5 6 * 7 8 9
4 * *

そして今回も
      For l = 0 To ia - 1
        For m = 0 To n - 1
          If (j - ja + m) <> j And (i - ia + l) <> i Then
            If
mah(i, j) = mah(i - ia + l, j - ja + m) Then GoTo owari
          End If
        Next
      Next

によって青mah(1, 0)とピンクmah(0, 1),mah(0, 2)
との比較が行われますが今回はいずれもクリアして
    If g + 1 < n * n * n * n Then
      sakusei (g + 1)
    Else
      cn = cn + 1
      hyouji
    End If

が実行され

1 2 3 * 4 5 6 * 7 8 9
4 1 * *

となります。そして、

1 2 3 * 4 5 6 * 7 8 9
4 1 * *

と比較され

1 2 3 * 4 5 6 * 7 8 9
4 3 * *

となりますが

1 2 3 * 4 5 6 * 7 8 9
4 3 * *

によって

1 2 3 * 4 5 6 * 7 8 9
4 5 * *

となり条件をクリアし

1 2 3 * 4 5 6 * 7 8 9
4 5 1 * *

同様に繰り返して

1 2 3 * 4 5 6 * 7 8 9
4 5 6 * *

なったとき初めて条件をクリアして

1 2 3 * 4 5 6 * 7 8 9
4 5 6 * 1 *

となります。
とにかく薄水色の部分に同じ数字が入っていないことを確認してください。

1 2 3 * 4 5 6 * 7 8 9
4 5 6 * 7 8 9 * 1 2 3
7 8 9 * 1 2 3 * 4 5 6

のときmah(i - ia + l, j - ja + m)は薄ピンクの範囲を動き
青はどの数字とも一致しない6が選ばれています。
もちろん
   If j > 0 Then
      For l = 0 To j - 1
        If mah(i, l) = mah(i, j) Then GoTo owari
      Next
    End If
    If i > 0 Then
      For l = 0 To i - 1
        If mah(l, j) = mah(i, j) Then GoTo owari 
      Next
    End If
がありますから黄色の数字とも異なるものになります。
結局以上の動きで一ブロック(小さな正方形)の中には同じ数字が並ばなくなり、
数独ができあがる訳です。
どうかご自分でi,j,l,mを動かしトレースして、
同じブロックには同じ数字が並ばないようになっていることをご確認頂ければと思います。

ではみなさん数独最後の課題です。
数独解答例
を改良して

1 2 3 * 4 5 6 * 7 8 9
4 5 6 * 7 8 9 * 1 2 3
7 8 9 * 1 2 3 * 4 5 6
* * * * * * * * * * *
2 1 4 * 3 6 5 * 8 9 7
3 6 5 * 8 9 7 * 2 1 4
8 9 7 * 2 1 4 * 3 6 5
* * * * * * * * * * *
5 3 1 * 6 4 2 * 9 7 8
6 4 2 * 9 7 8 * 5 3 1
9 7 8 * 5 3 1 * 6 4 2

のように小ブロックがわかるように間に*を入れるプログラムを考えましょう。
いじるのはhyouji()の部分だけです。皆さんがんばりましょう。

第4話へ 
第6話へ

VB入門講義応用編トップへ

VB入門講義トップへ