The Repo on GitHub

I have a bit of time, and I’m going back in.

I’m not sure what I’ll do yet. I might even get someone to join me. First off, I want to think about how the Bot might decide, regarding scent.

I’ll assume, that like Vision, you always get a scent when you get info back about your previous action, so any state can find out the total block-scent where it is. I’m not sure if we should get the scent of the cell in front of us, or the cell we’re standing on. Probably won’t matter.

If we are about to pick up a block, we want to tend to pick up if the pile is small, i.e. the scent is low. For dropping, we want to tend to drop if the scent is large. At first, there will likely be mostly singleton blocks, and since we only pick up, they’ll be right in front of us. If we center on that cell, a single block will have scent 4, a block adjacent to another might have scent of 7, 6, maybe 5. Dropping off, we require an open cell next to a block, so the scent of the open cell is at least 3.

I’m starting to suspect that we will want to adjust the scent on picking up downward, and on dropping, upward.

As a starting idea, let’s just pick up on less-than one value of scent and drop on greater than another. We’ll fiddle and see what happens.

So we want a scent to come back on every turn, and for that value to be stored in Knowledge.

I’m going to spike this rather than test it.

And GeePaw shows up. Life is good.

Not So Contemporaneous

I just can’t pair, talk, program, and type articles all at the same time. Not enough CPU cores, I guess. Anyway, I took him through what I was thinking, and my thinking that the world would collect a scent at the same time as it collects a Vision, and that the scent would be sent to the Bot, which would forward it to the Knowledge, where it would be used in the can_drop and can_take decisions.

So we wrote some tests and made some code work:

    def test_we_get_scent(self):
        world = World(10, 10)
        block = Block(5, 5)
        world.add(block)
        bot = Bot(4, 6)
        world.add(bot)
        world.step(bot)
        assert bot._knowledge.scent == 3

This test just tests the trip form World to knowledge, and it drove out a few little methods:

class World:
    def step(self, bot):
        location = self.bots_next_location(bot)
        self.map.attempt_move(bot.id, location)
        self.set_bot_vision(bot)
        self.set_bot_scent(bot)

    def set_bot_vision(self, bot):
        bot.vision = self.map.vision_at(bot.location)

    def set_bot_scent(self, bot):
        bot.scent = self.map.scent_at(bot.location)

class Bot:
    @property
    def scent(self):
        return self._knowledge.scent

    @scent.setter
    def scent(self, scent):
        self._knowledge.scent = scent

Now that we have it, we wanted to use it to control drop and take. We started with drop, and added a couple of lines to a couple of tests:

    def test_can_drop(self):
        location = Location(10, 10)
        direction = Direction.NORTH
        knowledge = Knowledge(location, direction)
        knowledge.vision = [('B', 10, 9)]
        knowledge.scent = Knowledge.drop_threshold  # <===
        assert not knowledge.can_drop
        knowledge.vision = [('B', 9, 9)]
        assert knowledge.can_drop
        knowledge.vision = [('B', 11, 9)]
        assert knowledge.can_drop


    def test_knowledge_drop_decision_low_scent(self):
        location = Location(5, 5)
        direction = Direction.NORTH
        knowledge = Knowledge(location, direction)
        vision_list = [('R', 5, 5), ('B', 4, 4)]
        knowledge.vision = vision_list
        knowledge.scent = Knowledge.drop_threshold - 1
        assert not knowledge.can_drop

And we updated can_drop:

class Knowledge:
    drop_threshold = 4

    @property
    def can_drop(self):
        is_scent_ok = self.scent >= self.drop_threshold
        return is_scent_ok and self.vision.match_forward_and_one_side('_', 'B')

And we were green and we wanted to see what the game does with just the new drop rule, which is that we have to have at least 4 scent notes in the area before we drop. And when we run the game for a while, we get this kind of picture:

a few big clumps rather than many small

The picture gets down to two clumps quite often, then the bots break them up a bit, then put them back together.

We were amazed, gobsmacked, surprised, and astounded that this simple change, the need to scent 4 or more scent points, made this much difference. We haven’t even changed how they decide to pick things up!

It’s truly fascinating what complex behavior we can get from such ridiculously simple rules. We’ll be back, tuning this, no doubt, but it’s quite wonderful as it stands.

Much fun! See you next time!