Hello, loves!

This morning, we’ll try to put stepping into the dungeon creation. Tout le monde déteste l’IA.

The basic idea here is to do just minimal setup in main, building a table that defines the dungeon build process, and then step through that table one bit at a time, so that we can watch the dungeon being built. My purpose, other than simply entertaining myself, is to give me a better visual understanding of things, in aid of allocating items into the dungeon. I am particularly interested in ensuring that Dot can reach the solution to any given puzzle without having already solved it. Avoid key on the wrong side of the door kind of thing.

Yesterday, I got main to build a table and execute it. Today we need to get it in the hands of our KeyPress object, specifically, for now, its response to letter D. Why D? I don’t remember.

Here’s main as it stands now:

def main():
    # random.seed(35)
    # random.seed(234)
    layout = DungeonLayout(64, 56)
    dungeon = Dungeon(layout)
    screen_width = 16*dungeon.max_x
    screen_height = 16*dungeon.max_y
    arcade.Window(screen_width, screen_height, 'Caveat Emptor')
    dungeon.run()
    for m in make_build_table():
        m(dungeon, layout)
    view = DungeonViewMaker(dungeon).view
    view.run()
    # dungeon.add_passage(Cell(32,30), Cell(33,30))


def make_build_table():
    return [
        make_diamond_in_round_room,
    make_a_diamond_room,
    make_a_round_room,
    make_random_rooms,
    finish,
    populate,
    add_content,
    ]

The functions in that table all take two parameters, dungeon and layout, as we can see from how they are called in the loop in main.

Let’s begin by change things so that ‘main’ just gets things going and does no building. Then we’ll change KeyPress to fetch the table and set up to run it. In other words, we’ll default to the manual build mode.

class KeyPress:
    def __init__(self, view, dungeon, pub_sub):
        self.view = view
        self.dungeon = dungeon
        self.pub_sub = pub_sub
        self.key_lock = None
        self.build_table = make_build_table()
        self.build_item = 0

And in D:

        elif symbol == arcade.key.D:
            from dungeon_view_maker import DungeonViewMaker
            if self.build_item >= len(self.build_table): return
            action = self.build_table[self.build_item]
            self.build_item += 1
            action(self.dungeon, self.dungeon.layout)
            maker = DungeonViewMaker(self.dungeon)
            self.view.keyed_sprites = maker.keyed_sprites

You’re not going to believe this, but once I got the imports isolated to avoid a recursive init, this worked right out of the box, with one oddity.

OK, two oddities. The first one that I noticed was that the initial game blurb came out twice. The second one is that we seem not to be creating the two appearing content items that are supposed to show up when Dot steps on those platform squares.

I’m going to set main back to do the work and see if things work there. The announcements come out twice, but the appearing objects work correctly.

Reflection

My overall reaction is to be pleased but not surprised that it works as well as it does, because yesterday’s steps worked (except that I didn’t notice the dual message). I am wishing that I could have better testing for what’s going on here, but the fact that it all has to work as the game runs leaves me not knowing - yet - how to test it better.

Some hypotheses about the appearing items: Perhaps the pub-sub is messed up so that when the button speaks, the content does not hear it. That could happen if the pub-sub got replaced at the wrong time. Or perhaps the button’s aren’t speaking.

Let’s check that out: we can put a print in the button’s code. That check says that the item does issue its message. So the message was not received.

Since the button and content are added essentially in the same go, I don’t see how the subscription could be lost.

At my peril I’ll do a bit more printing.

I got lucky and discovered that the Content.run method that initializes content is never being executed. Most content doesn’t care but the appearing ones do.

If I add one line to the add_content in main it all works:

    layout.run(dungeon.pub_sub)

That’s not really good, though. We might have many methods that add content and they might even call back and forth.

What should really happen? Well, ideally, we would do the run thing after all the other steps of building. We could build that into the D command, or include it as the unconditional last item in the build_table.

I find that ‘main’ is calling dungeon.run, and also when we start the view, it calls it. It is that method that is issuing the blurb, by the way, which explains why we get it twice.

I think we can probably change things so that when the view is created it doesn’t call dungeon.run, and call it after the build sequence is complete.

I’m working on a spike by now anyway, so let’s try it.

class DungeonView:
    def run(self):
        # self.dungeon.run()
        # self.illuminate_around_dot()
        self.window.show_view(self)
        arcade.run()

Change ‘main’ not to call dungeon.run. And in D:

class KeyPress:
        elif symbol == arcade.key.D:
            from dungeon_view_maker import DungeonViewMaker
            if self.build_item >= len(self.build_table): return
            action = self.build_table[self.build_item]
            self.build_item += 1
            action(self.dungeon, self.dungeon.layout)
            maker = DungeonViewMaker(self.dungeon)
            self.view.keyed_sprites = maker.keyed_sprites
            if self.build_item == len(self.build_table):
                self.dungeon.run()

Whether this works or not, I’m going to stop. I’ve only been working a little more than an hour, but I’ve bashed and hammered and done enough damage. It’s time for a break.

Try the code. It works and appears to be exactly right.

Perfect time for a break. No commit, but we can review the code next time and decide how to proceed. I think we’ll conclude that it makes sense almost as it is. But we’ll see … next time!