Repository: tmcclintock/donjuan

Issue:
Create the Randomizer class
The `Randomizer` class should handle actually randomizing parts of the `Dungeon`. It should do things like create rooms and hallways, add `Doorspace` objects, and add content to `Cell`s (e.g. lightsources, chests, tokens/actors, whatever).

This is a placeholder issue that can be specified once more of the `Dungeon` class is complete.

Note: the `Randomizer` class should have "seed" as an optional argument. This will allow for re-generating (regenerating?) the same dungeons repeatedly.

Comments:

Patch:
diff --git a/donjuan/__init__.py b/donjuan/__init__.py
index c959a4b..12928b9 100644
--- a/donjuan/__init__.py
+++ b/donjuan/__init__.py
@@ -6,4 +6,5 @@ from .door_space import Archway, Door, DoorSpace, Portcullis
 from .dungeon import Dungeon
 from .face import BareFace, DoorFace, Face, Faces, HexFaces, SquareFaces
 from .grid import Grid, HexGrid, SquareGrid
+from .randomizer import RandomFilled, Randomizer
 from .renderer import BaseRenderer, Renderer
diff --git a/donjuan/randomizer.py b/donjuan/randomizer.py
new file mode 100644
index 0000000..5b50d59
--- /dev/null
+++ b/donjuan/randomizer.py
@@ -0,0 +1,43 @@
+import random
+from typing import Optional
+
+from donjuan import Cell, Grid
+
+
+class Randomizer:
+    """
+    Class for randomizing features of a dungeon.
+    """
+
+    def randomize_cell(self, cell: Cell) -> None:
+        """Randomize properties of the `Cell`"""
+        pass  # pragma: no cover
+
+    def randomize_grid(self, grid: Grid) -> None:
+        """Randomize properties of the `Grid`"""
+        pass  # pragma: no cover
+
+    @classmethod
+    def seed(cls, seed: Optional[int] = None) -> None:
+        """
+        Args:
+            seed (Optional[int]): seed passed to :meth:`random.seed`
+        """
+        random.seed(seed)
+
+
+class RandomFilled(Randomizer):
+    """
+    Randomly set the :attr:`filled` attribute of cells.
+    """
+
+    def randomize_cell(self, cell: Cell) -> None:
+        """Randomly fill the cell with probability 50%"""
+        cell.filled = bool(random.randint(0, 1))
+
+    def randomize_grid(self, grid: Grid) -> None:
+        """Randomly fill all cells of the grid individually"""
+        for i in range(grid.n_rows):
+            for j in range(grid.n_cols):
+                self.randomize_cell(grid.cells[i][j])
+        return
diff --git a/examples/random_fill.py b/examples/random_fill.py
new file mode 100644
index 0000000..44378f3
--- /dev/null
+++ b/examples/random_fill.py
@@ -0,0 +1,22 @@
+import os
+
+import matplotlib as mpl
+
+from donjuan import Dungeon, RandomFilled, Renderer
+
+# Instantiate donjuan objects
+renderer = Renderer()
+dungeon = Dungeon(n_rows=4, n_cols=5)
+rng = RandomFilled()
+rng.randomize_grid(dungeon.grid)
+
+# Render the image
+file_path = "test.png"
+renderer.render(dungeon, file_path)
+
+# Look at it
+mpl.image.imread(file_path)
+mpl.pyplot.show()
+
+# Delete the image from on disk
+os.remove(file_path)


Test patch:
diff --git a/tests/randomizer_test.py b/tests/randomizer_test.py
new file mode 100644
index 0000000..6751161
--- /dev/null
+++ b/tests/randomizer_test.py
@@ -0,0 +1,54 @@
+from unittest import TestCase
+
+from donjuan import HexGrid, RandomFilled, Randomizer, SquareGrid
+
+
+class RandomizerTestCase(TestCase):
+    def setUp(self):
+        self.grid = SquareGrid(n_rows=4, n_cols=5)
+        self.hexgrid = HexGrid(n_rows=4, n_cols=5)
+
+
+class RandomizerTest(RandomizerTestCase):
+    def test_smoke(self):
+        rng = Randomizer()
+        assert rng is not None
+
+    def test_seed_passes(self):
+        Randomizer.seed(0)
+
+
+class RandomFilledTest(RandomizerTestCase):
+    def test_smoke(self):
+        rng = RandomFilled()
+        assert rng is not None
+
+    def test_filled(self):
+        rng = RandomFilled()
+        rng.seed(12345)
+        grid = self.grid
+        for i in range(grid.n_rows):
+            for j in range(grid.n_cols):
+                assert not grid.cells[i][j].filled
+        rng.randomize_grid(grid)
+        # Test that at least one cell became filled
+        for i in range(grid.n_rows):
+            for j in range(grid.n_cols):
+                if grid.cells[i][j].filled:
+                    break
+        assert grid.cells[i][j].filled
+
+    def test_filled_hex(self):
+        rng = RandomFilled()
+        rng.seed(12345)
+        grid = self.hexgrid
+        for i in range(grid.n_rows):
+            for j in range(grid.n_cols):
+                assert not grid.cells[i][j].filled
+        rng.randomize_grid(grid)
+        # Test that at least one cell became filled
+        for i in range(grid.n_rows):
+            for j in range(grid.n_cols):
+                if grid.cells[i][j].filled:
+                    break
+        assert grid.cells[i][j].filled