self.normalize()
- def __str__(self):
- """Stringification for pretty-printing."""
- if self.value != None:
- return symbols[self.value]
-
- return '.'
-
-
class Grid(object):
"""Represents a Sudoku grid."""
"""Normalizes every cell in the grid."""
for cell in self._cells:
cell.normalize()
-
-
- def __str__(self):
- """Pretty-printing."""
- divider = '+'
- for box in xrange(self._box_height):
- for col in xrange(self._box_width):
- divider += '-'
- divider += '+'
-
- res = ''
- for row in xrange(self._size):
- if row % self._box_height == 0:
- res += divider
- res += "\n"
-
- for col in xrange(self._size):
- if col % self._box_width == 0:
- res += '|'
- res += str(self.cell(row, col))
-
- res += '|'
- res += "\n"
-
- res += divider
- res += "\n"
-
- return res
--- /dev/null
+from ..grid import symbols
+
+class GridRenderer(object):
+ """Class that renders a grid in some human-consumable form.
+
+ This base class's methods result in a flat string of symbols, but it's easy
+ to create a more useful rendering by just overriding a few methods.
+ """
+
+ def render_grid(self, grid):
+ """Renders the entire grid. Code on the outside probably only needs to
+ call this.
+
+ Returns a string.
+ """
+ parts = []
+
+ parts.append(self.before_grid(grid))
+ for idx, row in enumerate(grid._rows):
+ if idx and idx % grid._box_height == 0:
+ parts.append(self.inside_grid(grid))
+ parts.append(self.render_row(row))
+ parts.append(self.after_grid(grid))
+
+ return ''.join(parts)
+
+ def render_row(self, row):
+ """Renders a single row."""
+ parts = []
+
+ parts.append(self.before_row(row))
+ for idx, cell in enumerate(row.cells):
+ if idx and idx % row._grid._box_width == 0:
+ parts.append(self.inside_row(row))
+ parts.extend(self.render_cell(cell))
+ parts.append(self.after_row(row))
+
+ return ''.join(parts)
+
+ def render_cell(self, cell):
+ """Renders a single cell."""
+ return ''.join([
+ self.before_cell(cell),
+ self.inside_cell(cell),
+ self.after_cell(cell),
+ ])
+
+
+ def before_grid(self, grid):
+ """Content prepended before the entire grid."""
+ return self.inside_grid(grid)
+
+ def inside_grid(self, grid):
+ """Content inserted within the grid, between boxes."""
+ return ''
+
+ def after_grid(self, grid):
+ """Content appended after the entire grid."""
+ return self.inside_grid(grid)
+
+
+ def before_row(self, row):
+ """Content prepended before each row."""
+ return self.inside_row(row)
+
+ def inside_row(self, row):
+ """Content inserted within each row, between boxes."""
+ return ''
+
+ def after_row(self, row):
+ """Content appended after each row.
+
+ Note that newlines are not assumed; you must provide one if you want
+ one included in the rendering.
+ """
+
+ return self.inside_row(row)
+
+
+ def before_cell(self, cell):
+ """Content prepended before each cell in a row."""
+ return ''
+
+ def inside_cell(self, cell):
+ """Content used to represent the actual cell value."""
+ if cell.value:
+ return symbols[cell.value]
+ else:
+ return '.'
+
+ def after_cell(self, cell):
+ """Content appended after each row in a cell."""
+ return ''
+
--- /dev/null
+from . import GridRenderer
+from ..grid import symbols
+
+class LineGridRenderer(GridRenderer):
+ """Renders a grid into a flat string, as puzzles are often presented in
+ plaintext collections.
+ """
+ pass
+
+
+class SquareGridRenderer(GridRenderer):
+ """Renders a grid as a square of characters."""
+
+ def after_row(self, row, new_box=False):
+ return '\n'
+
+
+class AsciiArtGridRenderer(SquareGridRenderer):
+ """Renders a questionably-pretty ASCII art drawing of a grid, with dividers
+ between rows and columns.
+ """
+
+ def inside_grid(self, grid):
+ box_header = '+' + '-' * grid._box_width
+ return box_header * grid._box_height + '+\n'
+
+ def inside_row(self, row):
+ return '|'
+
+ def after_row(self, row):
+ return '|\n'
+
+ def inside_cell(self, cell):
+ if cell.value:
+ return symbols[cell.value]
+ else:
+ return ' '