Четыре года назад я написал головоломку для судоку, и теперь я пытаюсь понять, как она работает, чтобы я мог повторно использовать части это для решения головоломки 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
Как вы видите, все большее количество обработки перемещаются за пределы функции туда, где маленькие переменные инициализируются.
Беда в том, что первые два варианта скользят в решатель Судоку и работают точно так, как это сделал оригинальный код. НО --- третья вариация ломается, говоря, что 6-й набор в рабочем списке (или становится) пустым. ПОКА --- списки множеств, полученных всеми тремя вариантами оценки равными:
p.W1 == p.W2 == p.W3 -> True
Я в тупик.
Вот некоторый код для создания списков множеств:
#!/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
ЭТО было быстро, Алекс! Я все еще редактировал название! Таким образом, бессмысленно пытаться устранить всю обработку из строки «возврат»; так или иначе, мне придется вызвать set(). Но набор множеств все еще является множеством, а не каким-то «вложенным множеством». Raffiniert, sehr raffiniert. И я не думаю, что я бы наткнулся на это объяснение для looooong времени. – behindthefall
Также кажется, что эта «мутация любой ссылки на объект меняет этот объект» (что, конечно, когда я пишу это так, я узнаю, но когда он похоронен в инициализации, я не видел в этот случай) не поднялся и укусил меня раньше. Как и в других местах этого решателя Судоку. – behindthefall
Правильно, 'set (someset)' - это только мелкая копия (точно так же, как 'someset.copy()', но я предпочитаю применять единообразную и приятную идиому, чтобы «вызвать тип, чтобы сделать (мелкую) копию« идиомой »широко; -). В любом случае, всегда рады помочь! –