[英]How to create a Sudoku puzzle in Python
目標是在 Python 中創建一個 9x9 數獨矩陣。
所以我走到了這一步。 但我似乎無法讓程序讓內部條件框正確。
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'
您可以生成一個隨機數獨解決方案板,在其中填寫所有數字,然后刪除其中一些以創建拼圖。 這將確保謎題始終有解決方案。 確保它只有一個解決方案更具挑戰性(提示:您必須為 9x9 數獨保留至少 17 個數字)
下面的算法將在 N < 1000 的情況下立即生成 NxN 隨機數獨解板。
base = 3
side = base*base
# pattern for a baseline valid solution
def pattern(r,c): return (base*(r%base)+r//base+c)%side
# randomize rows, columns and numbers (of valid base pattern)
from random import sample
def shuffle(s): return sample(s,len(s))
rBase = range(base)
rows = [ g*base + r for g in shuffle(rBase) for r in shuffle(rBase) ]
cols = [ g*base + c for g in shuffle(rBase) for c in shuffle(rBase) ]
nums = shuffle(range(1,base*base+1))
# produce board using randomized baseline pattern
board = [ [nums[pattern(r,c)] for c in cols] for r in rows ]
for line in board: print(line)
[6, 2, 5, 8, 4, 3, 7, 9, 1]
[7, 9, 1, 2, 6, 5, 4, 8, 3]
[4, 8, 3, 9, 7, 1, 6, 2, 5]
[8, 1, 4, 5, 9, 7, 2, 3, 6]
[2, 3, 6, 1, 8, 4, 9, 5, 7]
[9, 5, 7, 3, 2, 6, 8, 1, 4]
[5, 6, 9, 4, 3, 2, 1, 7, 8]
[3, 4, 2, 7, 1, 8, 5, 6, 9]
[1, 7, 8, 6, 5, 9, 3, 4, 2]
然后,您可以從數獨解決方案中刪除一些數字來創建拼圖:
squares = side*side
empties = squares * 3//4
for p in sample(range(squares),empties):
board[p//side][p%side] = 0
numSize = len(str(side))
for line in board:
print(*(f"{n or '.':{numSize}} " for n in line))
6 . . . . 3 . . 1
. 9 . . . . . . 3
4 . 3 . . . 6 . .
. . . 5 9 . 2 . 6
. . . . . . . . .
. . 7 . . . . . 4
. . . . . . 1 7 .
. . 2 . . 8 . . .
. . 8 . . . . 4 2
對於 4x4 到 36x36 的拼圖,您可以像這樣制作更好的電路板打印:
def expandLine(line):
return line[0]+line[5:9].join([line[1:5]*(base-1)]*base)+line[9:13]
line0 = expandLine("╔═══╤═══╦═══╗")
line1 = expandLine("║ . │ . ║ . ║")
line2 = expandLine("╟───┼───╫───╢")
line3 = expandLine("╠═══╪═══╬═══╣")
line4 = expandLine("╚═══╧═══╩═══╝")
symbol = " 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"
nums = [ [""]+[symbol[n] for n in row] for row in board ]
print(line0)
for r in range(1,side+1):
print( "".join(n+s for n,s in zip(nums[r-1],line1.split("."))) )
print([line2,line3,line4][(r%side==0)+(r%base==0)])
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
║ 6 │ │ ║ │ │ 3 ║ │ │ 1 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ 9 │ ║ │ │ ║ │ │ 3 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 4 │ │ 3 ║ │ │ ║ 6 │ │ ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║ │ │ ║ 5 │ 9 │ ║ 2 │ │ 6 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ │ ║ │ │ ║ │ │ ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ │ 7 ║ │ │ ║ │ │ 4 ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║ │ │ ║ │ │ ║ 1 │ 7 │ ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ │ 2 ║ │ │ 8 ║ │ │ ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ │ 8 ║ │ │ ║ │ 4 │ 2 ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
[編輯]
以下是有關改組過程的一些其他信息...
洗牌行被分成 3 行一組。 可以將組作為一個整體進行交換,但我們不能在不破壞塊完整性的情況下跨組交換行。 (同樣的推理適用於列)
例如:
0 [6, 2, 5, 8, 4, 3, 7, 9, 1] \ -|
1 [7, 9, 1, 2, 6, 5, 4, 8, 3] | group 0 -| -| r in shuffle(rBase)
2 [4, 8, 3, 9, 7, 1, 6, 2, 5] / | -|
|
3 [8, 1, 4, 5, 9, 7, 2, 3, 6] \ | -|
4 [2, 3, 6, 1, 8, 4, 9, 5, 7] | group 1 -| * -| r in shuffle(rBase)
5 [9, 5, 7, 3, 2, 6, 8, 1, 4] / | -|
|
6 [5, 6, 9, 4, 3, 2, 1, 7, 8] \ | -|
7 [3, 4, 2, 7, 1, 8, 5, 6, 9] | group 2 -| -| r in shuffle(rBase)
8 [1, 7, 8, 6, 5, 9, 3, 4, 2] / -|
* for g in shuffle(rBase)
我們可以通過同時移動所有 3 行來交換組 0、1、2:
3 [8, 1, 4, 5, 9, 7, 2, 3, 6] \ | -|
4 [2, 3, 6, 1, 8, 4, 9, 5, 7] | group 1 -| -| r in shuffle(rBase)
5 [9, 5, 7, 3, 2, 6, 8, 1, 4] / | -|
|
6 [5, 6, 9, 4, 3, 2, 1, 7, 8] \ | -|
7 [3, 4, 2, 7, 1, 8, 5, 6, 9] | group 2 -| * -| r in shuffle(rBase)
8 [1, 7, 8, 6, 5, 9, 3, 4, 2] / -|
|
0 [6, 2, 5, 8, 4, 3, 7, 9, 1] \ | -|
1 [7, 9, 1, 2, 6, 5, 4, 8, 3] | group 0 -| -| r in shuffle(rBase)
2 [4, 8, 3, 9, 7, 1, 6, 2, 5] / | -|
* for g in shuffle(rBase)
我們可以在一個組的 3 行之間交換(例如 3,4,5)...
0 [6, 2, 5, 8, 4, 3, 7, 9, 1] \ -|
1 [7, 9, 1, 2, 6, 5, 4, 8, 3] | group 0 -| -| r in shuffle(rBase)
2 [4, 8, 3, 9, 7, 1, 6, 2, 5] / | -|
|
5 [9, 5, 7, 3, 2, 6, 8, 1, 4] \ | -|
4 [2, 3, 6, 1, 8, 4, 9, 5, 7] | group 1 -| * -| r in shuffle(rBase)
3 [8, 1, 4, 5, 9, 7, 2, 3, 6] / | -|
|
6 [5, 6, 9, 4, 3, 2, 1, 7, 8] \ | -|
7 [3, 4, 2, 7, 1, 8, 5, 6, 9] | group 2 -| -| r in shuffle(rBase)
8 [1, 7, 8, 6, 5, 9, 3, 4, 2] / -|
* for g in shuffle(rBase)
我們不能跨組交換行(例如 1 <--> 3):
0 [6, 2, 5, 8, 4, 3, 7, 9, 1] \ -|
3 [8, 1, 4, 5, 9, 7, 2, 3, 6] | group 0 -| -| r in shuffle(rBase)
2 [4, 8, 3, 9, 7, 1, 6, 2, 5] / | -|
|
1 [7, 9, 1, 2, 6, 5, 4, 8, 3] \ | -|
4 [2, 3, 6, 1, 8, 4, 9, 5, 7] | group 1 -| * -| r in shuffle(rBase)
5 [9, 5, 7, 3, 2, 6, 8, 1, 4] / | -|
|
6 [5, 6, 9, 4, 3, 2, 1, 7, 8] \ | -|
7 [3, 4, 2, 7, 1, 8, 5, 6, 9] | group 2 -| -| r in shuffle(rBase)
8 [1, 7, 8, 6, 5, 9, 3, 4, 2] / -|
* for g in shuffle(rBase)
請參見左上塊中的重復 8,下面的重復 7,等等。
單解謎題
為了生成只有一個解決方案的數獨游戲,您需要一個求解器函數,它可以告訴您是否有多個解決方案。 我建議的策略是從刪除 75%(或更多)的數字開始,然后檢查是否只有一個解決方案。 如果有多個解決方案,請放回一個數字並再次檢查。 您可以在隨機位置放回一個數字或選擇解決方案不同的位置(這將更快地收斂到單個解決方案難題)
首先編寫一個求解器,它將生成它找到的所有解決方案(理想情況下作為生成器,因為我們只需要前 2 個)。 這是一個簡單的:
def shortSudokuSolve(board):
size = len(board)
block = int(size**0.5)
board = [n for row in board for n in row ]
span = { (n,p): { (g,n) for g in (n>0)*[p//size, size+p%size, 2*size+p%size//block+p//size//block*block] }
for p in range(size*size) for n in range(size+1) }
empties = [i for i,n in enumerate(board) if n==0 ]
used = set().union(*(span[n,p] for p,n in enumerate(board) if n))
empty = 0
while empty>=0 and empty<len(empties):
pos = empties[empty]
used -= span[board[pos],pos]
board[pos] = next((n for n in range(board[pos]+1,size+1) if not span[n,pos]&used),0)
used |= span[board[pos],pos]
empty += 1 if board[pos] else -1
if empty == len(empties):
solution = [board[r:r+size] for r in range(0,size*size,size)]
yield solution
empty -= 1
從包含所有數字的solution
變量和包含已清除 3/4 數字的拼圖的board
變量開始,您可以將數字添加回棋盤,直到只有一種方法可以解決它:
solution=[[9, 5, 3, 1, 6, 7, 4, 2, 8],
[4, 2, 8, 3, 5, 9, 7, 6, 1],
[7, 6, 1, 8, 2, 4, 9, 5, 3],
[5, 8, 4, 9, 3, 6, 2, 1, 7],
[6, 3, 9, 7, 1, 2, 5, 8, 4],
[2, 1, 7, 4, 8, 5, 6, 3, 9],
[3, 4, 5, 6, 9, 1, 8, 7, 2],
[8, 7, 2, 5, 4, 3, 1, 9, 6],
[1, 9, 6, 2, 7, 8, 3, 4, 5]]
board=[ [0, 0, 0, 0, 0, 0, 0, 0, 8],
[0, 2, 0, 0, 5, 0, 7, 6, 0],
[0, 6, 0, 0, 0, 0, 0, 0, 3],
[5, 0, 0, 0, 0, 0, 2, 0, 7],
[0, 3, 0, 0, 1, 0, 0, 0, 0],
[2, 0, 0, 4, 0, 0, 0, 3, 0],
[0, 0, 0, 6, 0, 0, 0, 0, 0],
[8, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 2, 7, 0, 0, 4, 0]]
import random
from itertools import islice
while True:
solved = [*islice(shortSudokuSolve(board),2)]
if len(solved)==1:break
diffPos = [(r,c) for r in range(9) for c in range(9)
if solved[0][r][c] != solved[1][r][c] ]
r,c = random.choice(diffPos)
board[r][c] = solution[r][c]
輸出:
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
║ │ │ ║ │ │ 7 ║ │ │ 8 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ 2 │ ║ │ 5 │ ║ 7 │ 6 │ ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ 6 │ ║ 8 │ │ 4 ║ │ │ 3 ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║ 5 │ │ ║ │ │ ║ 2 │ │ 7 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ │ 3 │ ║ │ 1 │ ║ │ │ ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 2 │ │ ║ 4 │ │ ║ │ 3 │ ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║ │ 4 │ ║ 6 │ │ ║ │ │ ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 8 │ │ ║ │ │ ║ 1 │ │ 6 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 1 │ │ ║ 2 │ 7 │ ║ │ 4 │ ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
請注意,對於 9x9 數獨板,這將在合理的時間內工作,但對於較大的板,您將需要更好/更快的求解器功能
另請注意,這通常會產生“簡單”的謎題,因為在某些情況下它會增加比絕對必要的數量更多的數字。 選擇最小的一組數字來添加回需要一個分層或回溯的方法,這會更復雜一些,運行起來也慢得多。 從更多的空白空間開始(例如 80% 或更多)將很有可能在合理的時間范圍內產生更難的謎題。
這應該有效。
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 '-------------------'
如果您的目標是創建9 x 9數獨,那么為什么不做一個更簡單的程序呢? 多時間在任何n^2 xn^2 (板)上工作。 要創建拼圖,您可能必須手動刪除元素。 保證一種解決方案需要一些回溯。 對於較大的 n^2 xn^2 數獨拉丁方,多時間是您想要的。
#Provide a list of non-repeating n-elements to output a valid sudoku grid.
#this code runs on python3
print('enter with [1,2,3...] brackets')
tup = input()[1:-1].split(',')
#Input required to map out valid n x m or n^2 x n^2 Sudoku Grid
x = input('Enter mapping 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 ... n^2 x n^2:')
x = int(x)
e = int(e)
f = int(f)
#Manipulation of Elements to prepare valid grid
squares = []
for i in range(len(tup)):
squares.append(tup[i:] + tup[:i])
#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 a single board 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.
沒有重復元素! 對於大於 9 x 9 的網格,請使用附加括號以提高可讀性。 例如。 [[01],[02],[03],....] 另外,請記住,您需要知道乘法才能輸出正確映射的 n^2 xn^2。 例如,對於如下輸入,25 x 25 應該是 5 x 5
對於 x,x = 5
對於 e,e = 25
對於 f,f = 5
另外,我有一個朋友幫我將我的算法轉換成這個 Python 代碼,用於我的業余數獨項目。 感謝那個 Reddit 用戶。
順便說一句,實際上是 O(m^2) 時間。 證明
感謝 Reddit 好友的幫助。
這是我的解決方案
import random
def create_board(height, width):
board = [[(i + k) % 9 + 1 for i in range(1, height + 1)] for k in range(width)] # Creates a board where each row counts to 9 such that no row contains more than one kind of each number. You can run this separately to see what it generates.
random.shuffle(board) # Shuffles this list of lists
board = [[board[x][y] for x in range(9)] for y in range(9)] # Reads each row and puts it into a column. (basically rotates it to its side)
random.shuffle(board) # Shuffles this list again but while its on its side
return board
希望大家喜歡。 它不會刪除數字,但這可以在您使用此函數隨機使用該函數后完成
def remove_numbers(board, remove_amount):
h, w, r = len(board), len(board[0]), []
spaces = [[x, y] for x in range(h) for y in range(w)]
for k in range(remove_amount):
r = random.choice(spaces)
board[r[0]][r[1]] = 0
spaces.remove(r)
return board
# import pygame library
import pygame
# initialise the pygame font
pygame.font.init()
# Total window
screen = pygame.display.set_mode((500, 600))
# Title and Icon
pygame.display.set_caption("SUDOKU SOLVER USING BACKTRACKING")
img = pygame.image.load('icon.png')
pygame.display.set_icon(img)
x = 0
y = 0
dif = 500 / 9
val = 0
# Default Sudoku Board.
grid =[
[7, 8, 0, 4, 0, 0, 1, 2, 0],
[6, 0, 0, 0, 7, 5, 0, 0, 9],
[0, 0, 0, 6, 0, 1, 0, 7, 8],
[0, 0, 7, 0, 4, 0, 2, 6, 0],
[0, 0, 1, 0, 5, 0, 9, 3, 0],
[9, 0, 4, 0, 6, 0, 0, 0, 5],
[0, 7, 0, 3, 0, 0, 0, 1, 2],
[1, 2, 0, 0, 0, 7, 4, 0, 0],
[0, 4, 9, 2, 0, 6, 0, 0, 7]
]
# Load test fonts for future use
font1 = pygame.font.SysFont("comicsans", 40)
font2 = pygame.font.SysFont("comicsans", 20)
def get_cord(pos):
global x
x = pos[0]//dif
global y
y = pos[1]//dif
# Highlight the cell selected
def draw_box():
for i in range(2):
pygame.draw.line(screen, (255, 0, 0), (x * dif-3, (y + i)*dif), (x * dif + dif + 3, (y + i)*dif), 7)
pygame.draw.line(screen, (255, 0, 0), ( (x + i)* dif, y * dif ), ((x + i) * dif, y * dif + dif), 7)
# Function to draw required lines for making Sudoku grid
def draw():
# Draw the lines
for i in range (9):
for j in range (9):
if grid[i][j]!= 0:
# Fill blue color in already numbered grid
pygame.draw.rect(screen, (0, 153, 153), (i * dif, j * dif, dif + 1, dif + 1))
# Fill grid with default numbers specified
text1 = font1.render(str(grid[i][j]), 1, (0, 0, 0))
screen.blit(text1, (i * dif + 15, j * dif + 15))
# Draw lines horizontally and verticallyto form grid
for i in range(10):
if i % 3 == 0 :
thick = 7
else:
thick = 1
pygame.draw.line(screen, (0, 0, 0), (0, i * dif), (500, i * dif), thick)
pygame.draw.line(screen, (0, 0, 0), (i * dif, 0), (i * dif, 500), thick)
# Fill value entered in cell
def draw_val(val):
text1 = font1.render(str(val), 1, (0, 0, 0))
screen.blit(text1, (x * dif + 15, y * dif + 15))
# Raise error when wrong value entered
def raise_error1():
text1 = font1.render("WRONG !!!", 1, (0, 0, 0))
screen.blit(text1, (20, 570))
def raise_error2():
text1 = font1.render("Wrong !!! Not a valid Key", 1, (0, 0, 0))
screen.blit(text1, (20, 570))
# Check if the value entered in board is valid
def valid(m, i, j, val):
for it in range(9):
if m[i][it]== val:
return False
if m[it][j]== val:
return False
it = i//3
jt = j//3
for i in range(it * 3, it * 3 + 3):
for j in range (jt * 3, jt * 3 + 3):
if m[i][j]== val:
return False
return True
# Solves the sudoku board using Backtracking Algorithm
def solve(grid, i, j):
while grid[i][j]!= 0:
if i<8:
i+= 1
elif i == 8 and j<8:
i = 0
j+= 1
elif i == 8 and j == 8:
return True
pygame.event.pump()
for it in range(1, 10):
if valid(grid, i, j, it)== True:
grid[i][j]= it
global x, y
x = i
y = j
# white color background\
screen.fill((255, 255, 255))
draw()
draw_box()
pygame.display.update()
pygame.time.delay(20)
if solve(grid, i, j)== 1:
return True
else:
grid[i][j]= 0
# white color background\
screen.fill((255, 255, 255))
draw()
draw_box()
pygame.display.update()
pygame.time.delay(50)
return False
# Display instruction for the game
def instruction():
text1 = font2.render("PRESS D TO RESET TO DEFAULT / R TO EMPTY", 1, (0, 0, 0))
text2 = font2.render("ENTER VALUES AND PRESS ENTER TO VISUALIZE", 1, (0, 0, 0))
screen.blit(text1, (20, 520))
screen.blit(text2, (20, 540))
# Display options when solved
def result():
text1 = font1.render("FINISHED PRESS R or D", 1, (0, 0, 0))
screen.blit(text1, (20, 570))
run = True
flag1 = 0
flag2 = 0
rs = 0
error = 0
# The loop thats keep the window running
while run:
# White color background
screen.fill((255, 255, 255))
# Loop through the events stored in event.get()
for event in pygame.event.get():
# Quit the game window
if event.type == pygame.QUIT:
run = False
# Get the mouse position to insert number
if event.type == pygame.MOUSEBUTTONDOWN:
flag1 = 1
pos = pygame.mouse.get_pos()
get_cord(pos)
# Get the number to be inserted if key pressed
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x-= 1
flag1 = 1
if event.key == pygame.K_RIGHT:
x+= 1
flag1 = 1
if event.key == pygame.K_UP:
y-= 1
flag1 = 1
if event.key == pygame.K_DOWN:
y+= 1
flag1 = 1
if event.key == pygame.K_1:
val = 1
if event.key == pygame.K_2:
val = 2
if event.key == pygame.K_3:
val = 3
if event.key == pygame.K_4:
val = 4
if event.key == pygame.K_5:
val = 5
if event.key == pygame.K_6:
val = 6
if event.key == pygame.K_7:
val = 7
if event.key == pygame.K_8:
val = 8
if event.key == pygame.K_9:
val = 9
if event.key == pygame.K_RETURN:
flag2 = 1
# If R pressed clear the sudoku board
if event.key == pygame.K_r:
rs = 0
error = 0
flag2 = 0
grid =[
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
]
# If D is pressed reset the board to default
if event.key == pygame.K_d:
rs = 0
error = 0
flag2 = 0
grid =[
[7, 8, 0, 4, 0, 0, 1, 2, 0],
[6, 0, 0, 0, 7, 5, 0, 0, 9],
[0, 0, 0, 6, 0, 1, 0, 7, 8],
[0, 0, 7, 0, 4, 0, 2, 6, 0],
[0, 0, 1, 0, 5, 0, 9, 3, 0],
[9, 0, 4, 0, 6, 0, 0, 0, 5],
[0, 7, 0, 3, 0, 0, 0, 1, 2],
[1, 2, 0, 0, 0, 7, 4, 0, 0],
[0, 4, 9, 2, 0, 6, 0, 0, 7]
]
if flag2 == 1:
if solve(grid, 0, 0)== False:
error = 1
else:
rs = 1
flag2 = 0
if val != 0:
draw_val(val)
# print(x)
# print(y)
if valid(grid, int(x), int(y), val)== True:
grid[int(x)][int(y)]= val
flag1 = 0
else:
grid[int(x)][int(y)]= 0
raise_error2()
val = 0
if error == 1:
raise_error1()
if rs == 1:
result()
draw()
if flag1 == 1:
draw_box()
instruction()
# Update window
pygame.display.update()
# Quit pygame window
pygame.quit()
首先,隨機創建一個完整的數獨解決方案。 這部分需要有一個數獨求解器。
從數獨解決方案中,不斷刪除隨機位置的數字。 對於每次刪除,檢查數獨是否仍然有效。 也就是說,數獨有一個獨特的解決方案。 這部分需要找出是否有多個解決方案。 它是數獨求解器的另一個版本。
如果沒有,我們會放回號碼並嘗試另一個位置。 該過程繼續進行,直到所有位置都嘗試過。
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()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.