
Here is an example solving Sudoku puzzle having three different types of 9 X 9, 16 X 16, and 25 X 25 cells with the use of Excel VBA program. Japanese
The range of puzzle must be enclosed with solid line and the starting cell must be set within a region of "A1:H8" cells as demonstrated in Figure 1.
Algorithm of solving game, for instance 9×9 cells, is as follow. At first, all vacant cells are filled with a string "abcdefghi", in which "a" and "b" … corresponds to 1, 2 and so. Several alphabetical characters are deleted according to a rule of Sudoku game. Thus, cells having only one letter can be altered to numerical figure.
Cells are divided into 1 〜 27 groups, i.e. Grp(1) to Grp(9) are Column, Grp(10) to Grp(18) are Row, and Grp(19) to Grp(27) are Block groups, respectively. Grp(0) is regarded as total cells, i.e. Range("C3:K11") in Figure 1, left.
Group number of a specified cell can be determined using private Function, i.e. cG(c), rG(c), bG(c). For example, if c is E8 cell, cG(c), rG(c), and bG(c) returns 3, 15, and 22.
WorksheetFunction.CountIf is particularly convenient in counting number of cells existing in each group.
If WorksheetFunction.CountIf((Grp(10), "*c*")) equals to 2, number of cells containing "c" character in the range of "C3:K3" is only two. If this Function measures 1, the cell can be numerically fixed (i).
Figure 2.9×9 cells
| 5 | 6 | |||||||
| 3 | 4 | 7 | 8 | |||||
| 1 | 9 | |||||||
| 2 | ||||||||
| 8 | ||||||||
| 8 | 3 | 7 | 5 | |||||
| 7 | 4 | 8 | ||||||
| 2 | 9 | 1 | ||||||
| 1 | 4 | 5 | 3 |
(1) If a Column group (or a Row group) has only two cells containing some character and relevant two cells are both in the same Block group, other cells in the Block cannot contain this character(!). Furthermore, If a Block group has only two cells containing some character and the two cells are both in same Column group (or same Row group), other cells in the Column group (or Row group) cannot contain this character (!).
(2) If a group has only two cells containing both "c" and "e" characters for instance, and the two cells are both identical cells, the relevant two cells could be fixed as "ce"(*). The same manner may be applied for three characters in three cells(^).
In the case of upper-graded puzzle beyond scheme described above or originally impossible one, "Give UP" message will appear. If successfully dissolved, message such as "iiii!!!!!^iiiiii-3.97" is shown indicating history of successful methods and time needed for solving.
Figure 3.16×16 cells
| 2 | 9 | 8 | 3 | ||||||||||||
| 8 | 5 | 2 | 11 | ||||||||||||
| 16 | 1 | 7 | 4 | 3 | 5 | ||||||||||
| 11 | 6 | 4 | 13 | 12 | 7 | ||||||||||
| 2 | 1 | 7 | 16 | ||||||||||||
| 12 | 8 | 15 | 13 | 11 | 10 | 4 | 7 | ||||||||
| 7 | 9 | 10 | 5 | 13 | 12 | ||||||||||
| 14 | 4 | 3 | 1 | 15 | 5 | ||||||||||
| 11 | 15 | 1 | 3 | 14 | 9 | ||||||||||
| 16 | 13 | 7 | 11 | 5 | 2 | ||||||||||
| 1 | 3 | 4 | 10 | 12 | 8 | 15 | 16 | ||||||||
| 7 | 16 | 15 | 5 | ||||||||||||
| 2 | 3 | 15 | 7 | 11 | 5 | ||||||||||
| 7 | 12 | 16 | 8 | 2 | 1 | ||||||||||
| 9 | 10 | 16 | 13 | ||||||||||||
| 14 | 12 | 9 | 1 |
Dim c0 As Range, Mas, sM, success As Boolean, Grp() As Range
Sub sudoku()
Dim cel(9) As Range '---[ Sudoku Ver 5.1 ]---
Call SelSt(w): Set c0 = Range(w)
For i = 1 To 25: If c0.Cells(i + 1, 1).Borders(7).LineStyle <> 1 Then Exit For
Next: Mas = i: If Mas = 16 Or Mas = 25 Then Else Mas = 9
ReDim Grp(Mas * 3), nG(1 To Mas, 1 To Mas * 3)
Set Grp(0) = Range(c0, c0.Cells(Mas, Mas)): sM = Sqr(Mas)
If WorksheetFunction.CountIf(Grp(0), ">0") = 0 Then Grp(0).Select: MsgBox "Range missing":: End
For i = 1 To Mas: Set Grp(i) = Grp(0).Columns(i).Cells: Set Grp(Mas + i) = Grp(0).Rows(i).Cells:
Set Grp(Mas * 2 + i) = SetB(i)
Next: Call Init(c):
With Grp(0): .HorizontalAlignment = xlCenter: .ColumnWidth = 3.4: .RowHeight = 22.6: .Borders.Weight = 2
End With: For i = 2 * Mas + 1 To 3 * Mas: Grp(i).BorderAround Weight:=xlThick: Next
a = MsgBox(Mas & "×" & Mas & " Cells. Start?", vbYesNo): If a = vbNo Then End
s = Timer: w = "": For i = 1 To Mas: w = w & Chr(96 + i): Next ' String "abcdefghi"
Set myRange = Grp(0).SpecialCells(4) '(注)xlCellTypeBlanks =4
With myRange: ' .Font.Size = 11: .Font.Color = vbBlue: .Value = w
.Font.Size = 1: .Font.Color = vbWhite: .Value = w
End With
For Each c In Grp(0): If IsNumeric(c.Value) Then Call DelUn(c, w)
Next
myLoop:
Do While WorksheetFunction.CountIf(Grp(0), "?") > 0
For Each c In myRange '
If c.Value Like "[a-z]" Then w = c.Value: c.Value = Asc(c.Value) - 96: Call DelUn(c, w)
Next
Loop: If WorksheetFunction.CountIf(Grp(0), ">0") = Mas ^ 2 Then ok = True: GoTo Fin '===to Final
For ch = 1 To Mas: For Gr = 1 To Mas * 3
w = Chr(96 + ch): nG(ch, Gr) = WorksheetFunction.CountIf(Grp(Gr), "*" & w & "*")
Next: Next: Lenadv = Len(adv)
For ch = 1 To Mas: For Gr = 1 To Mas * 3
If nG(ch, Gr) = 1 Then '=====case of only one Cell in a Group ( i )
w = Chr(96 + ch): For Each c In Grp(Gr)
If InStr(c.Value, w) Then c.Value = ch: Call DelUn(c, w): adv = adv & "i"
Next
End If
Next: Next
If Len(adv) > Lenadv Then GoTo myLoop
For ch = 1 To Mas: For Gr = 1 To Mas * 3
If nG(ch, Gr) = 2 Then '==================case of two Cells in a Group
w = Chr(96 + ch): Call GetEx(w, Gr, Ex)
For i = 1 To Mas * 3
If i <> Gr And Union(Ex, Grp(i)).Cells.Count = Mas Then Call DelC(w, Grp(i), Ex)
Next
End If
If success = True Then success = False: adv = adv & "!": GoTo myLoop
Next: Next
For Gr = 1 To Mas * 3: For ch = 1 To Mas - 1: For ch2 = ch + 1 To Mas
If nG(ch, Gr) = 2 And nG(ch2, Gr) = 2 Then '======== a,b are both in same Cells? (2) ( * )
w = Chr(96 + ch) & Chr(96 + ch2): Call GetEx(w, Gr, Ex)
If Ex.Cells.Count = 2 Then
For Each c In Ex
If Len(c.Value) > 2 Then c.Value = w: success = True
Next
End If: End If
If success = True Then success = False: adv = adv & "*": GoTo myLoop
Next: Next: Next
For Gr = 1 To Mas * 3: For ch = 1 To Mas - 2: For ch2 = ch + 1 To Mas - 1
For ch3 = ch2 + 1 To Mas
n = nG(ch, Gr): n2 = nG(ch2, Gr): n3 = nG(ch3, Gr) '==are there Cells in a Group? ( ^ )
If (n = 2 Or n = 3) And (n2 = 2 Or n2 = 3) And (n3 = 2 Or n3 = 3) Then
st = Chr(96 + ch) & Chr(96 + ch2) & Chr(96 + ch3): Call GetEx(st, Gr, Ex)
If Ex.Cells.Count = 3 Then
w = "": For Each c In Ex: w = w & c.Value: Next
w = Replace(w, Chr(96 + ch), "")
w = Replace(w, Chr(96 + ch2), ""): w = Replace(w, Chr(96 + ch3), "")
If Len(w) > 0 Then
For i = 1 To Mas: w = Chr(96 + i)
If InStr(st, w) Then Else Ex.Replace what:=w, replacement:=""
Next: adv = adv & "^": GoTo myLoop
End If
End If: End If: Next: Next: Next: Next
Fin: '=================Final
With myRange.Cells.Font: .Color = vbBlue: .Size = 11: .Italic = True: End With
If ok = True Then MsgBox "Completed" & vbCr & vbCr & adv & Round(s - Timer, 2) - 1: End
MsgBox "Give UP": Call Init(c): End
End Sub
Function SetB(i) ' block
j = Int((i - 1) / sM): k = i Mod sM: If k = 0 Then k = sM
y = sM * j + 1: x = sM * (k - 1) + 1
Set SetB = Range(c0.Cells(y, x), c0.Cells(y + sM - 1, x + sM - 1))
End Function
Function cG(c) 'column
cG = c.Column - c0.Column + 1:
End Function
Function rG(c) 'row
rG = c.Row - c0.Row + Mas + 1:
End Function
Function bG(c) 'block
bG = Int((c.Column - c0.Column) / sM) + 1 + Mas * 2 + Int((c.Row - c0.Row) / sM) * sM
End Function
Sub SelSt(w) ')xlEdgeLeft=7, xlEdgeTop=8, xlSolid=1
For i = 1 To 8: For j = 1 To 8
If Cells(j, i).Borders(7).LineStyle = 1 And Cells(j, i).Borders(8).LineStyle = 1 _
Then w = Cells(j, i).Address: Exit Sub
Next: Next
Retry: w = InputBox("Input Start Cell e.g. f12" & vbCr & "9x9 only for no border line" & _
vbCr & "Cancel for Stop", "☆Start Cell is not recognized"): If w = "" Then End
If w Like "[a-zA-Z][1-9][0-9]" Or w Like "[a-zA-Z][1-9]" Then Exit Sub Else GoTo Retry
End Sub
Sub GetEx(w, Gr, Ex)
Dim cel(1 To 9) As Range, wd(1 To 3) As String
wd(1) = Left(w, 1): wd(2) = Mid(w, 2, 1): wd(3) = Mid(w, 3, 1): n = 0
For Each c In Grp(Gr): For i = 1 To 3
If wd(i) = "" Then Else If InStr(c.Value, wd(i)) Then n = n + 1: Set cel(n) = c
Next: Next: Set Ex = cel(1)
For i = 1 To 9: If cel(i) Is Nothing Then Else Set Ex = Union(Ex, cel(i))
Next
End Sub
Sub DelUn(c, w)
Union(Grp(cG(c)), Grp(rG(c)), Grp(bG(c))).Replace what:=Chr(96 + c.Value), replacement:=""
End Sub
Sub Init(c)
For Each c In Grp(0): With c.Font
If .Color = vbWhite Or .Color = vbBlue Or .Italic = True Then c.Value = ""
.Color = 0: .Bold = False: .Italic = False: If c.Value <> "" Then .Bold = True
End With: Next
End Sub
Sub DelC(w, u, Ex)
If WorksheetFunction.CountIf(u, "*" & w & "*") = 2 Then Exit Sub
w1 = Ex.Address
For Each c In u: If InStr(w1, c.Address) Then Else c.Value = Replace(c.Value, w, "")
Next
success = True
End Sub
Figure 4.
Figure 4. shows a process of solving the puzzle. If you pay attention to the three parts *, which do not accept values except 1, 3, and 5, it leads you relatively easy completion.