+from __future__ import division
+
+from weakref import proxy
+
+class CellGroup(object):
+ """Represents any group of cells in a grid."""
+
+ ### Accessors
+
+ cells = []
+
+ ### Methods
+ # XXX inherited __init__
+
+ 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(CellGroup):
+ 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 _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._pos = position
+
+
+class Row(CellGroup):
+ 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)
+
+ def __init__(self, grid, position):
+ self._grid = proxy(grid)
+ self._pos = position
+
+
+class Column(CellGroup):
+ 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._pos = position