A Longer View
Hello, loves! Tout le monde déteste l’IA.
Having made my point about refactoring, I think we need a longer view … and a longer view. Just some planning and a couple of pictures.
- The Point
- The point of this long multi-commit refactoring sequence was: odds are that we can always improve our design in small steps over time. This approach may help us avoid the long delays and high risks of efforts to “rewrite” things. The extent to which you agree with this point, and to take advantage of it, is entirely up to you. I’m just over here doin’ stuff.
- A Longer View
- I have no intention of turning this Dungeon program into an actual game, butI do want to have it be credible that it could be turned into an actual game, in that all the key aspects of how to make it playable are solved, leaving no big problems to be solved, just lots of work all of which is clearly readily able to be done.
-
With that in mind, let’s list some of the key issues that we’d have to resolve if this were to be a real game, and pick one to work on. And, in taking that longer view of the future, we’re going to realize that we need a longer view of the dungeon.
Game Needs
I see a few things that we’d need to make a decent game. I think we need encounters with dungeon creatures, puzzles to solve, and some kind of scoring system, perhaps as simple as an accumulation of treasures. But the old Colossal Cave game comes to mind, There was a system of points that one would collect, but no clues about how to get the points. You had to get the bird into the cage; you had to use the bird to scare the snake; you had to see yourself in the mirror; you had to get your stuff back from the pirate; and, in the version I edited, you had to ignore the cute kitten entirely. If you interacted with the kitten in any way, you lost one point. People hated me for that.
I think that some points-bearing puzzles would be nice to have, so let’s put that on the list. Maybe you have to create a bridge or drain a swamp or solve a maze.
We should have encounters with “intelligent” dungeon denizens. Perhaps some steal from us and we have to get them to give back our stuff, or find where they hide it. Perhaps some ask us to find something and bring it to them, and they award us with something good, or something we need to progress. So we’ll need to devise a moderately capable interaction system, where the NPCs have enough memory and “intelligence” to respond usefully.
I think we’ll want some special room layouts. Our current maps, as you’ll notice below, always include a roundish room in the center, with a diamond room in the middle of that. That might represent a boss room, or a special treasure room that you can only open if you’ve solved the rest of the level, and so on. We’ll probably have some special generators to do different layouts of the same idea, a room within a room.
I suspect we may need more robust lighting than we now have, perhaps including areas that do not illuminate so readily, or even dark areas.
We need doors. And doors need ways to be opened. Some use keys. (In some sense, they all use keys, it’s just that sometimes the key is explosive in nature.) And that leads to an interesting problem that I think we’ll work on very soon.
Allocating Content
Suppose there are two sections of the dungeon separated by a “door”. There is some “key” to opening the door, whether an object that Dot must find, or an NPC she must induce to open the door for her. We need to allocate content in the dungeon such that Dot and the key are on the same side of the door. If they were not, Dot could never open the door.
Our dungeon is essentially random, and I think we want to keep it that way. As things stand, we create however many rooms we intend to create, and then we ensure that they are connected. That process discovers “suites”, sets of rooms that are already connected, and then tries to connect the suites. That code is fairly robust, but we don’t really know if it could ever fail. My guess is that it cannot. If it can, we’ll make one that cannot fail.
An interesting approach, p-baked for p much less than 1/2, might be to create rooms, or maybe discrete suites, and populate them with puzzles and solutions for those puzzles, each suite containing enough to solve all those puzzles. One puzzle might be how to exit this suite. Then we connect those suites and populate them with puzzles and solutions for exiting. Repeat. With care, we might be able to ensure that you’d have to explore the whole dungeon to find everything but that you could never be trapped away from something you needed.
A scheme like this will probably require us to change dungeon layout and population a bit. That’s OK, we don’t really have a current scheme, we just have a batch of code in main that creates a connected dungeon. I think that instead, we’ll want to create a bit, populate a bit, create or connect some more, etc.
To do that, I think we’ll need some work on the Maker side of this project, the tools that we use to build the Made side, the actual game. And in particular, I think we’ll want …
A Longer View
As things stand now, the display shows a small fraction of the dungeon, which is all that will fit into a square-ish window on my screen at a size that lets me see the rooms and walls and treasures reasonably well. There is no built-in way to see the whole dungeon, although it is easy to do. It goes like this:
class DungeonView(arcade.View):
def __init__(self, dungeon, pub_sub, keyed_sprites):
if arcade.window_commands._window:
super().__init__()
self.cameras = Cameras(self, dungeon.max_x, dungeon.max_y, zoom=4)
self.dungeon = dungeon
self.pub_sub = pub_sub
self.keys = KeyPress(self, self.dungeon, self.pub_sub)
self.keyed_sprites = keyed_sprites
self.subscribe(self.dungeon, self.pub_sub)
If I change that 4 to a 1 in the zoom=4, and cause everything to init to visible=True, we can see the whole dungeon:

And I think that if we were to comment out some of the dungeon cleanup, we could see what a map looks like before it’s all connected up:

Maker Tools
To get that disconnected map, I disabled a couple of lines here:
class DungeonLayout:(self):
# self.ensure_connected()
# self.make_passages()
self.make_borders()
No real tools but already I can see some things that I like. We have some single rooms, but also a group of four rooms that are adjacent, three groups of two, and one group of three. That’s probably fairly typical given the current ad hoc room generation. It looks to me as if we could do something good with a layout like this.
So. Maker Tools. Here are some ideas:
Maybe we want an ability to manually zoom the screen, although just running at zoom = 1 seems nearly good enough for working if not for playing. For younger eyes, it’s probably almost OK for playing.
I’d like to have the ability to put pause-points in the current code. For example, looking at the islands above, I’d like to then be able to run one step of the suite-finding and connecting code, to see what it does. Then another, and so on. I want that for at least two reasons: to see different layouts and make decisions about how puzzles and solutions could be allocated; and then when those decisions are put into code, to observe what the code’s decisions look like in the game world, to assess whether they’re good enough.
And here is an interesting one: if we’re going to see the dungeon as it is partially built, the current DungeonViewMaker won’t quite do. Right now, it builds essentially all the tiles and contents and sets the view running on them. If we’re going to watch things grow, we’ll need to be adding sprites and such dynamically.
My initial reaction to realizing this was “Oh no, this may make the whole refactoring we just did a bad idea”. But then I realized, no, actually, it is likely to show that it was a good idea, because now the view is separate, and if we have a maker that works in phases or dynamically, the View won’t have to change. All we really need to do, I think, is to update the KeyedSpriteList properly, and the View will just blithely go along. Similarly, if new content is placed in the layout, it’ll be discovered the next time Dot walks into it.
Needless to say, there’s work to be done. Let’s try an experiment.
Those two commented-out lines. Let’s have a new keystroke that executes them while the view is open, just to see what happens. I expect nothing good, we might have to do just a bit more than that. Let’s find out.
Doesn’t work. It is possible that things were generated OK, but nothing displays because we need some kind of incremental update. I tried calling a DungeonViewMaker and grabbing its keyed_sprites to replace the existing ones, but then the border creation goes berserk for some reason that I don’t instantly see.
I did find a hack that lets my D command draw the paths between the rooms. There are issues in figuring out the border cells and passages. The present code for those assumes that the dungeon is not going to be extended after they run. I’m not sure at this writing how deeply that assumption runs.
Point being we need some maker tooling here, to give us a more step-by-step visual understanding of the dungeon structure as it is being constructed.
The design will have to be improved to allow for that. Fun!
I’ll leave my hacked code in the IDE for now, to review it next time, then we’ll probably throw most of it away and work out something better.