2009-11-02 46 views
0

四年前,我写了一个Sudoku拼图求解器,现在我试图了解它是如何工作的,以便我可以重用零件它是一个KenKen难题求解器。我认为我更好地将循环压缩到列表解析中,并为变量选择更多自解释名称。一个在Python 2.5中表现不同的案例(我认为......)

有一个Puz类包含输入难题作为(81)数字列表; 1到9,其中单元格的值是已知的,0表示不是。

Puz类还包含一个拼图的工作版本,除了这里列表中的每个(81)项是一个集合;其中一个单元格的答案是已知的,该集合包含一个从1到9的值,例如set([4]),并且在答案未知的情况下,该集合包含剩余的可能性,例如set([3,5 ,7,9])。 当Puz._init __(self,puz)被调用时,工作列表中的那些“可能”集被设置为([1,2,3,4,5,6,7,8,9]),并且找到解决方案的第一步是在单元格的行,列和3x3块中删除显示为答案的所有值。

最初,使用for循环填充工作列表:对于0到80,如果它是答案,则将答案作为集合放入,否则放入集合(范围(1,10))。我无法弄清楚如何将这种条件转化为列表理解,因此我将其分解为一个单独的“填充函数”,其中3个版本如下所示。该fill_funcs在他们的“不的回答分支”有所不同:

return set(range(1,(self.dim+1))) 
return set(self.r_dim_1_based) 
return self.set_dim_1_based 

正如你看到的,处理的越来越多的功能外搬回到小变量初始化。

问题是,前两个变体滑入Sudoku求解器中,并按原始代码的方式工作。但是---第三种变化中断了,说工作列表中的第六个集合是(或变成)空的。 YET ---由这三种不同的制作组名单评估作为平等:

p.W1 == == p.W2 p.W3 - >真

我难倒。

下面是制作的集列出了一些代码:

#!/usr/bin/env python 
import copy 
from math import sqrt 

''' 
Puzzle #15, from The Guardian: 050624: #41: rated difficult 
''' 
puz = [ 
0,0,1, 9,0,0, 3,0,0, 
0,0,0, 0,0,0, 2,0,0, 
7,6,0, 0,2,0, 0,0,9, 

3,0,0, 0,6,0, 0,0,5, 
0,0,2, 1,0,3, 4,0,0, 
4,0,0, 0,9,0, 0,0,3, 

1,0,0, 0,3,0, 0,9,7, 
0,0,4, 0,0,0, 0,0,0, 
0,0,5, 0,0,8, 6,0,0 
] 

class GroupInfo: pass 

class Puz(GroupInfo): 
    def __init__(self, puz): 
     self.A = copy.deepcopy(puz) 
     self.ncells = len(self.A) 
     self.r_ncells = range(0,self.ncells) 
     self.dim =  int(sqrt(self.ncells)) 
     assert (self.dim ** 2) == self.ncells, "puz is not square" 
     self.r_dim_0_based = range(0,self.dim) 
     self.r_dim_1_based = range(1, self.dim + 1) 
     self.set_dim_1_based = set(self.r_dim_1_based) ## <<---- causes to fail! 
     ##### with 'empty set at W[5]' !?!?!? 

     def W1_fill_func(val): 
      if (val == 0): 
       return set(range(1,(self.dim+1))) 
      else: 
       return set([val]) 

     self.W1 = [ W1_fill_func(self.A[cid]) 
        for cid in self.r_ncells ] 

     def W2_fill_func(val): 
      if (val == 0): 
       return set(self.r_dim_1_based) 
      else: 
       return set([val]) 

     self.W2 = [ W2_fill_func(self.A[cid]) 
        for cid in self.r_ncells ] 

     def W3_fill_func(val): 
      if (val == 0): 
       return self.set_dim_1_based 
      else: 
       return set([val]) 

     self.W3 = [ W3_fill_func(self.A[cid]) 
        for cid in self.r_ncells ] 

     return 
    #def Puz.__init__() 
#class Puz 

p = Puz(puz) 
print p.W1 == p.W2 == p.W3 

回答

2

self.W3如你编码它包含相同的一组对象多引用 - 只要你调用任何不同诱变方法上一个这些参考文献中,你已经改变了所有其他文献。您需要确保W3_fill_func返回独立副本与所有其他人一样,通过改变其回报return set(self.set_dim_1_based)

+0

这很快,亚历克斯!我还在编辑标题! 因此,尝试从“返回”行中消除所有处理的方式毫无意义;无论如何,我将不得不打电话给set()。但是,一组集合仍然是一个集合,而不是某种“嵌套集合”。 Raffiniert,sehr raffiniert。我不认为我会在一段漫长的时间里解释这个解释。 – behindthefall 2009-11-02 01:44:37

+0

也似乎是绝对愚蠢的运气,这个'对任何对象的引用的变化改变对象'(当然,当我这样写出来,我认识到,但是当它被埋在一个初始化中,我没有看到这种情况)还没有起来,并且在我之前咬过我。就像在那个数独解算器的其他地方一样。 – behindthefall 2009-11-02 01:54:25

+0

对,'set(someset)'只是一个浅拷贝(就像'someset.copy()'一样,但我更喜欢用统一的和好的习惯用法来“调用类型来制作一个(浅)复制”的习语。 - )。无论如何,总是乐于帮忙! – 2009-11-02 02:09:42

相关问题