这是recursive Sudoku solve
代码,这不是学校作业。我无法弄清楚如何让它回归"备份"通过我以前的动作。它会在first row
结束时卡住,因为该地点没有有效数字,只是不断尝试找到适合那里的数字。我遇到问题的功能是check
。
在阅读了你的答案后,我已经接近了,但它并不完全存在。它一直支持并退出递归
import sys
class Board:
def __init__(self, grid):
self.grid = grid
self.ogrid = grid
def get_col(self, col):
column = []
for i in self.grid:
column.append(str(i[col]))
return column
def get_row(self, row):
return self.grid[row]
def check_row(self, r, val):
row = self.grid[r]
for i in range(0,9):
if str(val) in row:
return False
return True
def check_col(self, column, val):
col = self.get_col(column)
for i in range(0,9):
if str(val) in col:
return False
return True
def check_square(self, x, y, val):
col = (y//3)*3
row = (x//3)*3
s = ''
for i in range(row, row+3):
for j in range(col, col+3):
s += str(self.grid[i][j])
if str(val) in s:
return False
return True
def check_cell(self, x, y, val):
if self.check_col(y, val) == False:
return False
elif self.check_row(x, val) == False:
return False
elif self.check_square(x, y, val) == False:
return False
return True
def check(self, x, y):
if y == 9:
y = 0
x += 1
if x == 9:
self.print_board()
sys.exit()
if self.ogrid[x][y] == '.':
for val in range(1,10):
if self.check_cell(x, y, val):
self.grid[x][y] = str(val)
self.check(x, y+1)
##I don't think the reset is working and I'm not sure why
if self.ogrid[x][y] == '.': #reset index
self.grid[x][y] = '.'
self.print_board() #Notice it never prints a '.' in spots that have changed
else:
self.check(x,y+1)
return
def print_board(self):
for i in range(0,9):
for j in range(0,9):
sys.stdout.write(self.grid[i][j])
if j == 2 or j == 5:
sys.stdout.write(' ')
if i == 2 or i == 5:
sys.stdout.write('\n')
print('')
def main():
f = open("./easySudoku.txt",'r')
s = ''
grid = []
row = []
for line in f:
s += line
print line
s = s.replace(' ','')
s = s.replace('\n','')
for i in range(0,9):
row = []
for j in range(0,9):
row.append(s[(i*9) + j])
grid.append(row)
sudoku = Board(grid)
sudoku.check(0,0, 1)
if __name__ == "__main__":
main()
以下是检查功能应如何工作
处尝试每个值
check
获取棋盘的x和y坐标,并从0,0
开始,它从1-9
开始运行for循环,并设置在该索引处起作用的第一个值,然后移动到下一个索引。当它到达行的末尾时,它向下移动一行并返回到第一列。如果没有值在索引处起作用,则将当前索引重置为'.'
并将索引向后移动一个并继续计数到9
。即如果索引0,0
的当前值为2
,则继续3
。如果3
有效,则向前移动一个索引,依此类推,直到董事会被填满为止。对于简单的答案,它会在每个空索引1-9
如果不清楚,请告诉我
此处是我正在使用的电路板
..6 ..7 3..
.18 ..9 .5.
5.. ... .64
92. .8. ...
... 763 ...
... .9. .75
63. ... ..8
.9. 3.. 52.
..2 4.. 6..
答案 0 :(得分:2)
问题是你似乎为你尝试的每个数字递归一步,这将消耗每个理智的堆栈。我建议您也使用迭代并使用return
进行备份(这样你应该只使用81个堆栈帧 - 这样当你获得一千个堆栈帧时它会失败)。
我以前做过求解器,它会很快找到解决方案......
答案 1 :(得分:1)
我为检查您的代码所做的工作:将此行添加为check
方法的第一行:
raw_input('x: %d, y: %d, val: %d' % (x,y,val))
并在插入数字后打印电路板。
看起来你的求解器在(x,y) = (0,3)
犯了第一个错误。它检查所有数字最多9,然后在那里放9。根据你的算法,它应该是1.挂断是你的check_square
方法。你应该
col = (y//3)*3
row = (x//3)*3
修好后,下一个错误会在(x,y) = (1,8)
开始,从self.check(1, 8, 1)
开始。此广场没有合法的值(使用您的算法到此时为止)(一直到self.check(1, 8, 9)
)。接下来称为self.check(1, 8, 10)
。自val==10
起,它返回,然后在self.check(1, 8, 9)
的调用中,调用最后一行self.check(x, y-1, val+1)
,即self.check(1, 7, 10)
。它当然会立即返回,因为val == 10
。我们回到self.check(1, 8, 8)
并调用方法定义的最后一行。执行的旁边是self.check(1, 7, 9)
,它会生成下一个self.check(1, 8, 1)
。看起来熟悉?我们已经在这里,并且在此期间没有状态变化。甚至没有意识到这一点,这将成为一个无限循环。
那令人困惑吗?当然是。程序员试图避免递归是有原因的,除非在教授递归概念时。追踪这些类型的递归错误很困难,但只需几行打印就可以完成。
P.S。你的算法很有趣。我想知道你在哪里找到它......绝对不是人类玩的方式(所有的猜测和编辑)。 FWIW,我首先只会在董事会中插入一个值,如果该值是该正方形的唯一合法移动,并且只有当董事会中的所有空白方块都不明确时才会猜测。
将标准库的一部分import copy
添加到顶部,然后将__init__
更改为self.ogrid = copy.deepcopy(grid)
。应该解决你的问题。见https://stackoverflow.com/a/2612815/2100286。您创建网格重复版本的方法可以达到同样的效果。
答案 2 :(得分:0)
我不知道这个片段:
if y == -1:
y = 8
x -= 1
如果y
等于行中的最后一个位置,您将其设置为8
,这是该行中最后一个位置的索引?这可能是它为什么没有正常进行的原因吗?
答案 3 :(得分:0)
好吧,我解决了我的问题!
这就是我的所作所为。我接受了@Skyking给我的建议,只是通过递归索引而不是我原来的每个索引的值。我改变的第二件事是接受@James Pringles关于如何修复我的check_square
函数和复制网格的建议,以便ogrid
在grid
更改时不会改变。
因为我不能给两张绿色支票,所以我把它给了@James Pringle,因为他/她帮助了我最多,但是如果没有@ Skyking的建议我就不可能得到它
这是完成的代码
import sys
import copy
class Board:
def __init__(self, grid):
self.grid = grid
self.ogrid = copy.deepcopy(grid)
def get_col(self, col):
column = []
for i in self.grid:
column.append(str(i[col]))
return column
def get_row(self, row):
return self.grid[row]
def check_row(self, r, val):
row = self.grid[r]
if str(val) in row:
return False
return True
def check_col(self, column, val):
col = self.get_col(column)
if str(val) in col:
return False
return True
def check_square(self, x, y, val):
col = (y//3)*3
row = (x//3)*3
s = ''
for i in range(row, row+3):
for j in range(col, col+3):
s += str(self.grid[i][j])
if str(val) in s:
return False
return True
def check_cell(self, x, y, val):
if self.check_col(y, val) == False:
return False
elif self.check_row(x, val) == False:
return False
elif self.check_square(x, y, val) == False:
return False
return True
def check(self, x, y):
if y == 9:
y = 0
x += 1
if x == 9:
self.print_board()
sys.exit()
if self.ogrid[x][y] == '.':
for val in range(1,10):
if self.check_cell(x, y, val):
self.grid[x][y] = str(val)
self.check(x, y+1)
if self.ogrid[x][y] == '.':
self.grid[x][y] = self.ogrid[x][y]
else:
self.check(x,y+1)
return True
def print_board(self):
for i in range(0,9):
for j in range(0,9):
sys.stdout.write(self.grid[i][j])
if j == 2 or j == 5:
sys.stdout.write(' ')
if i == 2 or i == 5:
sys.stdout.write('\n')
print('')
def main():
f = open("./easySudoku.txt",'r')
s = ''
grid = []
row = []
for line in f:
s += line
s = s.replace(' ','')
s = s.replace('\n','')
for i in range(0,9):
row = []
for j in range(0,9):
row.append(s[(i*9) + j])
grid.append(row)
sudoku = Board(grid)
sudoku.check(0,0)
print('shouldn\'t be here')
if __name__ == "__main__":
main()