Removed distinction between Row/Box/Column.
authorEevee <ferrox@veekun.com>
Fri, 19 Dec 2008 09:35:16 +0000 (01:35 -0800)
committerEevee <ferrox@veekun.com>
Fri, 19 Dec 2008 09:35:16 +0000 (01:35 -0800)
CellConstraints now remember which cells they actually own, rather than
generating a list on the fly.
Grids are largely apathetic towards which constraints they actually have once
they exist.
Also swapped out proxies for ref()s and gave CellConstraint some real
properties to get around the ugliness of that.

pseudoku/grid/__init__.py
pseudoku/grid/cellgroup.py

index ce7a701..e91a1bd 100644 (file)
@@ -35,41 +35,21 @@ class Cell(object):
         return None
     value = property(_get_value)
 
-    def _get_row(self):
-        """Returns the Row object associated with this cell."""
-        return self._grid._rows[self._row]
-    row = property(_get_row)
-
-    def _get_column(self):
-        """Returns the Column object associated with this cell."""
-        return self._grid._columns[self._col]
-    column = property(_get_column)
-
-    def _get_box(self):
-        """Returns the Box object associated with this cell."""
-        # Some actual math required here!
-        # Row 0..2 -> box 0..2
-        # Col 0..2 -> box 0, 3, 6 (box col 0)
-        box_row = self._row // self._grid._box_height
-        box_col = self._col // self._grid._box_width
-        box_idx = box_row * self._grid._box_height + box_col
-        return self._grid._boxes[box_idx]
-    box = property(_get_box)
-
     def _get_constraints(self):
-        return [ self.row, self.column, self.box ]
+        return self._constraints
     constraints = property(_get_constraints)
 
-    def _get_groups(self):
-        return self._groups
-
     def __init__(self, grid, row, column):
         self._grid = proxy(grid)
         self._row = row
         self._col = column
         self._values = range(self._grid.size)
+        self._constraints = []
         self._normalized = False
 
+    def add_constraint(self, constraint):
+        self._constraints.append(constraint)
+
     def set(self, value, normalize=True):
         """Sets the value of this cell.  If `normalize` is True or omitted, the
         grid will be updated accordingly.
@@ -99,8 +79,8 @@ class Cell(object):
             return
 
         # Elimination time
-        for group in self.constraints:
-            for cell in group.cells:
+        for constraint in self.constraints:
+            for cell in constraint.cells:
                 if cell == self:
                     continue
                 cell.eliminate(self.value)
@@ -177,7 +157,7 @@ class Grid(object):
     size = property(_get_size)
 
     def _get_constraints(self):
-        return self._rows + self._columns + self._boxes
+        return self._constraints
     constraints = property(_get_constraints)
 
     ### Constructors
@@ -190,16 +170,15 @@ class Grid(object):
         self._box_width = box_width
         self._size = box_height * box_width
 
-        self._rows = [Row(self, i) for i in xrange(self._size)]
-        self._columns = [Column(self, i) for i in xrange(self._size)]
-        self._boxes = [Box(self, i) for i in xrange(self._size)]
-
         self._cells = range(self._size ** 2)
         for row in xrange(self._size):
             for col in xrange(self._size):
                 self._cells[self._cellidx(row, col)] \
                     = Cell(self, row, col)
 
+        self._constraints = []
+        self.add_default_constraints()
+
     @classmethod
     def from_matrix(cls, rows, box_height=None, box_width=None):
         """Creates and returns a grid read from a list of lists."""
@@ -259,6 +238,21 @@ class Grid(object):
 
         return self
 
+    ### Constraints
+
+    def add_constraint(self, constraint):
+        self._constraints.append(constraint)
+        for cell in constraint.cells:
+            cell.add_constraint(constraint)
+
+    def add_default_constraints(self):
+        for i in xrange(self._size):
+            self.add_constraint(Row(self, i))
+            self.add_constraint(Column(self, i))
+            self.add_constraint(Box(self, i))
+
+        return
+
     ### Inspectors
 
     def cell(self, row, column):
index 8ff948e..374bd20 100644 (file)
@@ -1,16 +1,19 @@
 from __future__ import division
 
-from weakref import proxy
+from weakref import ref
 
 class CellConstraint(object):
     """Represents any group of cells in a grid that cannot repeat a digit."""
 
     ### Accessors
 
-    cells = []
+    # 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__
+    # XXX inherited __init__ to init _grid/_cells
 
     def find_value(self, value):
         """Returns the cells that can be a specific value."""
@@ -25,7 +28,7 @@ class CellConstraint(object):
         return possible_cells
 
     def resolve_uniques(self):
-        for value in xrange(self._grid._size):
+        for value in xrange(self.grid._size):
             # XXX cache values that are taken care of
             possible_cells = self.find_value(value)
 
@@ -45,52 +48,39 @@ class CellConstraint(object):
 
 class Box(CellConstraint):
     def _get_box_row(self):
-        return self._pos // self._grid._box_width
+        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
+        return self._pos % self.grid._box_height
     box_column = property(_get_box_column)
 
-    def _get_cells(self):
-        # XXX generator + docstring
-        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
-                cells.append(self._grid.cell(cell_row, cell_col))
-        return cells
-    cells = property(_get_cells)
-
     def __init__(self, grid, position):
-        self._grid = proxy(grid)
+        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(CellConstraint):
-    def _get_cells(self):
-        # XXX generator + docstring
-        cells = []
-        for col in xrange(self._grid._size):
-            cells.append(self._grid.cell(self._pos, col))
-        return cells
-    cells = property(_get_cells)
 
+class Row(CellConstraint):
     def __init__(self, grid, position):
-        self._grid = proxy(grid)
+        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(CellConstraint):
-    def _get_cells(self):
-        # XXX generator + docstring
-        cells = []
-        for row in xrange(self._grid._size):
-            cells.append(self._grid.cell(row, self._pos))
-        return cells
-    cells = property(_get_cells)
-
     def __init__(self, grid, position):
-        self._grid = proxy(grid)
+        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)))