我目前正在python中编写一个数独求解程序,只是为了好玩。这是我现在拥有的:
#!/usr/bin/env python
"""Reads in a file formatted with nine lines each of which has nine characters
corresponding to a sudoku puzzle. A blank is indicated by the value '0'
Eventually should output a solution to the input puzzle"""
import sys
class cell:
value = 0
"""Value of 0 means it is undetermined"""
def __init__(self, number):
self.value = number
self.possible = [2, 2, 2, 2, 2, 2, 2, 2, 2]
"""Possibility a given value can be the number. 0 is impossible, 1 is definite, 2 is maybe"""
def selfCheck(self):
"""Checks if the cell has only one possible value, changes the value to that number"""
if self.value == 0:
if self.possible.count(2) == 1:
"""If there's only one possible, change the value to that number"""
i = 1
for item in self.possible:
if item == 2:
self.value = i
self.possible[i-1] = 1
i+=1
def checkSection(section):
"""For any solved cells in a section, marks other cells as not being that value"""
for cell in section:
if cell.value != 0:
for otherCell in section:
otherCell.possible[cell.value-1] = 0
def checkChunk(chunk):
"""Checks a chunk, the set of rows, columns, or squares, and marks any values that are impossible for cells based on that
chunk's information"""
for section in chunk:
checkSection(section)
def selfCheckAll(chunk):
for section in chunk:
for cell in section:
cell.selfCheck()
cellRows = [[],[],[],[],[],[],[],[],[]]
cellColumns = [[],[],[],[],[],[],[],[],[]]
cellSquares = [[],[],[],[],[],[],[],[],[]]
infile = open(sys.argv[1], 'r')
"""Reads the file specified on the command line"""
i = 0
for line in infile:
"""Reads in the values, saves them as cells in 2d arrays"""
line = line.rstrip('\n')
for char in line:
row = i/9
column = i%9
newcell = cell(int(char))
cellRows[row].append(newcell)
cellColumns[column].append(newcell)
row = (row/3)*3
column = column/3
square = row+column
cellSquares[square].append(newcell)
i+=1
i = 0
while i<50:
checkChunk(cellRows)
checkChunk(cellColumns)
checkChunk(cellSquares)
selfCheckAll(cellRows)
i+=1
displayRow = []
for row in cellRows:
for cell in row:
displayRow.append(str(cell.value))
i = 0
while i < 9:
output1 = ''.join(displayRow[9*i:9*i+3])
output2 = ''.join(displayRow[9*i+3:9*i+6])
output3 = ''.join(displayRow[9*i+6:9*i+9])
print output1 + ' ' + output2 + ' ' + output3
if i%3 == 2:
print
i+=1
我的问题是:
i = 0
while i<50:
checkChunk(cellRows)
checkChunk(cellColumns)
checkChunk(cellSquares)
selfCheckAll(cellRows)
i+=1
我想运行代码,直到它检测到前一次迭代没有变化,而不是当前硬编码50次。这可能是因为不再有逻辑的下一步(需要启动暴力强制值),或者拼图完全解决了。无论哪种方式,我都需要我的当前数据集的深层副本(比如cellRows)来比较实际副本在通过我的checkChunk函数时可能发生的变化。
Python中有这样的东西吗? (如果有更好的方法来检查我是否已经完成,那也会有效,尽管此时如果我可以进行深入的比较,我会更感兴趣。)
编辑 - 我尝试使用copy.deepcopy。虽然这创建了一个很好的深层副本,但使用'=='检查两者之间的相等性总是返回false。
答案 0 :(得分:1)
通过比较str()
可以进行非常粗略的比较。当然不是最好的方法,但考虑到列表的复杂性,它可能没问题。
如果你想要更坚实的东西,你可以写一个递归函数来处理它。
答案 1 :(得分:1)
您可以随时挑选对象并将其作为字符串进行比较。将它们转换为JSON字符串可能是最简单的方法之一。我怀疑有一种资源效率更高的方式,但它的工作正常。这是一个例子:
>>> from simplejson import dumps
>>> ls1 = [1, [2, 3], [4, [5, 6]]]
>>> ls2 = [1, [2, 3], [4, [5, 6]]]
>>> dumps(ls1) == dumps(ls2)
True
>>>
答案 2 :(得分:1)
我不确定比较字符串表示是否可行,但如果性能问题,我猜您可以进行基准测试。这是对深度/递归列表比较的快速尝试:
from itertools import izip
def list_compare(a, b):
if type(a) != type(b):
return False
if type(a) != list:
return a == b
if len(a) != len(b):
return False
for a_, b_ in izip(a, b):
if not list_compare(a_, b_):
return False
return True
它使用常规相等运算符对递归列表和非列表项进行比较。
答案 3 :(得分:0)
在您的情况下,这只是一个二维列表。因此,将它们转换为单维字符串列表并进行比较将使代码最小。
list_of_list = [[1, 2, 3, 4, 5, 6, 7, 8], [2, 3, 4, 5, 6, 7, 8, 1], [3, 4, 5, 6, 7, 8, 1, 2], [4, 5, 6, 7, 8, 1, 2, 3], [5, 6, 7, 8, 1, 2, 3, 4], [6, 7, 8, 1, 2, 3, 4, 5], [7, 8, 1, 2, 3, 4, 5, 6], [8, 1, 2, 3, 4, 5, 6, 7]]
current_iteration = ",".join(["".join(map(str, row)) for row in list_of_list])
previous_iteration = ",".join(["".join(map(str, row)) for row in list_of_list])
if current_iteration == previous_iteration:
return
生成字符串后,您可以用相同的方式转换比较板,并以相同的方式比较它们。
但是,我建议直接将它们作为列表进行比较会更容易阅读
previous_iteration = [[1,2,3], [2,3,1], [3,1,2]]
current_iteration = [[1,2,3], [2,3,1], [3,1,2]]
if len(current_iteration) != len(previous_iteration):
# This check is not required in your case as the lengths will be same for all iterations
return False
for index, item_list in enumerate(current_iteration):
if item_list != previous_iteration[index]:
return False
return True
答案 4 :(得分:0)
如果checkChunk()
已更改,请添加到selfCheckAll()
和True/False
返回中。之后,您可以编写类似
while True:
changed = checkChunk(cellRows)
changed = changed or checkChunk(cellColumns)
changed = changed or checkChunk(cellSquares)
changed = changed or selfCheckAll(cellRows)
if not changed:
break
答案 5 :(得分:-1)
标准copy模块中提供了通用的深层复制工具:您要搜索的是copy.deepcopy
函数。