数独(九宫格)

Mark:此程序的关键记算来源于http://gundumw100.iteye.com/blog/760402,非本人原创。

Option Explicit
'/增加随机产生固定数
'|产生随机数的数独
'|来源:http://gundumw100.iteye.com/blog/760402
'|原理
'|       1.随机产生1-9之间数字
'|       2.检查所处行、列、3X3区域
'|       3.如果数字遍历1-9无解,退回第一列
'|       4.步数超过一定数,重新开始
'| 增加随机数初始化填充
'| 开始游戏后将n常驻内存,直至结束游戏

'产生初始数的最大量
Const Max_Begin_Num = 13
Const Min_Begin_Num = 5
Const w = 9
Const Begin_Color = 15
'/生成随机数字的源数组,10以内自然数
Public Num(1 To 9) As Integer
'/存储数字的数组,
'/0存储状态:1为初始化;0为手工录入
'/1存储数值
Public n(1 To w, 1 To w, 0 To 1) As Integer
Public t%

'/初始化数独数据
'/产生<13的随机1-9之间数据填入矩阵
Sub BeginGame()
'矩阵列的X/Y座标
Dim x As Integer, y As Integer
'产生随机数的量<Max_Begin_Num
Dim RndCount As Integer
Dim iX&, iY&  '变量
Dim i&
'随机数,X,Y
Dim RanN&, RanX&, RanY&
'初始化n
Erase n
Dim t
t = Timer
'随机数发生器
Randomize
'产生随机数量值
RndCount = Int((Max_Begin_Num - 1) * Rnd) + 1
'最小填充值>=5
If RndCount < Min_Begin_Num Then RndCount = Min_Begin_Num
For i = 1 To RndCount
   '产生随机数
   Do
      RanX = Int((w - 1) * Rnd) + 1
      RanY = Int((w - 1) * Rnd) + 1
      RanN = Int((w - 1) * Rnd) + 1
      n(RanX, RanY, 1) = RanN    '数值读入
      If IsCorrect(RanX, RanY) Then
         '标记为标始化
         'Stop
          n(RanX, RanY, 0) = 1
          Exit Do
      Else
          n(RanX, RanY, 0) = 0
      End If
   Loop
Next i
'Stop
'输出
For iX = 1 To 9
   For iY = 1 To 9
   Sheet2.Cells(iX, iY) = ""
   Sheet2.Cells(iX, iY).Interior.ColorIndex = xlNone
      '有初始值存在
      If n(iX, iY, 0) = 1 Then
         Sheet2.Cells(iX, iY) = n(iX, iY, 1)
         Sheet2.Cells(iX, iY).Interior.ColorIndex = Begin_Color   'gray
       End If
   Next iY
Next iX
   MsgBox ("Game Start " & Timer - t)
'Erase n
End Sub

'/Restart This Game
Sub RestartGame()
Dim iX%, iY%
'数据读入
Game_Data_In 1
For iX = 1 To w    'ROW
   For iY = 1 To w    'COLUMN
      '数据不是初始值
      If n(iX, iY, 0) = 0 Then
         n(iX, iY, 1) = 0
      End If
   Next iY
Next iX
Game_Data_Output
MsgBox ("Restart Game Done")
End Sub

'/check the result
Sub CheckGame()
Dim iX%, iY%
'变量,j=行;k=列
Dim j%, k%
Dim i%, m%
'EXCEL读入内存
Game_Data_In 0
For iX = 1 To w
   For iY = 1 To w
     If n(iX, iY, 1) = 0 Then
        '空单元格选中
        Sheet2.Cells(iX, iY).Select
        MsgBox ("请填满数据")
        Exit Sub
     Else
     '检查数据
     '检查行
        '最后一列,退出(不需检查)
        If iY = w Then Exit For
            For j = iY + 1 To w
               If n(iX, iY, 1) = n(iX, j, 1) Then
                  Union(Sheet2.Cells(iX, iY), Sheet2.Cells(iX, j)).Select
                  MsgBox ("未通过审核")
                  Exit Sub
               End If
             Next j
       '检查列
          '最后一行,退出(不需检查)
         If iX = w Then Exit For
            For k = iX + 1 To w
               If n(iX, iY, 1) = n(k, iY, 1) Then
                  Union(Sheet2.Cells(iX, iY), Sheet2.Cells(k, iY)).Select
                  MsgBox ("未通过审核")
                  Exit Sub
               End If
            Next k
        '检查3X3
            j = Int((iX - 1) / 3) * 3 + 1   '取整,3的倍数
            k = Int((iY - 1) / 3) * 3 + 1  '取整,3的倍数
             '/循环比较3X3
             For i = 1 To w
             '0值skip
                 If Not n(j + Int((i - 1) / 3), k + (i - 1) Mod 3, 1) = 0 Then
               '    If n(j + Int((i - 1) / 3), k + (i - 1) Mod 3) = 0 Then Exit Function
                     For m = i + 1 To w
                        '比较3X3区域
                        If n(j + Int((i - 1) / 3), k + (i - 1) Mod 3, 1) = n(j + Int((m - 1) / 3), k + (m - 1) Mod 3, 1) Then
                           Union(Sheet2.Cells(j + Int((i - 1) / 3), k + (i - 1) Mod 3), Sheet2.Cells(j + Int((m - 1) / 3), k + (m - 1) Mod 3)).Select
                           MsgBox ("未通过审核")
                           Exit Sub
                        End If
                     Next m
                  End If   'NOT=0
              Next i
      End If   'NOT=0
   Next iY
Next iX
MsgBox ("Check Done")
End Sub

Sub EndGame()
Dim i%, j%
Erase n
Erase Num
'清除单元格数据
For i = 1 To w
   For j = 1 To w
      Sheet2.Cells(i, j) = ""
      Sheet2.Cells(i, j).Interior.ColorIndex = xlNone
   Next j
Next i
MsgBox ("Game Clear")
End Sub

'矩阵区域读入
'公共参数n不能很好的常驻内存
'增加程序参数作为:
'1为只读入初始值
'0为读入所有值
Sub Game_Data_In(ByVal flag As Integer)
Dim iX%, iY%
 '矩阵数据读入
Erase n
For iX = 1 To w
   For iY = 1 To w
      '原始区域不为0
     If Sheet2.Cells(iX, iY) <> "" Then
         'FLAG=1
       If flag = 1 Then
          '初始化数据有数值,有颜色来辨别
          If Sheet2.Cells(iX, iY).Interior.ColorIndex = Begin_Color Then
             '数据读入
              n(iX, iY, 1) = Sheet2.Cells(iX, iY)
    '           '标记为初始值
              n(iX, iY, 0) = 1
          End If  'colorindex
       ElseIf flag = 0 Then
           '数据读入
           n(iX, iY, 1) = Sheet2.Cells(iX, iY)
          If Sheet2.Cells(iX, iY).Interior.ColorIndex = Begin_Color Then
 '           '标记为初始值
              n(iX, iY, 0) = 1
          End If  'colorindex
       End If  'flag
     End If '<>""
   Next iY
Next iX

End Sub

'矩阵输出
Sub Game_Data_Output()
Dim iX%, iY%
For iX = 1 To w
   For iY = 1 To w
      '如果为0,表示没有数据录入
      If n(iX, iY, 1) = 0 Then
         Sheet2.Cells(iX, iY) = ""
      Else
         '数据输出
         Sheet2.Cells(iX, iY) = n(iX, iY, 1)
      End If
   Next iY
Next iX
End Sub

'/产生九宫格(数独)数字
Sub Game_Done()
Dim iX%, iY%
'/数字的位置座标,x->横座标,y->纵座标
Dim x%, y%
'/填充数字的次数
Dim tm
Dim ST
'---------------------------------------------
'生成数字
tm = Timer
ST = 0
Game_Data_In 1

For x = 1 To w
   '尝试填充数字次数,每行开始初始化
   t = 1
   '填充数字
Redo:
   For y = 1 To w
      '不是初始值
      If n(x, y, 0) = 0 Then
         '产生数字
         n(x, y, 1) = GenerateNum(t)
         '//////////////////////////////////
         Game_Data_Output
         '////////////////////////////////////
         '如果步数超过某一数(梅森素数),无解
         ST = ST + 1
         If ST >= 1000 Then GoTo noAnswer
         '/如果返回值为0,则代表超过边界,退回处理
         '/退回处理的原则是:如果不是第一列,则先倒退到第一列;否则倒退到前一行的最后一列
         If n(x, y, 1) = 0 Then
            '不是第一列,退回第一列
            If y > 1 Then
               GoTo Redo
   '            y = y - 2
            Else  '是第一列,则退到上一行的最后一列
               x = x - 1
               y = 9
            End If
         End If   '返回0值
       '/填充成功
         If IsCorrect(x, y) Then
            '初始化time,为下次填充准备
            t = 1
         Else  '/继续填充
            t = t + 1
            y = y - 1
         End If
         'Stop
     End If
   '   WaitMoment (0.5)
   Next y
Next x
MsgBox (Timer - tm)
Exit Sub
noAnswer:
   MsgBox ("无解")
Erase n
End Sub

'
'产生1-9之间的随机数字 规则:生成的随机数字放置在数组8-time下标的位置,随着time的增加,已经尝试过的数字将不会在取到
'说明:即第一次次是从所有数字中随机,第二次时从前八个数字中随机,依次类推, 这样既保证随机,也不会再重复取已经不符合要求的数字,提高程序的效率
'这个规则是本算法的核心
'@param time
'填充的次数,1代表第一次填充

Function GenerateNum(ByVal t As Integer) As Integer
Dim i%
Dim RanNum As Integer
Dim temp As Integer
'第一次填充时,初始化随机数字源数组
If t = 1 Then
   For i = 1 To w
       Num(i) = i
   Next i
End If
'填充次数>=9次,表明位置已经超过边界,则返回0;由主程序处理退回
If t = w + 1 Then
   '返回0值
   GenerateNum = 0
   '退出
   Exit Function
End If
'/不是第一次填充
'/通过成随机数字,该数字是数组的下票,取数组num中该下标对应的烽字为随机数字
   Randomize
   '产生下标随机数
   RanNum = Int((w - t) * Rnd) + 1 '/j2me
   '把数字放置在数组倒数第time个位置,=换位
   temp = Num(w - t + 1)
   Num(w - t + 1) = Num(RanNum)
   Num(RanNum) = temp
   '返回数字
   GenerateNum = Num(w - t + 1)
End Function


'/是否满足行、列和3x3区域不重复的要求
' @param row
'@param col
'@return true代表符合要求
Function IsCorrect(ByVal r As Integer, ByVal col As Integer) As Boolean
  If CheckRow(r) And CheckLine(col) And CheckNine(r, col) Then
      IsCorrect = True
  End If
End Function

'/检查行是否符合要求
'@param row
'@return true代表符合要求
Function CheckRow(ByVal ro As Integer) As Boolean
Dim j As Integer  '列
Dim k As Integer
For j = 1 To w
   '0值skip
   If Not n(ro, j, 1) = 0 Then
'    If n(ro, j) = 0 Then Exit Function
      For k = j + 1 To w
         If n(ro, j, 1) = n(ro, k, 1) Then
            CheckRow = False
            Exit Function
         Else
            CheckRow = True
         End If
      Next k
   End If
Next j
End Function

'/检查行是否符合要求
'@param row
'@return true代表符合要求
Function CheckLine(ByVal col As Integer) As Boolean
Dim j As Integer  '列
Dim k As Integer
For j = 1 To w
   '0值skip
   If Not n(j, col, 1) = 0 Then
'    If n(j, col) = 0 Then Exit Function
      For k = j + 1 To w
         If n(j, col, 1) = n(k, col, 1) Then
            CheckLine = False
            Exit Function
         Else
            CheckLine = True
         End If
      Next k
   End If
Next j
End Function

'/检查3X3区域是否符合要求
' @param row
Function CheckNine(ByVal ro As Integer, ByVal col As Integer) As Boolean
'/获得左上角坐标
Dim j As Integer
Dim k As Integer
Dim i As Integer, m As Integer
'Stop
j = Int((ro - 1) / 3) * 3 + 1   '取整,3的倍数
k = Int((col - 1) / 3) * 3 + 1  '取整,3的倍数
'/循环比较
For i = 1 To w
   '0值skip
   If Not n(j + Int((i - 1) / 3), k + (i - 1) Mod 3, 1) = 0 Then
'    If n(j + Int((i - 1) / 3), k + (i - 1) Mod 3) = 0 Then Exit Function
      For m = i + 1 To w
         If n(j + Int((i - 1) / 3), k + (i - 1) Mod 3, 1) = n(j + Int((m - 1) / 3), k + (m - 1) Mod 3, 1) Then
            CheckNine = False
            Exit Function
         Else
            CheckNine = True
         End If
      Next
   End If
Next i
End Function

'Wait for showing movement
Sub WaitMoment(rMoment!)
    Dim rT!
    rT = Timer
    Do While Timer - rT < rMoment
        DoEvents
    Loop
End Sub


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值