class SolutionStep(object): ROW = 0 COL = 1 def __init__(self, nonogram): self._uid = 1000 self._idToIndex = {} self._nonogram = nonogram self._idToIndex[-1] = -1 self._idToIndex[0] = 0 self.row = [[self.__getIndex(x) for x in r] for r in nonogram.rows()] self.column = [[self.__getIndex(x) for x in c] for c in nonogram.columns()] y_size, x_size = self.shape() self._sol = Solution(shape=(x_size, y_size)) self.matrix = Matrix(x=x_size, y=y_size, default=SolutionCell()) def __getIndex(self, value): self._uid = self._uid + 1 index = LayoutIndex(value) self._idToIndex[index.id()] = index return index def index(self, uid): return self._idToIndex[int(uid)] def shape(self): return (len(self.column), len(self.row)) def solution(self): return self._sol def row_layout(self, i): return self.row[i] def column_layout(self, i): return self.column[i] def row_lineup(self, i): return [x.v[self.ROW] for x in self.matrix.row(i)] def col_lineup(self, i): return [x.v[self.COL] for x in self.matrix.column(i)] def set_row(self, i, j, item): self.matrix.row(i)[j][self.ROW] = item self._sol.item(i, j).v = item.color() def set_col(self, i, j, item): self.matrix.col(i)[self.COL] = item self._sol.item(j, i).v = item.color()
class Solution(SudokuDescr): def __init__(self, descr=None): SudokuDescr.__init__(self, matrix=descr.matrix) self.steps = [] # ((x, y), value) x, y = self.matrix.shape self.probability = Matrix(x=x, y=y, default_func=lambda ix, iy: Probability(self.values())) self.pending = [] # (x, y), value self.random = [] indexes = set() for init in self.matrix: if init.v != 0: indexes.add(init.index()) self.add_step(init.index(), init.v) new_pending = [] for i in self.pending: if not i[0] in indexes: new_pending.append(i) self.pending = new_pending def probability_line(self, index): return [ SolverMethod.belonged_box(index, self.probability, self.box_shape()), self.probability.row(index[1]), self.probability.column(index[0]) ] def add_step(self, index, value): lines = self.probability_line(index) for l in lines: for i in l: if i.index() != index and i.v.erase(value, len(self.steps)): self.add_pending(i.index(), i.v.value()) self.probability.item_i(index).v.set(value, len(self.steps)) self.steps.append((index, value)) self.matrix.item_i(index).v = value def add_pending(self, index, value): self.pending.append((index, value)) def add_random_choice(self, index, values): vs = copy(values) v = vs.pop() self.random.append((index, vs, len(self.steps))) self.add_step(index, v) def rollback_random(self): # revert to 0 in matrix r = self.random.pop() while not r[1]: r = self.random.pop() rev = r[2] while rev != len(self.steps): s = self.steps.pop() self.matrix.item_i(s[0]).v = 0 for item in self.probability: item.v.rollback(rev) self.pending = [] self.add_random_choice(r[0], r[1]) def process_pending(self): while self.pending: item = self.pending.pop() self.add_step(item[0], item[1]) def is_done(self): x, y = self.matrix.shape return x*y == len(self.steps)