X-Git-Url: http://git.veekun.com/pseudoku.git/blobdiff_plain/bf40f463be2e8809afbaed42abdd00105053a19d..8a045b780490790e8d69f929562a8d4befaf6283:/pseudoku/grid/constraints.py diff --git a/pseudoku/grid/constraints.py b/pseudoku/grid/constraints.py new file mode 100644 index 0000000..91f8287 --- /dev/null +++ b/pseudoku/grid/constraints.py @@ -0,0 +1,111 @@ +from __future__ import division + +from weakref import ref + +class Constraint(object): + """Represents any group of cells in a grid that cannot repeat a digit.""" + + ### Accessors + + # NOTE: _cells is a list of refs; _grid is a ref + # XXX document this + cells = property(lambda self: [ x() for x in self._cells ]) + grid = property(lambda self: self._grid()) + + ### Methods + # XXX inherited __init__ to init _grid/_cells + + def find_value(self, value): + """Returns the cells that can be a specific value.""" + possible_cells = [] + for cell in self.cells: + if value in cell._values: + possible_cells.append(cell) + + if len(possible_cells) == 0: + raise Exception # XXX + + return possible_cells + + def resolve_uniques(self): + for value in xrange(self.grid._size): + # XXX cache values that are taken care of + possible_cells = self.find_value(value) + + if len(possible_cells) > 1: + # Not unique + continue + + target_cell = possible_cells[0] + if target_cell.solved: + # Already seen this + # XXX this is what cache is for + continue + + # Only cell in the group that can be value + target_cell.set(value) + + +class Box(Constraint): + def _get_box_row(self): + return self._pos // self.grid._box_width + box_row = property(_get_box_row) + + def _get_box_column(self): + return self._pos % self.grid._box_height + box_column = property(_get_box_column) + + def __init__(self, grid, position): + self._grid = ref(grid) + self._pos = position + + self._cells = [] + for row in xrange(self.grid._box_height): + for col in xrange(self.grid._box_width): + cell_row = row + self.box_row * self.grid._box_height + cell_col = col + self.box_column * self.grid._box_width + self._cells.append(ref(self.grid.cell(cell_row, cell_col))) + + +class Row(Constraint): + def __init__(self, grid, position): + self._grid = ref(grid) + self._pos = position + + self._cells = [] + for col in xrange(self.grid._size): + self._cells.append(ref(self.grid.cell(self._pos, col))) + +class Column(Constraint): + def __init__(self, grid, position): + self._grid = ref(grid) + self._pos = position + + self._cells = [] + for row in xrange(self.grid._size): + self._cells.append(ref(self.grid.cell(row, self._pos))) + +class Diagonal(Constraint): + def __init__(self, grid, direction='down', offset=0): + self._grid = ref(grid) + self._direction = direction + self._offset = offset + + if direction == 'down': + coords = {'row': 0, 'column': 0} + increment = 1 + elif direction == 'up': + coords = {'row': 0, 'column': grid.size - 1} + increment = -1 + else: + raise Exception # XXX + + # XXX + if offset != 0: + raise NotImplementedError + + self._cells = [] + for i in xrange(self.grid.size): + self._cells.append(ref(self.grid.cell(coords['row'], coords['column']))) + coords['row'] += 1 + coords['column'] += increment