Hello, loves!

I have a bit of time where I can’t concentrate deeply but can probably do some easy things. A new class reduces DungeonLayout.

Let’s see what we can find that might be useful. A bit of mess reduction.

Here’s the code that turns a picture of a map into cells:

class DungeonLayout:
# probably should be separate object.
    def add_rooms_from_map(self, string_map):
        d = self.string_map_to_dictionary(string_map)
        self.add_from_dictionary(d)

    @staticmethod
    def string_map_to_dictionary(string_map):
        string_map = textwrap.dedent(string_map)
        strings = string_map.split('\n')
        strings = [string for string in strings if string]
        room_cells = dict()
        for y, line in enumerate(strings):
            for x, char in enumerate(line):
                if char != '.':
                    if not char in room_cells:
                        room_cells[char] = []
                    room_cells[char].append((x, y))
        return room_cells

    def add_from_dictionary(self, name_to_xy):
        for name, tuples in name_to_xy.items():
            cells = [ Cell(x,y) for x,y in tuples ]
            self.add_room(Room(cells, name))

Like the comment says, that should probably be its own object. The static method is a clear signal that it doesn’t need to be in the layout, although as written the add_from does. What is it to be called? It makes rooms from a map and adds them to whoever asks. I think we’ll have it generate the rooms, most likely.

No, it makes rooms from a string map. I think it is a StringMap whose input is a string. We’ll rename it as needed. As written, it doesn’t declare the layout. We use it only in tests, like this:

    def test_long_path_to_nearby_cell(self):
        layout = DungeonLayout(5, 3)
        map = '''
        111..
        ..1..
        111..
        '''
        layout.add_rooms_from_map(map)
        ...

I think this needs to be a factory object. Let’s just repurpose that test right there.

    def test_long_path_to_nearby_cell(self):
        map = '''
        111..
        ..1..
        111..
        '''
        layout = TextLayout(map).layout
        assert layout.max_x == 5
        assert layout.max_y == 3
        origin = Cell(0, 2)
        target = Cell(0,0)
        results = dict()
        for cell, distance in (Flooder(layout=layout, origin=origin)
                .in_any_room()
                .flood()):
            results[cell] = distance
        assert origin.manhattan_distance(target) == 2
        assert results[target] == 6

We’ll add the check that the layout is the right size as well.

Now to do it. It’s mostly just moving the code into a class:

class TextLayout:
    def __init__(self, text):
        self.max_x = 0
        self.max_y = 0
        map = self.string_map_to_dictionary(text)
        self.layout = DungeonLayout(self.max_x, self.max_y)
        self.add_from_dictionary(map)

    def string_map_to_dictionary(self, string_map):
        string_map = textwrap.dedent(string_map)
        strings = string_map.split('\n')
        strings = [string for string in strings if string]
        self.max_y = len(strings)
        self.max_x = len(strings[0])
        room_cells = dict()
        for y, line in enumerate(strings):
            for x, char in enumerate(line):
                if char != '.':
                    if not char in room_cells:
                        room_cells[char] = []
                    room_cells[char].append((x, y))
        return room_cells

    def add_from_dictionary(self, name_to_xy):
        for name, tuples in name_to_xy.items():
            cells = [ Cell(x,y) for x,y in tuples ]
            self.layout.add_room(Room(cells, name))

Now use it for all the callers of the one in DungeonLayout … and done … remove the old code, commit.

Summary

There’s about ten percent of the length of DungeonLayout moved off to the side. Making a dungeon from a text map is now nicely isolated into a class that just does that. Could have done a forwarding method in DungeonLayout but changing the tests was easy enough.

Small changes toward better. This is the way. See you next time!