GitHub Repo

Let’s keep banging away at the new Item. We’ll make them a bit smarter.

I do think I’ll do the Items collection. Why? Because once I have it, I’m sure it’ll find ways to be useful, and the more I do without it, the more I’ll be futzing with that vanilla collection. For now, it can just be a simple cover, holding the collection, but I am not sure that I want it to offer the subscripting notation that we’re using now:

    fun item(thing: String) {
        contents[thing] = Item(thing)
    }

Another thing to do right out of the box, though, would be to expand that method right there to allow for details, in the style of the room. We’ll copy the implementation of room:

    fun room(name: String, details: Room.()->Unit) : Room {
        val room = Room(name)
        rooms.add(room)
        room.details()
        return room
    }

Let’s just do that. We could default the details but let’s not.

    fun item(thing: String, details: Item.()->Unit): Item {
        val item = Item(thing)
        contents[thing] = item
        item.details()
        return item
    }

That’s pretty much by rote. We’ll find compile errors on our calls to item now. They all will just need {} appended.

    val theWorld = world {
        room("spring") {
            desc("spring", "You are at a clear water spring. There is a well house to the east, and a wooded area to the west and south.")
            item("water") {}
            item("bottle") {}
            ...

There were quite a few more. Green. Commit: Room.item now calls a details lambda.

Now let’s see what we might do. Presumably there was some point to adding the details, though we certainly don’t have a test requiring them. Let’s give the item a long and short description, rather as we did for the room.

    @Test
    fun `initial item`() {
        var myRoom = Room("y")
        val world = world {
            myRoom = room("x") {
                item("axe") {
                    desc("an axe", "an ornate axe belonging to the dwarf Bridget Ingridsdotter")
                }
            }
        }
        val item: Item = myRoom.contents["axe"]!!
        assertThat(item.shortDesc).isEqualTo("an axe")
        assertThat(item.longDesc).contains("Bridget Ingridsdotter")
    }

Interesting fact. desc is implemented on Room, and this method seems to be referring to it. I’ll add it to item and hope that the problem goes away. I’m not sure I understand Kotlin’s rules on what it can see, and when.

class Item(val name: String) {
    var shortDesc = name
    var longDesc = name
    fun desc(short: String, long: String) {
        shortDesc = short
        longDesc = long
    }
}

Green. Commit: Item.desc saves long and short description.

Now we might change the inventory and contents displays to use the short description. In Room we have this:

    fun itemString(): String {
        return contents.keys.joinToString(separator = "") {"You find $it.\n"}
    }

Let’s improve that. Do we have a test for it?

We have. It looks like this:

    @Test
    fun `room has contents`() {
        val world = world {
            room("storage") {
                desc("storage room", "large storage room")
                item("broom") {}
                item("broom") {}
                item("water") {}
                item("axe") {}
            }
        }
        val room = world.unsafeRoomNamed("storage")
        assertThat(room.contents).containsKey("broom")
        assertThat(room.contents.size).isEqualTo(3)
        val itemString = room.itemString()
        assertThat(itemString).contains("axe")
        assertThat(itemString).contains("broom")
        assertThat(itemString).contains("water")
    }

We’ll need to add desc clauses to those, but let’s do so. And … I think I’d like to default the long description to the short. I don’t have a test for that yet. But I can force it by simply not providing one above.

    item("broom") {
        desc("a broom")
    }
    item("broom") {
        desc("a broom")
    }
    item("water") {
        desc("some water")
    }
    item("axe") {
        desc("an axe")
    }

IDEA is whining about the missing second parameter, so:

    fun desc(short: String, long: String = short) {
        shortDesc = short
        longDesc = long
    }

I expect this to fail, not seeing the articles: we’ve not changed the itemString method yet. Of course, I didn’t change the asserts yet either. It would help if I were to do that:

    assertThat(itemString).contains("an axe")
    assertThat(itemString).contains("a broom")
    assertThat(itemString).contains("some water")

That should fail nicely:

Expecting:
 <"You find broom.
You find water.
You find axe.
">
to contain:
 <"an axe"> 

And now:

    fun itemString(): String {
        return contents.values.joinToString(separator = "") {"You find ${it.shortDesc}.\n"}
    }

I expect me some green. I get it. Commit: Room items display item short description.

So that’s nice. We must have a test for inventory somewhere. Let’s find it.

Enhanced it is:

    @Test
    fun `can take inventory`() {
        val world = world {
            room("storage") {
                desc("storage room", "large storage room")
                item("broom") {
                    desc("a broom")
                }
            }
        }
        val player = Player(world, "storage")
        var resultString = player.command("take broom")
        assertThat(resultString).isEqualTo("broom taken.\nlarge storage room\n")
        resultString = player.command("inventory")
        assertThat(resultString).isEqualTo("You have a broom.\n\nlarge storage room\n")
    }

Note that I added the desc and ask for “a broom”, not just broom. And this is the change that makes it work:

    private fun showInventory() {
        val values = inventory.values.map { it.shortDesc}
        say( values.joinToString(prefix="You have ", separator=", ", postfix=".\n") )
    }

Green. Commit: Inventory displays shortDesc not name.

I transform to an unintelligible one-liner:

    private fun showInventory() {
        say( inventory.values.joinToString(
        	prefix="You have ", 
        	transform={it.shortDesc}, 
        	separator=", ", 
        	postfix=".\n") )
    }

Green. Commit: tidying?

I’m not sure that converting that to a one-liner counts as tidying, but maybe it does.

Time to sum up:

Summary

We made the item function a full-fledged member of the DSL, and gave it short and long descriptions. We changed the contents display and the inventory display to use the short description. We went in a few commits, though not many, and never broke anything. Everything we did, I think, is covered by tests, though some of it was done after the fact, not before.

Everything is proceeding smoothly. This is telling me that most of our objects are in just about the right place. We have work to do, but we’re getting sell set up to do it. Is it time for the clever water-taking trick? I’m not sure about that.

A pleasant interlude. See you next time!