Documented constraints.diagonal test more better.
[pseudoku.git] / pseudoku / grid / constraints.py
index 91f8287..e1ea667 100644 (file)
@@ -7,6 +7,11 @@ class Constraint(object):
 
     ### Accessors
 
+    # True iff a constraint consists of a straight line of cells.  Used to
+    # quickly skip over pairs of constraints that cannot possibly have more
+    # than one cell in common.
+    is_linear = False
+
     # NOTE: _cells is a list of refs; _grid is a ref
     # XXX document this
     cells = property(lambda self: [ x() for x in self._cells ])
@@ -28,7 +33,15 @@ class Constraint(object):
         return possible_cells
 
     def resolve_uniques(self):
-        for value in xrange(self.grid._size):
+        """Searches for values that can only appear in one cell, and sets them
+        appropriately.
+
+        Returns the number of cell changes.
+        """
+
+        cell_changes = 0
+
+        for value in xrange(self.grid.size):
             # XXX cache values that are taken care of
             possible_cells = self.find_value(value)
 
@@ -43,16 +56,18 @@ class Constraint(object):
                 continue
 
             # Only cell in the group that can be value
-            target_cell.set(value)
+            cell_changes += target_cell.set(value)
+
+        return cell_changes
 
 
 class Box(Constraint):
     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 __init__(self, grid, position):
@@ -60,32 +75,38 @@ class Box(Constraint):
         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
+        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):
+    is_linear = True
+
     def __init__(self, grid, position):
         self._grid = ref(grid)
         self._pos = position
 
         self._cells = []
-        for col in xrange(self.grid._size):
+        for col in xrange(self.grid.size):
             self._cells.append(ref(self.grid.cell(self._pos, col)))
 
 class Column(Constraint):
+    is_linear = True
+
     def __init__(self, grid, position):
         self._grid = ref(grid)
         self._pos = position
 
         self._cells = []
-        for row in xrange(self.grid._size):
+        for row in xrange(self.grid.size):
             self._cells.append(ref(self.grid.cell(row, self._pos)))
 
 class Diagonal(Constraint):
+    is_linear = True
+
     def __init__(self, grid, direction='down', offset=0):
         self._grid = ref(grid)
         self._direction = direction