Up to Main Index                              Up to Journal for June, 2021

                      JOURNAL FOR SUNDAY 13TH JUNE, 2021
______________________________________________________________________________

SUBJECT: New command matcher for WolfMini
   DATE: Sun 13 Jun 17:53:38 BST 2021

Another jolly week of working late into the night hacking away on WolfMini.

I finished the world loader which can now load the original zone files from
WolfMUD proper and link the zones together. I have basic vetoes working after
implementing the Thing.Any field I discussed last time. Although, after using
vetoes for a while this became part of Thing.As :/ However, the Thing.Any
field is now used for aliases and alias qualifiers. I also tweaked, a major
refactoring, the inventories to be map[string]*Thing where the key is the
unique identifier of the item. My current thing now looks like:


  // Thing is used to represent any and all items in the game world.
  type Thing struct {
    Is  isKey               // Bit flags for capabilities/state
    As  map[asKey]string    // Single value for a key
    Any map[anyKey][]string // One or more values for a key
    In  map[string]*Thing   // Item's in a Thing (inventory)
  }


One of the issues I had/have with WolfMUD is the item matcher that tries to
work out which items a player’s command is referring to. In WolfMUD, adopting
the matcher and switching out the simple parser was a pain, it made a mess of
the code for all commands and slowed down the command handling a lot.

A lot of this week has been spent on a new command matcher for WolfMini. I had
some specific goals in mind: it had to be simple, fast, and integrate nicely
with other code.

The new matcher has all of the features of the current WolfMUD matcher, except
it can’t handle ranges of items. It can handle aliases, qualifiers, bound
qualifiers, ‘All’ and a specific instance such as 2 (second) or 3 (third)
item. For experimenting with the matcher I again implemented the WHICH command
that tells you which item would have been picked by the matcher. Here is a
quick demo, I’ve outdented the command lines to make it easier to read. The
duration on the prompt is the time to take input, process it, display results
and return to the prompt for the next command:


      Welcome to the WolfMini experimental environment!

    [Fireplace]
    You are in the corner of the common room in the dragon's breath tavern. A
    fire burns merrily in an ornate fireplace, giving comfort to weary
    travellers. The fire causes shadows to flicker and dance around the room,
    changing darkness to light and back again. To the south the common room
    continues and east the common room leads to the tavern entrance.

    You see a large, round blue ball here.
    You see a small green ball here.
    You see a small red ball here.
    You see a small blue ball here.

    You see exits: East Southeast South
  33.839µs>which ball
    You see a large, round blue ball.
  41.576µs>which all ball
    You see a large, round blue ball.
    You see a small green ball.
    You see a small red ball.
    You see a small blue ball.
  43.255µs>which blue ball
    You see a large, round blue ball.
  34.285µs>which 3 ball
    You see a small red ball.
  36.736µs>get ball
    You get a large, round blue ball.
  30.749µs>which all blue ball
    You see a small blue ball.
    You have a large, round blue ball.
  49.266µs> which all ball
    You see a small green ball.
    You see a small red ball.
    You see a small blue ball.
    You have a large, round blue ball.
  46.91µs>which red ball green ball
    You see a small red ball.
    You see a small green ball.
  47.107µs>which 2 ball
    You see a small red ball.
  35.663µs>which 2 blue ball
    You have a large, round blue ball.
  48.131µs>which red ball green frog green ball
    You see a small red ball.
    You see no 'GREEN FROG'.
    You see a small green ball.
  40.254µs>


My next job is to roll the new matcher into all of the commands I have
implemented so far. The matcher is about 88 lines of code. I won’t show that
much code here, but I will show the code for the WHICH command:


  func (s *state) Which() {

    if len(s.word) == 0 {
      s.Msg("Which what?")
      return
    }

    action := []string{"see", "have"}
    actIdx := 0

    for _, uid := range MatchUID(s.word, World[s.actor.As[Where]], s.actor) {
      what := World[s.actor.As[Where]].In[uid]
      if what == nil {
        what = s.actor.In[uid]
        actIdx = 1
      }

      switch {
      case what == nil:
        s.Msg("You see no '", uid, "'.\n")
      default:
        s.Msg("You ", action[actIdx], " ", what.As[Name], ".\n")
      }
    }
  }


The magic is in the MatchUID function which takes a list of words and the
items whose inventories should be looked into for items. Here we look at items
in the location where the actor is first: World[s.actor.As[Where]] and then
the actor’s inventory: s.actor for matching items.

The match results are returned as a string slice containing either unique
identifiers or unmatched words. For example the last command “which red ball
green frog green ball” returns: []string{"#UID-106", "GREEN FROG", "#UID-10A"}

We can then get the item with a simple lookup that returns nil if no item
matches: World[s.actor.As[Where]].In[uid] and s.actor.In[uid], if we try to
get the “GREEN FROG” we will get nil indicating not found. However, we can
also test if the string has a prefix of “#UID-” for matches, otherwise it’s a
non-matching result.

I need to tidy up the new matcher code a bit, then roll it into all of the
existing commands and see how well everything works. After that? I’m still
trying to hit the hard nails on the head early to see how far this little
experiment can go and if it’s worth pursuing. I’d like to bring life to the
world next with mobs doing things and items resetting. For that I’ll need to
tackle the prickly source of many previous problems — concurrency and locking.
Will the BRL (Big Room Lock) survive into WolfMini? Not sure yet…

--
Diddymus


  Up to Main Index                              Up to Journal for June, 2021