Четыре года назад я написал решатель головоломок Судоку, и теперь я пытаюсь понять, как он работает, чтобы я мог повторно использовать его части для решателя головоломок KenKen. Я подумал, что мне лучше сжимать циклы в списках и выбирать более понятные имена для переменных.
Есть класс Puz, который содержит загадку ввода в виде списка (81) цифр; С 1 по 9, где значение ячейки известно, и 0, если это не так.
Класс Puz также содержит рабочую версию головоломки, за исключением того, что здесь каждый из (81) пунктов в списке является набором; где ответ для ячейки известен, набор содержит одно значение от 1 до 9, например, set ([4]), а где ответ неизвестен, набор содержит оставшиеся возможности, например, set ([3,5 , 7,9]).
Когда вызывается Puz._init __ (self, puz), эти «возможно» наборы в рабочем списке устанавливаются в set ([1,2,3,4,5,6,7,8,9]), и первый Шаг к решению - вычеркнуть все значения, которые отображаются в виде ответов в строке, столбце и блоке 3x3 этой ячейки.
Изначально рабочий список заполнялся с использованием цикла for: от 0 до 80, если это ответ, введите ответ в виде набора, иначе - в набор (диапазон (1, 10)). Я не мог понять, как включить этот вид условия в понимание списка, поэтому я разбил его на отдельную «функцию заполнения», из которых 3 версии показаны ниже. Fill_funcs различаются по веткам "not-an-answer":
return set( range( 1,(self.dim+1)))
return set( self.r_dim_1_based)
return self.set_dim_1_based
Как видите, увеличивающиеся объемы обработки перемещаются за пределы функции туда, где инициализируются маленькие переменные.
Проблема в том, что первые два варианта проскальзывают в решатель судоку и работают точно так же, как и оригинальный код. НО --- третий вариант ломается, говоря, что 6-й набор в рабочем списке (или становится) пустым. YET --- списки наборов, созданных всеми тремя вариантами, оцениваются как равные:
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