EXCEL VBA 宏 数独游戏解法 回溯

2025-10-01 16:31:07

1、将数独的已知数填入活动表的A1:I9单元格,打开宏编辑器,将如下语句考入编辑区。运行宏即可

2、Sub 数独()

'本程序有很多不足,欢迎改进!

      Dim i As Byte, t As Byte, r As Byte, x As Byte, y As Byte, zz As Integer

      Dim ta As Byte,tc As Double

      Dim hh(1 To 9, 1 To 9, 1 To 9) As Byte    '用于保存每个单元格中可能的数,经过排序最后一维保存的数从大到小,一维、二维是单元格的位置

      Dim g(1 To 9, 1 To 9) As Byte, gg(1 To 9) As Byte   '九宫和九宫的和

      Dim ypsi(1 To 9, 1 To 9) As Byte, yskn(0 To 99999, 1 To 9, 1 To 9) As Byte  '原始数组和分叉时保存数据的数组 0是起始数,原始可能的数。

      Dim jisu(1 To 9, 1 To 9) As Byte   '计数数组,由于统计每个单元格可能数字的个数,及数组hh(y,x,i)中i保留了几位数

      Dim zsjw(1 To 9) As Byte  '中间数组

      Dim dzan(0 To 99999, 1 To 6) As Integer '记录路径,候选数,历遍标志

      MsgBox "根据游戏的难易程度有可能等待几秒到几十分钟,请耐心等待!         点击     “确认”    开始"

    Application.ScreenUpdating = False     '关闭屏幕刷新

      

      For y = 1 To 9

        For x = 1 To 9

           ypsi(y, x) = Cells(y, x)    '把原始数据保留到数组

        Next

      Next

      yskn(0, 1, 1) = 0

      zz = 0

      ta = 0

E1:

      For y = 1 To 9

         For x = 1 To 9

            If Cells(y, x) = 0 Then Cells(y, x) = ""   '如果单元格中有0 数组将溢出,此处做技术处理

         Next

      Next

      g(1, 1) = Cells(1, 1)                   '把单元格的数转换到“宫”里以便编程

      g(1, 2) = Cells(1, 2)

      g(1, 3) = Cells(1, 3)                   '此处可以用取整函数,EVEN(y/3)来确定单元格属于哪一宫,但会增加运算次数。

      g(1, 4) = Cells(2, 1)

      g(1, 5) = Cells(2, 2)

      g(1, 6) = Cells(2, 3)

      g(1, 7) = Cells(3, 1)

      g(1, 8) = Cells(3, 2)

      g(1, 9) = Cells(3, 3)

      

      g(2, 1) = Cells(1, 4)

      g(2, 2) = Cells(1, 5)

      g(2, 3) = Cells(1, 6)

      g(2, 4) = Cells(2, 4)

      g(2, 5) = Cells(2, 5)

      g(2, 6) = Cells(2, 6)

      g(2, 7) = Cells(3, 4)

      g(2, 8) = Cells(3, 5)

      g(2, 9) = Cells(3, 6)

   

      g(3, 1) = Cells(1, 7)

      g(3, 2) = Cells(1, 8)

      g(3, 3) = Cells(1, 9)

      g(3, 4) = Cells(2, 7)

      g(3, 5) = Cells(2, 8)

      g(3, 6) = Cells(2, 9)

      g(3, 7) = Cells(3, 7)

      g(3, 8) = Cells(3, 8)

      g(3, 9) = Cells(3, 9)

      

      g(4, 1) = Cells(4, 1)

      g(4, 2) = Cells(4, 2)

      g(4, 3) = Cells(4, 3)

      g(4, 4) = Cells(5, 1)

      g(4, 5) = Cells(5, 2)

      g(4, 6) = Cells(5, 3)

      g(4, 7) = Cells(6, 1)

      g(4, 8) = Cells(6, 2)

      g(4, 9) = Cells(6, 3)

      

      g(5, 1) = Cells(4, 4)

      g(5, 2) = Cells(4, 5)

      g(5, 3) = Cells(4, 6)

      g(5, 4) = Cells(5, 4)

      g(5, 5) = Cells(5, 5)

      g(5, 6) = Cells(5, 6)

      g(5, 7) = Cells(6, 4)

      g(5, 8) = Cells(6, 5)

      g(5, 9) = Cells(6, 6)

      g(6, 1) = Cells(4, 7)

      g(6, 2) = Cells(4, 8)

      g(6, 3) = Cells(4, 9)

      g(6, 4) = Cells(5, 7)

      g(6, 5) = Cells(5, 8)

      g(6, 6) = Cells(5, 9)

      g(6, 7) = Cells(6, 7)

      g(6, 8) = Cells(6, 8)

      g(6, 9) = Cells(6, 9)

      

      g(7, 1) = Cells(7, 1)

      g(7, 2) = Cells(7, 2)

      g(7, 3) = Cells(7, 3)

      g(7, 4) = Cells(8, 1)

      g(7, 5) = Cells(8, 2)

      g(7, 6) = Cells(8, 3)

      g(7, 7) = Cells(9, 1)

      g(7, 8) = Cells(9, 2)

      g(7, 9) = Cells(9, 3)

      

      g(8, 1) = Cells(7, 4)

      g(8, 2) = Cells(7, 5)

      g(8, 3) = Cells(7, 6)

      g(8, 4) = Cells(8, 4)

      g(8, 5) = Cells(8, 5)

      g(8, 6) = Cells(8, 6)

      g(8, 7) = Cells(9, 4)

      g(8, 8) = Cells(9, 5)

      g(8, 9) = Cells(9, 6)

      g(9, 1) = Cells(7, 7)

      g(9, 2) = Cells(7, 8)

      g(9, 3) = Cells(7, 9)

      g(9, 4) = Cells(8, 7)

      g(9, 5) = Cells(8, 8)

      g(9, 6) = Cells(8, 9)

      g(9, 7) = Cells(9, 7)

      g(9, 8) = Cells(9, 8)

      g(9, 9) = Cells(9, 9)

  For y = 1 To 9

      'gg(y) = 0

      For i = 1 To 9

        jisu(y, i) = 0   '对计数数组赋值

        'gg(y) = gg(y) + g(y, i) '对每一宫的数进行合计

        For t = 1 To 9

         hh(y, i, t) = t

        Next

      Next

   Next

        

'''分段3

For y = 1 To 9

 For x = 1 To 9

  If Cells(y, x) > 0 And Cells(y, x) < 10 Then  '如果宫格里的数已经确定则将该数读入列

    For i = 1 To 9

    hh(y, x, i) = 0

    Next

    Else

     For i = 1 To 9

        If Cells(y, i) <> "" Or Cells(y, i) <> 0 Then

          r = Cells(y, i)   '去掉行里有的数

          hh(y, x, r) = 0

        End If

     Next

    For t = 1 To 9

        If Cells(t, x) <> "" Or Cells(t, x) <> 0 Then

         r = Cells(t, x) '去掉列里有的数

          hh(y, x, r) = 0

        End If

    Next

           If y = 1 Or y = 2 Or y = 3 Then     ''A

                  If x = 1 Or x = 2 Or x = 3 Then

                       For t = 1 To 9      '去掉宫1里有的数

                           If g(1, t) <> 0 Then

                              r = g(1, t)

                              hh(y, x, r) = 0

                           End If

                       Next

                  Else

                      If x = 4 Or x = 5 Or x = 6 Then

                             For t = 1 To 9      '去掉宫2里有的数

                                  If g(2, t) <> 0 Then

                                     r = g(2, t)

                                     hh(y, x, r) = 0

                                  End If

                             Next

                      Else

                             For t = 1 To 9      '去掉宫3里有的数

                                  If g(3, t) <> 0 Then

                                     r = g(3, t)

                                     hh(y, x, r) = 0

                                  End If

                             Next

                      End If

                 End If

        '''''''''''''

            Else ''1

               If y = 4 Or y = 5 Or y = 6 Then

                  If x = 1 Or x = 2 Or x = 3 Then ''''3

                       For t = 1 To 9      '去掉宫4里有的数

                           If g(4, t) <> 0 Then

                              r = g(4, t)

                              hh(y, x, r) = 0

                           End If

                       Next

                  Else

                      If x = 4 Or x = 5 Or x = 6 Then

                             For t = 1 To 9      '去掉宫5里有的数

                                  If g(5, t) <> 0 Then

                                     r = g(5, t)

                                     hh(y, x, r) = 0

                                  End If

                             Next

                      Else

                             For t = 1 To 9      '去掉宫6里有的数

                                  If g(6, t) <> 0 Then

                                     r = g(6, t)

                                     hh(y, x, r) = 0

                                  End If

                             Next

                      End If

                 End If ''''3

                 Else

                   If y = 7 Or y = 8 Or y = 9 Then

                       If x = 1 Or x = 2 Or x = 3 Then ''''3

                       For t = 1 To 9      '去掉宫7里有的数

                           If g(7, t) <> 0 Then

                              r = g(7, t)

                              hh(y, x, r) = 0

                           End If

                       Next

                  Else

                      If x = 4 Or x = 5 Or x = 6 Then

                             For t = 1 To 9      '去掉宫8里有的数

                                  If g(8, t) <> 0 Then

                                     r = g(8, t)

                                     hh(y, x, r) = 0

                                  End If

                             Next

                      Else

                             For t = 1 To 9      '去掉宫9里有的数

                                  If g(9, t) <> 0 Then

                                     r = g(9, t)

                                     hh(y, x, r) = 0

                                  End If

                             Next

                      End If

                 End If

                 End If ''''3

             End If '''1

          End If  ''A

End If

      For i = 1 To 9

            If hh(y, x, i) <> 0 Then     '对单元格(数组)可能的数字进行计数

              jisu(y, x) = jisu(y, x) + 1

            End If

     Next

Next

Next

'''''''对可能的数进行从大到小的排序

  For y = 1 To 9

    For x = 1 To 9

          For i = 1 To 9

             zsjw(i) = hh(y, x, i)

          Next

           For i = 1 To 9

             hh(y, x, i) = Application.WorksheetFunction.Large(zsjw, i)  '降序排序函数 和升序 small一样

           Next

    Next

  Next

'''''''排序结束

''''''对走不通的单元格进行判断

For y = 1 To 9

      For x = 1 To 9

          If Cells(y, x) = "" And jisu(y, x) = 0 Then                         '死路的条件

             For tc = 1 To zz      '''''''用负步长此处溢出,采取技术处理,有可能是VBA的bag

                 If dzan(zz - tc, 1) = 2 Or dzan(zz - tc, 1) = 3 Then                  '判断有2个候选数和有3个候选数

                     If dzan(zz - tc, 1) = 2 Then

                      dzan(zz - tc, 1) = 1

                       For i = 1 To 9

                         For t = 1 To 9

                            Cells(i, t) = yskn(zz - tc, i, t)

                         Next

                       Next

                          Cells(dzan(zz - tc, 2), dzan(zz - tc, 3)) = dzan(zz - tc, 5)

                          GoTo E1

                      End If

                      

                      If dzan(zz - tc, 1) = 3 Then                            ''有3个候选数选第3个再试

                      dzan(zz - tc, 1) = 2

                       For i = 1 To 9

                         For t = 1 To 9

                            Cells(i, t) = yskn(zz - tc, i, t)

                         Next

                       Next

                          Cells(dzan(zz - tc, 2), dzan(zz - tc, 3)) = dzan(zz - tc, 6)

                          GoTo E1

                      End If

                 End If

             Next tc

          End If

      Next

Next

''''''判断结束

'''''''''''注释1,jisu数组中只有一个数(0除外)时,将相应的数写入相应的单元格并从头再来

 For y = 1 To 9

        For x = 1 To 9

          If jisu(y, x) = 1 Then

             Cells(y, x) = hh(y, x, 1)

             GoTo E1 '从头再来

          End If

        Next

     Next

''''''''''''''遇见候选数为2

 For y = 1 To 9

   For x = 1 To 9

          If jisu(y, x) = 2 Then                    '2个候选数,选第一个数试

               Cells(y, x) = hh(y, x, 1)            '将第一个候选数写入单元格

                zz = zz + 1                         '路径计数

                dzan(zz, 1) = 2                     '候选数标志,也是节点标志

                dzan(zz, 2) = y                     ' 行位置

                dzan(zz, 3) = x                     ' 列位置

                dzan(zz, 4) = hh(y, x, 1)           '候选数1

                dzan(zz, 5) = hh(y, x, 2)           '候选数2

                   For i = 1 To 9

                   For r = 1 To 9

                       yskn(zz, i, r) = Cells(i, r)       '将节点处的数据保存到数组

                   Next

                Next

            GoTo E1                                '从头再来

            End If

    Next

  Next

'End If                 '遇见候选数为2的结束

''''''''''''''''''''''遇见候选数为3

For y = 1 To 9

   For x = 1 To 9

          If jisu(y, x) = 3 Then                      '3个候选数,选第一个数试

               Cells(y, x) = hh(y, x, 1)

                zz = zz + 1

              dzan(zz, 1) = 3

              dzan(zz, 2) = y

              dzan(zz, 3) = x

              dzan(zz, 4) = hh(y, x, 1)

              dzan(zz, 5) = hh(y, x, 2)

              dzan(zz, 6) = hh(y, x, 3)  '候选数3

                For i = 1 To 9

                   For r = 1 To 9

                       yskn(zz, i, r) = Cells(i, r)

                   Next

                Next

                GoTo E1                                '从头再来

            End If

    Next

  Next

 ''''''''''''''''''''''''''''''遇见候选数为3的结束

For y = 1 To 9

      For x = 1 To 9

          If Cells(y, x) = "" And jisu(y, x) = 0 Then    '死路的条件

             If dzan(zz, 1) = 2 Then

                dzan(zz, 1) = 1    '表示两个数其中一个走不通,再试另外一个

                Cells(dzan(zz, 2), dzan(zz, 3)) = dzan(zz, 5)

                GoTo E1

             End If

          End If

      Next

Next

For y = 1 To 9

      For x = 1 To 9

          If Cells(y, x) = "" And jisu(y, x) = 0 Then GoTo E3

          If jisu(y, x) = 4 Then GoTo E4

      Next

Next

 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

 Application.ScreenUpdating = True      '打开屏幕刷新

 GoTo E5

E3: MsgBox "待解,有可能是本数独无解;也有可能本程序不能应付。"

    GoTo E6

E4: MsgBox "待解,已知数太少,本程序不能应付。"

    GoTo E6

E5:

     For y = 1 To 9

     Cells(y, 10) = Cells(y, 1) + Cells(y, 2) + Cells(y, 3) + Cells(y, 4) + Cells(y, 5) + Cells(y, 6) + Cells(y, 7) + Cells(y, 8) + Cells(y, 9) '计算行之和,用于检查

     Cells(10, y) = Cells(1, y) + Cells(2, y) + Cells(3, y) + Cells(4, y) + Cells(5, y) + Cells(6, y) + Cells(7, y) + Cells(8, y) + Cells(9, y)  '计算列之和,用于检查

     Next

     MsgBox "成功完成"

E6:

 End Sub

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢