问题描述
我对编程还很陌生,最近我开始研究sudoko求解器,除了求解算法本身之外,其他一切都很好,我从互联网上获得了一些帮助,但是由于我自己编写了方法,所以我可以找不到我的代码的准确解决方案,任何帮助将不胜感激!
问题:代码一直运行到无法将值输入到空(0)索引之一中为止,而不是回溯,它只是停止了。
如果您可以让我知道我在做错什么,或者提出可能的方法来改进代码,那么任何事情都会有很大帮助!
import time
start_time = time.time()
grid = [
[7,8,4,1,2,0],[6,7,5,9],[0,6,8],9,3,[9,5],2],[1,7]
]
def printBoard():
print("Suduko Board")
for row in grid:
for elem in row:
print(elem,end=' ')
print()
def checkInRow(grid,row,num):
for i in range(0,9):
if(grid[row][i] == num):
return True
return False
def checkInCol(grid,col,9):
if(grid[i][col] == num):
return True
return False
def checkInBox(grid,num):
#This will give the starting point for the Box
BoxX = (row // 3) * 3
BoxY = (col // 3) * 3
for i in range(3):
for j in range(3):
if((grid[BoxY + j][BoxX + i]) == num):
return True
return False
def findNextEmpty(grid,num):
for row in range(9):
for col in range(9):
if(grid[row][col] == num):
return row,col
return None
def checkSafe(grid,num): #Returns true if safe returns false if unsafe
return not checkInRow(grid,num) and not checkInCol(grid,num) and not checkInBox(grid,num)
#PROBLEM IS HERE \/
def solveSudoko(grid,i,j):
if not findNextEmpty(grid,0):
return True
else:
i = findNextEmpty(grid,0)[0] # Finds Row #
j = findNextEmpty(grid,0)[1] # Finds Col #
print(i,j)
for value in range(1,10):
if checkSafe(grid,j,value) == True:
grid[i][j] = value
printBoard()
print("--- %s seconds ---" % (time.time() - start_time))
if(solveSudoko(grid,j)):
return True
grid[i][j] = 0
return False
#print(str(value) + " can go in grid[" + str(i) + "]" + "[" + str(j) + "]")
printBoard()
solveSudoko(grid,0)
解决方法
问题说明
我认为问题在于您的网格是一个列表,即是可变的。这意味着,如果您调用solveSudoko(grid,i,j)
,则它不会复制网格,但是内存中只有一个网格。因此,solveSudoko
遇到问题后便无法回滚,因为您已经更改了原始网格。可能的解决方案是使用不可更改的数据类型(例如元组或有点难看),但也可能是复制网格。
示例:
grid = [1,2,3]
def test(grid):
grid[0] = 0
test(grid)
print(grid)
---> [0,3]
快速但丑陋的解决方案
您可能可以避免在代码开头添加import copy
并替换
if(solveSudoko(grid,j)):
作者
if(solveSudoko(copy.deepcopy(grid),j)):
示例:
grid = [1,3]
def test(grid):
grid[0] = 0
test(copy.deepcopy(grid))
print(grid)
---> [1,3]
请注意,在示例中也可以使用copy.copy
而不是copy.deepcopy
,因为整数是不可变的,但是如代码中所示,列表是列表,您需要copy.deepcopy
。
好的解决方案
示例:
grid = (1,3)
def test(grid):
grid = (0,3)
test(grid)
print(grid)
---> (1,3)
元组的问题是获得新的网格并不有趣。我可能会使用一个小类来为我管理网格:
class Grid:
def __init__(self,grid):
assert type(grid) == tuple
self.grid = grid
@staticmethod
def gird_from_list(list_):
return Grid(tuple(list_[i][j] for i in range(len(list_)) for j in range(len(list_[0]))))
def __repr__(self):
return "\n".join(str(self.grid[i*9:(i+1)*9]) for i in range(9))
def set(self,j,value):
return Grid(tuple(value if i+j*9==k else x for k,x in enumerate(self.grid)))
tuple_grid = Grid.gird_from_list(gird)
tuple_grid2 = tuple_grid.set(8,8,0)
这里grid_from_list
只是将您的列表转换为我的格式,而__repr__
给您一个2d网格的漂亮表示,尽管我实际上只保留了1d元组。如果您不知道在打印类的实例时总是调用__repr__
。
现在打印tuple_grid将产生
(7,4,1,0)
(6,7,5,9)
(0,6,8)
(0,0)
(0,9,3,0)
(9,5)
(0,2)
(1,7)
打印出tuple_grid2将会产生
(7,0)
因此,在调用set时,围带不会改变,但会为您提供一个具有新值的全新围带。