如何在Python中创建数独谜题

时间:2017-08-02 21:17:16

标签: python python-2.7

目标是在Python中创建一个9x9 Sudoku矩阵。

所以我到目前为止。但我似乎无法让程序让内部特遣队正确。

def sudoku(size):
    import random as rn
    mydict = {}
    n = 0
    while len(mydict) < 9:
        n += 1
        x = range(1, size+1)
        testlist = rn.sample(x, len(x))

        isgood = True
        for dictid,savedlist in mydict.items():
            if isgood == False:
                break
            for v in savedlist:
                if testlist[savedlist.index(v)] == v:
                    isgood = False
                    break
        if isgood == True:
            #print 'success', testlist
            mydict[len(mydict)] = testlist
    return mydict, n

return_dict, total_tries = sudoku(9)
for n,v in return_dict.items():
    print n,v
print 'in',total_tries,'tries'

4 个答案:

答案 0 :(得分:1)

您可以生成一个随机数独板,在其中填写所有数字,然后删除其中的一些数字以创建拼图。这将向您保证拼图有解决方案。确保它只有一个解决方案更具挑战性,并且更具挑战性,因此您要删除更多的数字(提示:9x9数独必须至少保留17个数字)

下面的算法几乎会在N <1000时立即生成NxN个随机数独板。

from random import sample
base  = 3  # Will generate any size of random sudoku board in O(n^2) time
side  = base*base
nums  = sample(range(1,side+1),side) # random numbers
board = [[nums[(base*(r%base)+r//base+c)%side] for c in range(side) ] for r in range(side)]
rowGr = sample(range(base),base) # random rows/horizontal blocks
rows  = [ r for g in rowGr for r in sample(range(g*base,(g+1)*base),base) ] 
colGr = sample(range(base),base) # random column/vertical blocks
cols  = [ c for g in colGr for c in sample(range(g*base,(g+1)*base),base) ]            
board = [[board[r][c] for c in cols] for r in rows]

for line in board: print(line)
[8, 5, 7, 9, 3, 4, 2, 6, 1]
[9, 4, 3, 6, 1, 2, 5, 8, 7]
[6, 2, 1, 8, 7, 5, 4, 9, 3]
[2, 1, 9, 5, 6, 7, 3, 4, 8]
[5, 7, 6, 4, 8, 3, 1, 2, 9]
[4, 3, 8, 2, 9, 1, 7, 5, 6]
[1, 9, 4, 7, 2, 6, 8, 3, 5]
[3, 8, 5, 1, 4, 9, 6, 7, 2]
[7, 6, 2, 3, 5, 8, 9, 1, 4]

然后您可以从有效的数独板中删除一些数字以创建拼图:

for _ in range(side*side//2): # remove more to make it more difficult
    r,c = sample(range(side),2)
    board[r][c] = 0

for line in board: print("["+"  ".join(f"{n or '.'}" for n in line)+"]")
[8  .  7  9  .  .  2  6  1]
[9  4  .  6  .  .  5  8  7]
[.  2  1  8  7  .  4  .  3]
[2  .  .  5  .  .  .  .  8]
[5  .  .  4  8  .  1  2  .]
[.  3  8  2  .  1  7  5  .]
[1  9  .  .  2  6  8  3  .]
[.  8  .  1  4  9  .  7  2]
[.  .  2  3  5  .  .  .  4]

答案 1 :(得分:0)

这应该有用。

def sudoku(size):
    import time
    start_time=time.time()

    import sys
    import random as rn
    mydict = {}
    n = 0
    print '--started calculating--'
    while len(mydict) < 9:
        n += 1
        x = range(1, size+1)
        testlist = rn.sample(x, len(x))

        isgood = True
        for dictid,savedlist in mydict.items():
            if isgood == False:
                break
            for v in savedlist:
                if testlist[savedlist.index(v)] == v:
                    isgood = False
                    break

        if isgood == True:
            isgoodafterduplicatecheck = True
            mod = len(mydict) % 3
            dsavedlists = {}
            dtestlists = {}
            dcombindedlists = {}
            for a in range(1,mod + 1):
                savedlist = mydict[len(mydict) - a]               
                for v1 in savedlist:
                    modsavedlists = (savedlist.index(v1) / 3) % 3
                    dsavedlists[len(dsavedlists)] = [modsavedlists,v1]
                for t1 in testlist:
                    modtestlists = (testlist.index(t1) / 3) % 3
                    dtestlists[len(dtestlists)] = [modtestlists,t1]
                for k,v2 in dsavedlists.items():
                    dcombindedlists[len(dcombindedlists)] = v2
                    dcombindedlists[len(dcombindedlists)] = dtestlists[k]
            vsave = 0
            lst1 = []
            for k, vx in dcombindedlists.items():
                vnew = vx[0]
                if not vnew == vsave:
                    lst1 = []
                    lst1.append(vx[1])
                else:
                    if vx[1] in lst1:
                        isgoodafterduplicatecheck = False
                        break
                    else:
                        lst1.append(vx[1])
                vsave = vnew

            if isgoodafterduplicatecheck == True:

                mydict[len(mydict)] = testlist
                print 'success found', len(mydict), 'row'   

    print '--finished calculating--'
    total_time = time.time()-start_time
    return mydict, n, total_time

return_dict, total_tries, amt_of_time = sudoku(9)
print ''
print '--printing output--'
for n,v in return_dict.items():
    print n,v
print 'process took',total_tries,'tries in', round(amt_of_time,2), 'secs'
print '-------------------'

答案 2 :(得分:0)

如果您的目标是创建 9 x 9 Sudoku,那么为什么不开发一个更简单的程序呢? 这不必是恒定时间。     您可以更改元组的长度     对于任何 n!的n ^ 2 x n ^ 2 的倍数。然后手动删除     创造谜题的要素。

 tup = input()[1:-1].split(',')

x = input('Enter mapping to generate valid Sudoku eg. 3 for 9 x 9')
e = input('Enter 9 for 9 x 9 ...12 for 12 x 12')
f = input('Enter 3 if its a 9 x 9 and corresponding for n^2 x n^2')

x = int(x)
e = int(e)
f = int(f)

squares = []

for index in range(len(tup)):
  tup.append(tup.pop(0))
  squares.append(tup.copy())

#Everything below here is just printing

for s in range(x):
  for d in range(0,e,f):
    for si in range(s,e,f):
      for li in range(d,d+f):
        print(squares[si][li], end = '')
    print('')

#Remember that if you want
#to create n! of n^2 x n^2
#you need to edit the below
#for a valid grid
#for example

#a 9 x 9 
#would be a 3 x 3
#and so on.

侧面注:如果要创建12 x 12或任何更大的Sudoku。您需要编辑元组,以便值可读。 例如。 ['[01]','[02]',....]

此外,我还有一个好友,他帮助我将算法转换为我的业余Sudoku项目的python代码。感谢那个Reddit用户。

答案 3 :(得分:-2)

首先,随机创建一个完整的数独解决方案。这部分需要有一个数独求解器。

从数独解决方案中,不断删除随机位置的数字。对于每次删除,检查数独是否仍然有效。也就是说,数独有一个独特的解决方案。这部分需要找出是否有多个解决方案。这是数独求解器的另一个版本。

如果没有,我们将号码放回并尝试另一个位置。该过程一直持续到所有位置都尝试过为止。

import random
import numpy as np

def PossibleValueAtPosition(pz:[], row:int, col:int):
    r=row//3*3
    c=col//3*3
    return {1,2,3,4,5,6,7,8,9}.difference(set(pz[r:r+3,c:c+3].flat)).difference(set(pz[row,:])).difference(set(pz[:,col]))

def Solution_Count(pz:[], n:int, Nof_solution:int):
    if Nof_solution>1:
        return Nof_solution
    if n>=81:
        Nof_solution+=1
        return Nof_solution
    (row,col) = divmod(n,9)
    if pz[row][col]>0:
        Nof_solution = Solution_Count(pz, n+1, Nof_solution)
    else:
        l = PossibleValueAtPosition(pz, row,col)
        for v in l:
            pz[row][col] = v
            Nof_solution = Solution_Count(pz, n+1, Nof_solution)
            pz[row][col] = 0
    return Nof_solution 

def SudokuSolver(pz:[], n:int):
    if n==81:
        return True
    (row,col) = divmod(n,9)
    if pz[row][col]>0:
        if SudokuSolver(pz, n+1):
            return True
    else:
        l = list(PossibleValueAtPosition(pz, row,col))
        random.shuffle(l)
        for v in l:
            pz[row][col] = v
            if SudokuSolver(pz, n+1):
                return True
            pz[row][col] = 0
    return False

def DigHoles(pz:[], randomlist:[], n:int, nof_holes:int):
    if n>=81 or nof_holes>=64:
        return
    (row,col) = divmod(randomlist[n],9)
    if pz[row][col]>0:
        pz_check=pz.copy()
        pz_check[row][col]=0
        Nof_solution = Solution_Count(pz_check, 0, 0)
        if Nof_solution==1:
            pz[row][col]=0
            nof_holes+=1
            print(pz)
            print("{} zeros".format(nof_holes))
            print()
    DigHoles(pz, randomlist, n+1, nof_holes)

def main():
    puzzle = np.zeros((9,9), dtype=int)
    SudokuSolver(puzzle, 0)
    print(puzzle, "--------- Answer\n")
    randomlist = list(range(81))
    random.shuffle(randomlist)
    DigHoles(puzzle, randomlist, 0, 0)

if __name__ == "__main__":
    main()