生成4x4x4数独板的更好/更好的方法?

时间:2008-12-29 01:32:48

标签: .net algorithm optimization

为了我有时间的乐趣,我喜欢编写游戏以查看它有多难,或者只是因为我想从内部看到它是如何工作的还是仅仅是为了个人挑战。我只是喜欢编码。现在,我做了these ones

所以我做了一个数独板。首先它是正常的3x3x3板,但后来有人让我做一个4x4x4板。我很成功但我的算法很慢。

问题是,如何为4x4x4(或更多)Sudoku主板执行快速算法

我当前的算法是这样的:我将用随机数填充网格1,确保我没有放回相同的数字,然后切换到网格2.当我在0.0或任何其他位置时在网格中我从网格1中删除任何可能的数字。我继续这样对网格中的每一行/列。 (现在你可以看到英语不是我的第一语言,所以如果难以理解我很抱歉。)


更新
几个月后的一点点跟进。

我当前的解决方案可以找到here

所以,当我开始这个问题时,它每30-50秒做1个网格,现在每秒超过300个

5 个答案:

答案 0 :(得分:9)

考虑以下网格:

 1  2  3  4 |  5  6  7  8 |  9 10 11 12 | 13 14 15 16
 5  6  7  8 |  9 10 11 12 | 13 14 15 16 |  1  2  3  4
 9 10 11 12 | 13 14 15 16 |  1  2  3  4 |  5  6  7  8
13 14 15 16 |  1  2  3  4 |  5  6  7  8 |  9 10 11 12
------------+-------------+-------------+------------
 2  3  4  1 |  6  7  8  5 | 10 11 12  9 | 14 15 16 13
 6  7  8  5 | 10 11 12  9 | 14 15 16 13 |  2  3  4  1
10 11 12  9 | 14 15 16 13 |  2  3  4  1 |  6  7  8  5
14 15 16 13 |  2  3  4  1 |  6  7  8  5 | 10 11 12  9
------------+-------------+-------------+------------
 3  4  1  2 |  7  8  5  6 | 11 12  9 10 | 15 16 13 14
 7  8  5  6 | 11 12  9 10 | 15 16 13 14 |  3  4  1  2
11 12  9 10 | 15 16 13 14 |  3  4  1  2 |  7  8  5  6
15 16 13 14 |  3  4  1  2 |  7  8  5  6 | 11 12  9 10
------------+-------------+-------------+------------
 4  1  2  3 |  8  5  6  7 | 12  9 10 11 | 16 13 14 15
 8  5  6  7 | 12  9 10 11 | 16 13 14 15 |  4  1  2  3
12  9 10 11 | 16 13 14 15 |  4  1  2  3 |  8  5  6  7
16 13 14 15 |  4  1  2  3 |  8  5  6  7 | 12  9 10 11

假设我没有做过任何拼写错误,那么显而易见(根据其构造模式),这符合Sudoku布局的要求(每个值1..16在每行,列中恰好出现一次,和4x4 subgrid)。

此外,显而易见的是,以下每项更改都会满足要求(假设采用1原点索引):

  1. 列交换:交换位于同一子网格中的任意两列的全部内容(例如,交换cols 1和3,交换cols 10和11,但 not < / strong>交换cols 6和13)。

  2. 行交换:交换位于同一子网格中的任意两列的全部内容(类似索引到#1)。

  3. 子网格列交换:交换两列子网格的相应列(例如交换子网格列2和4,这意味着交换所有列5和13,列6和14,列7和15,以及cols 8和16)。

  4. 子网格行交换:交换两行子网格的相应行(类似索引到#3)。

  5. 因此,基于上述事实,策略是从上面显示的网格开始,然后进行一些适当的迭代次数(您可以通过实验确定),随机选择四种变换中的一种,并将其应用于随机选择的指数,满足变换规定的要求。

      

    例如,要应用变换#1,随机选择范围(1..4)中的子网格列号sgcn,然后随机选择两个不同的列号cn1和{{1}在范围(1..4)。交换列cn2(sgcn - 1) * 4 + cn1中的所有值。

    从(任何)合法网格开始,并执行合法性保留转换,结果保证合法。然而,随着应用的变换数量的增加,人类观察者越来越难以区分模式和随机性。

    用空格替换“乱码”网格中的值,以获得所需的难度。

答案 1 :(得分:2)

您目前的算法是什么?

我想维基百科Algorithmics of sudoku页面上讨论的算法可以扩展到4x4x4。

答案 2 :(得分:1)

可以使用Python编写Sudoku Generator。关于作者如何生成数独板的解释(算法)在该页面上,并提供源代码。

答案 3 :(得分:0)

这是joel.neely建议的代码

传递3表示3x3x3,4表示4x4x4等

Public Class Class1

Private aSquare(,,) As Integer
Private iSquare As Integer

Sub New(ByVal squareSize As Integer)

    iSquare = squareSize
    ReDim aSquare(iSquare - 1, iSquare - 1, CInt(iSquare ^ 2 - 1))

    createSquare()
    rndSquare()

End Sub



Private Sub createSquare()
    Dim i As Integer, j As Integer, k As Integer

    For i = 0 To aSquare.GetUpperBound(0)
        For j = 0 To aSquare.GetUpperBound(1)
            For k = 0 To aSquare.GetUpperBound(2)
                If i = 0 And j = 0 Then
                    aSquare(i, j, k) = k + 1
                ElseIf j = 0 And i > 0 Then
                    If (k + i) Mod (iSquare) = 0 Then
                        aSquare(i, j, k) = aSquare(i - 1, j, k) - (iSquare - 1)

                    Else
                        aSquare(i, j, k) = aSquare(i - 1, j, k) + 1
                    End If
                Else
                    aSquare(i, j, k) = aSquare(i, j - 1, k) + iSquare
                End If

                If aSquare(i, j, k) > iSquare ^ 2 Then
                    aSquare(i, j, k) = aSquare(i, j, k) - CInt(iSquare ^ 2)
                End If
            Next
        Next
    Next
End Sub

Private Sub rndSquare()
    Dim i As Integer

    Randomize()

    For i = 0 To CInt(iSquare ^ 2)

        Select Case CInt(Rnd() * 3)
            Case 0
                rndBigCol()
            Case 1
                rndBigRow()
            Case 2
                rndLittleCol()
            Case 3
                rndlittleRow()
        End Select

    Next



End Sub

Private Sub rndBigCol()
    Dim square As Integer
    Dim rnd1, rnd2 As Integer
    Dim i As Integer, j As Integer, k As Integer

    Randomize()

    For k = 0 To iSquare
        Do
            rnd1 = CInt(Rnd() * aSquare.GetUpperBound(1))
            rnd2 = CInt(Rnd() * aSquare.GetUpperBound(1))
        Loop Until rnd1 <> rnd2

        For i = 0 To aSquare.GetUpperBound(0)
            For j = 0 To aSquare.GetUpperBound(2)
                square = aSquare(i, rnd1, j)
                aSquare(i, rnd1, j) = aSquare(i, rnd2, j)
                aSquare(i, rnd2, j) = square
            Next
        Next
    Next
End Sub

Private Sub rndBigRow()
    Dim square As Integer
    Dim rnd1, rnd2 As Integer
    Dim i As Integer, j As Integer, k As Integer

    Randomize()

    For k = 0 To iSquare
        Do
            rnd1 = CInt(Rnd() * aSquare.GetUpperBound(0))
            rnd2 = CInt(Rnd() * aSquare.GetUpperBound(0))
        Loop Until rnd1 <> rnd2

        For i = 0 To aSquare.GetUpperBound(1)
            For j = 0 To aSquare.GetUpperBound(2)
                square = aSquare(rnd1, i, j)
                aSquare(rnd1, i, j) = aSquare(rnd2, i, j)
                aSquare(rnd2, i, j) = square
            Next
        Next
    Next
End Sub

Private Sub rndLittleCol()
    Dim square As Integer
    Dim rnd1, rnd2, rnd3 As Integer
    Dim i As Integer, k As Integer, l As Integer

    Randomize()

    For k = 0 To iSquare * 2
        Do
            rnd1 = CInt(Rnd() * aSquare.GetUpperBound(1))
            rnd2 = CInt(Rnd() * (iSquare - 1))
            rnd3 = CInt(Rnd() * (iSquare - 1))
        Loop Until rnd2 <> rnd3

        For i = 0 To aSquare.GetUpperBound(0)
            For l = 0 To (iSquare - 1)
                square = aSquare(i, rnd1, rnd2 + (l * iSquare))
                aSquare(i, rnd1, rnd2 + (l * iSquare)) = aSquare(i, rnd1, rnd3 + (l * iSquare))
                aSquare(i, rnd1, rnd3 + (l * iSquare)) = square
            Next
        Next
    Next
End Sub

Private Sub rndlittleRow()
    Dim square As Integer
    Dim rnd1, rnd2, rnd3 As Integer
    Dim j As Integer, k As Integer, l As Integer

    Randomize()

    For k = 0 To iSquare * 2
        Do
            rnd1 = CInt(Rnd() * aSquare.GetUpperBound(0))
            rnd2 = CInt(Rnd() * (iSquare - 1))
            rnd3 = CInt(Rnd() * (iSquare - 1))
        Loop Until rnd2 <> rnd3

        rnd2 *= iSquare
        rnd3 *= iSquare

        For j = 0 To aSquare.GetUpperBound(1)
            For l = 0 To (iSquare - 1)
                square = aSquare(rnd1, j, rnd2 + l)
                aSquare(rnd1, j, rnd2 + l) = aSquare(rnd1, j, rnd3 + l)
                aSquare(rnd1, j, rnd3 + l) = square
            Next
        Next
    Next
End Sub
End Class

答案 4 :(得分:0)

好的,我发现为什么3x3x3的速度如此之快,但4x4x4的速度却很慢

这是我的回溯逻辑,非常糟糕,现在需要最多20秒(至少在我的电脑上),大部分时间不到5秒