将单元格地址添加到 VBA 中的动态数组

Add cell address to dynamic array in VBA

我有一个脚本,其中循环遍历 9x9 数组,如果单元格包含 0,它将更改数字,使数字在行、列和其中的 3x3 正方形中是唯一的。每次找到并更改一个这样的单元格时,我想将该单元格位置添加到一个数组中,这样如果替换 0 的数字不是最优的,我可以轻松地返回到那个被更改的单元格并且尝试一个新号码。我该怎么做?

下面是我到目前为止编写的代码,我用三个撇号 (''') 表示我的“伪代码” 这进一步解释了我想要它做什么。

Check Function根据我提到的条件(Sudoku Rules)判断1到9的数字是否可以放入当前单元格。

它涉及递归,所以如果我需要以更清楚的方式解释,请告诉我。

Sub Solve()

Dim x As Integer, y As Integer, row As Integer, col As Integer, rw As Integer, cl As Integer, a As Worksheet, puzzle As Range, n As Integer, num As Integer
Dim startcol As Integer, startrow As Integer, check1 As Boolean, check2 As Boolean, check3 As Boolean, r As Integer, c As Integer, x1 As Double, y1 As Double, z As Boolean
Dim fillednums(1 To 9, 1 To 9) As String

Set a = ThisWorkbook.Worksheets("Puzzle")
Set puzzle = a.Range(Cells(4, 4), Cells(12, 12))


startcol = 4
startrow = 4

For row = startrow To startrow + 8
    For col = startcol To startcol + 8
        If a.Cells(row, col).Value = 0 Then
            For num = 1 To 9
                If Check(col, row, num) = True Then
                a.Cells(row, col).Value = num
                    '''Add cell address to array
                Call Solve
                ElseIf num = 9 And a.Cells(row, col).Value = 0 Then
                    '''Go back one index of the array (fillednums) and use check() function for numbers greater than the one in the cell and up to 9
                    '''If that still doesnt work, go back to cell before this one that was changed and check again (recursively)
                    '''Call Solve() again to try new number
                'a.Cells(row, col).Value = 0
                End If
            Next num
        End If
    Next col
Next row
            
            
End Sub 

对于递归,您可以从拼图中的第一个空单元格开始。对于每个可能的值,将下一个空闲单元格传递给 child 以检查解决方案。该过程一直持续到找到解决方案(假设拼图有效)。

主要的 Solve 函数必须 return True 或 False,以便 parent 知道是否已找到解决方案。

Function GetNextCell(cc)  ' get next free cell in puzzle
   GetNextCell = Cells(cc.Row, cc.Column+1) ' move next column
   If (GetNextCell.Column = 13) Then  ' go to next row
      GetNextCell = Cells(cc.Row+1, 4)
   End If
   If GetNextCell.Row = 13 Then ' off the grid
      GetNextCell = Nothing  ' no more cells
   End If
   If GetNextCell <> Nothing And GetNextCell.Value <> "" Then
      GetNextCell GetNextCell(GetNextCell) ' skip filled cells
   End If    

Function Solve(cc) as Boolean    
    ' we only care about our single cell
    For num = 1 to 9 ' all possible values for this cell
        cc.Value = num
        If Check(cc.column, cc.row, num) Then  ' so far so good
            NextCell = GetNextCell(cc)  ' get next cell for child to process
            if NextCell = Nothing Then  ' no more cells and current values work
                    Solve = True  ' puzzle solved
                    Exit Function
            Else  ' call child with next cell
                If Solve(NextCell) Then  ' did child solve puzzle ?
                    Solve = True  ' puzzle solved
                    Exit Function
                End If
                ' Child could not find solution based on current values
            End If
        End If
    Next
    
  cc.Value = ""    ' No solution found at this point, must revert back to parent to try next value
  Solve = False  ' no solution found    
End Function

Solve(GetNextCell(Cells(4,3)))  ' first empty cell in block, must return true