Hello, loves!

With Content in good enough shape, I think doors can be next on the agenda. (I delete 235 lines from this article.)

Somewhere in the code, the program has at least a vague understanding of the borders between rooms, because we draw walls between adjacent rooms:

dungeon map showing walls between rooms

As things stand, Intrepid Adventurer Dot can walk freely between rooms, but cannot walk into the open space shown as black in the picture above. We need a door scheme, something like this:

Things that look like walls are usually impermeable and cannot be walked through. Certain cells on the border between two rooms are “doors”. There will generally be exactly one door between any two adjacent rooms. A door can have a number of appearances, ranging from an obviously open passageway to something that looks like a door … and even possibly something that looks like a wall. Doors will have at least an open state and a closed state and may have at least two visible appearances associated with state.

As always, expect the unexpected. We’ll probably come up weird door ideas as time passes.

You know what I mean: dungeon doors.

How might we do this?

Darn good question. I think we’d best start by reviewing what the code knows now about borders. I believe but would not swear that all it knows is just enough to put those wall-bearing tiles down in the right places on the floor. Let’s find out.

At this point, I began a long foray into the existing border-related code. I will now be deleting all the code and commentary that I displayed, because it was almost entirely a waste of my time and certainly would be a waste of yours.

235 lines of code and text deleted. We rejoin the show here:

Well, This Is Irritating

All the code reviewed above (and then deleted, along with commentary) does what it was intended to do, namely provide a proper cell texture showing borders and open cells as needed.

But it’s not, as far as I can tell, doing what I’d like to have now. Reviewing it refreshed my recollection a bit, but it’s certainly not worthy of being included in an article, even one as boring as mine often are.

What do we really need? We need, for any room, a set of cells that border another given room. (Or, possibly, something a bit more.)

Maybe that’s not really that hard. It’s probably seriously heavy to compute.

Theory

Let’s think about the thing mathematically, or sort of mathematically.

Consider a Room. It has a collection of cells. The cells can mostly be thought of as a coordinate pair (x,y). Suppose we want all the cells in room A that border on room B.

That set is exactly the cells from A whose manhattan distance from some cell of B is 1.

A given cell of A could be selected more than once, since it could be adjacent to B along one, two, or even three sides. So there could be duplicates if we’re not careful.

The Cell class understands manhattan_distance, so we could easily write the search.

I decide to write a test, including WishfulThinking:

    def test_find_border_cells(self):
        layout = DungeonLayout(64, 56)
        maker = RoomMaker(layout)
        origin = layout.at(32, 28)
        diamond = maker.diamond(number_of_cells=13, origin=origin, name='diamond')
        round = maker.round(radius=5, origin=origin, name='round')
        layout.add_room(diamond)
        layout.add_room(round)
        border_cells = diamond.border_with(round)
        assert len(border_cells) == 8

That’s the layout code that creates the cross room in the round room. I think the border count is correct.

We “just” need a border_with method:

    def border_with(self, room):
        result = set()
        for my_cell in self:
            for other_cell in room:
                if my_cell.manhattan_distance(other_cell) == 1:
                    result.add(my_cell)
        return result

Well, that was easy.

EXPLETIVE DELETED. This is the point where I realized the whole top of this article needed to be deleted. I feel better now.

I want to break, but first I want to try expressing that little method differently. Commit it this way first: new border_with method.

    def border_with(self, room):
        result = (my_cell for my_cell in self
                  for other_cell in room
                  if my_cell.manhattan_distance(other_cell)==1)
        return set(result)

I prefer the comprehension. YMMV. Agree to disagree. Frankly, I just needed to do that to prove to myself that I’m not a complete loser for chasing through all that code that wasn’t that valuable to the morning’s topic.

However: because I’ve done this very simple — albeit somewhat costly — border-finding method, and in the light of the code I reviewed to get here, I have the sense that all that other borders code can probably be simplified, using what we come up with here.

Let’s sum up: I need a break.

Summary

Reviewing the existing border-related code was good for me, just not good for an article. The code might have been more useful than it appears now that it will be, and it might still be useful. Familiarity with what’s going on with borders before doing more work on them just makes sense.

And, at the beginning of the session, I certainly didn’t see the simple notion of how to get the border cells, and I certainly needed to know what Room was about, to know that it sticks around long enough, and has all the cells of the room, even though we currently use it only to build the flooring sprite list.

Something along the way sparked the idea of just computing the border from the cells of a room, compared with the cells of another, and triggered me to recognize that manhattan distance was just the thing.

I like the simple border_with method, but I’m not sure it’s going to be quite what we want. We’ll want matching pairs of cells across the border, and to select one such pair and make the door between them. But it’ll be the same kind of loop or comprehension that’s in border_with. One interesting aspect will be that we want to be sure not to make a door between Room A and Room B, and then another door between Room B and Room A.

Another thing that I picked up while meandering through the old Borders stuff was the notion of a “suite”, which is an ephemeral collection of rooms that are connected, computed during the phase of making sure that the dungeon is fully connected. We might find that to be a good place to compute our new border structure.

Also we might not.

I guess I’m no longer irritated. I certainly don’t regret sparing you the long listings and meandering thoughts: I assure you there was nothing profound there. And reflecting here in the summary has shown me that I did glean value from the review of the code.

But I’m still tired and still want a break. See you next time!