Skip to Content

1130h, October 27th 2019

1130h, October 27th 2019 is a log tagged with Racket, qtMUD, and programming. It was released on Oct 27, 2019.

So, writing a MUD engine in a new language. I’ve been here before, too many times.

I’d love to say I’m wiser now, but honestly I haven’t spent nearly as much time doing anything close to “programming” as I used to.

I have a more-or-less working engine written in Python, but I’ve become disillusioned with Python as a programming… ecosystem?

So I’ve decided to switch to Racket, which honestly has a lot of the same problems, but a lot of benefits (in my opinion) for what I want to do.

(I’m sure there’s a bunch of readers anxious to hear more about what I mean by all that, but frankly, I don’t know a way to express these opinions without getting flamed and subsequently insecure, so, Racket, because I say so!)

Now, I’ve been reading a bit about programming, from the book How to Design Programming, and it taught me that I should follow a “formula design recipe,” when planning a formula, or bigger program. A MUD is a pretty big sort of program (even if nothing it does is individually complex), but I imagine the formula still applies.

Let’s see if I can remember the steps:

  1. Define the problem and data structures it requires.
  2. Define the inputs and return of the function (or program).
  3. Write example data and expected results.
  4. Template the function.
  5. Program the function.
  6. Re-write the example data as functions.

@margin-note{I should look up how to do an ordered list in Scribble properly, and also how to make a TODO note.}

I’m pleased I remembered the steps! Can I apply them, though?

So the problem is, I don’t have a way to interface with my digital personal information. The required data structures are… plentiful. I honestly don’t know how to answer that question at this scope, it seems like there will be lots of small data structures.

But, I suppose, let’s look at how an interface works, generally. There’s some data, on the backend, and then you (the user) do something to interact with the data. But reading the data means rendering it, and that usually means bringing it into some unified form.

I know from reading Chris Webber’s blog that he’s doing some cool work with like, Actors and Objects and Object Capabilities, and I’m sure if I understood it, I’d probably find it really applicable to this step.

Without looking it up again, I remember that within ActivityPub, there are Objects, and Actors. Objects have a type, an associated actor, and content.

Type and content make sense as metadata but perhaps it should be a link to the JSON schema that defines the content, for type, instead of just a string?

That’d give me a data structure of something like

(struct thing (type content))

When I was working on a web-server in Elisp, I’m remembering, I had it so that my “things” - then called “rosian objects” - had themselves a head, contents, and renderings. The information in head was used to create the contents and renderings. The information in the contents and head was used to create the renderings. The information in renderings was sent to clients, with plans to cache it based on modification dating on the contents.

So maybe

(struct thing (head content renderings))

Where

(struct head (type schema))

Content would be serialized data following the schema in head, and renderings would be a hash of rendering IDs (say “html5-full-document”) and the created rendering.

That sounds pretty reasonable. So, to restate, I’m completing step #1 of the “function design recipe,” which is to state the problem with its data structures.

So the problem is that I want to use a variety of personal information through a unified interface, and the data structure I’ll use to do that is {[head (type schema)] [content (title body)] [renderings (html-doc)]}, for example.

(I’m not sure how one writes out a more formal specification?

{
    "head": {
      "type": "Log Entry",
      "schema": "https://emsenn.net/qtmud-schemas/log-entry.json"
    }
    "body": {
      "date": "2019-10-26T10:30Z"
      "body": "Today I decided to rewrite qtMUD in Racket."
    }
    "renderings": {
      "markdown-paragraph": "**1030h**, ***October 26th, 2019***: Today I decided to rewrite qtMUD in Racket.\n\n"
    }
}

Maybe that makes it a bit more clear. Then the page emsenn.net…log-entry.json would have something like:

{
    "date": "2019-10-26T10:30Z"
    "body": "Log entry body"
}

Or however you properly define that - I remember ActivityPub links to its own specification, I’ll research the specifics later: for now, I’m just sketching out what the data structure I’ll probably be working with looks like.

One thing that’s missing here is anything that instructs the program on which rendering to make: I think that’s okay, because I’ll provide that information through the function’s input.

Okay, just to restate one more time so it’s extra clear for myself: the problem to be solved is working with my personal information using a unified interface, and the data structure to be used is {[head (type schema)] [contents (...)] [renderings (...)]}.

Step #2 of the function (program) design recipe is… write out what input and output the function (program) will be, right?

Okay, well, this one opens me up to a lot of different answers, beccause there are a lot of inputs and outputs that could be used for a MUD.

Generally put, the input is a request from a client (a computer somewhere, perhaps the same computer running the server), and the return is a rendering of a thing. That glosses over… a lot.

So, the server has to be able to get from a request to a rendering. What information comes with the request? I know it has to have the client itself, in some form - that’s useful in as much as it tells us where to send the reply, but doesn’t do much to inform about what sort of resource is requested. So we also need some sort of identifier as part of the request, something that says “this is the thing we want rendered and returned.”

Skipping ahead for a moment: what sort of rendering? That can either be specified in the request, or inferred (maybe) from the client. If it’s a client making the request through telnet, they probably want a plain or ANSI text rendering sent back as the reply. If they’re making the request as an HTTP GET, they probably want HTML (or maybe JSON) back as a response.

Going back to an identifier: this is a thornier problem than it might seem. Let’s set up two example situations.

  1. I’m a client logged into the MUD server through telnet, and I’m in my in-game living room, where there’s a bookshelf containing little books, each one a log entry. I’ve taken a book from the shelf representing a log from October 26th, 2019, and entered the command (made the request) to read that book.1 This should send me a bit of text that represents that log entry.

  2. I’m a client anonymously browsing the MUD server with my web browser, and have arrived at a page listing every public log entry on the server tagged qtMUD. I see one from October 26th, 2019, and click on the link. This should bring my browser to an HTML document that represents that log entry.

In both cases, I intend to request the same thing, and the type of rendering is implicit based on the type of client, so the only issue is in figuring out, from the request, what thing is wanted.

Looking at the MUD situation, our request (re-written as JSON) might come in looking something like this:

{
  "client": #mud-client
  "input": "read book"
}

From this, the server would:

  1. Break down the command into its parts: the verb “read” an the object “book.”
  2. Determine that “read” means “render the ‘contents.body’ of the object”
  3. Determine what “book” refers to, by doing something like “find the first thing whose nouns include ‘book’ in the player’s surroundings.”

Ahh - this brings us to “identifiers.”

The book is just a representation of the actual thing - the thing is a “log entry,” not a book. How do we get it from being a thing of type “log entry” to able to respond to the name “book”?

Let’s look at the web browser situation. Our request there, re-writtne as JSON, migth come in looking something like this:

{
    "client": #http-client,
    "request-uri": "/logs/201910261130/"
}

We encounter a similar problem: How do we get from a thing of type “log entry” to a thing that can respond to the name “/logs/whatever”?

(To those of you reading this who know more about computer science, you may feel as though I am re-inventing the wheel, or talking through basic concepts. These notions are new to me, and working through my needs like this helps me learn them.)

It’s easy enough to create a unique identifier for each thing: generate an ID, compare it to all known IDs, and if it’s used, throw it out and make a new one until it one isn’t used.

That unique ID can be viewed as the “proper” name of the thing. Let’s say the unique id of our log entry thing is A2C4.

So, let’s say we start up the MUD and there’s a step there that creates all the environments. When it came to create my house, it’d look up my house’s thing, which would contain a list of furnishings, which would specify my bookcase thing, and that it contains all these log entry things.

It’d do this by going “Okay, so are there any things of type ‘room’?” There is, at least one, my house. It’d take my houses thing, and say “Thing, you’ve been given the nickname ‘room’ by the room creator service.” Now, the room Thing responds to its ID, say Z5P8, and the nickname room.

Remember - this is all to answer the question “what does the program receive and output,” - we’re making sure that we’ll be able to work with the limited inputs I’m suggesting. It looks like, given a system of internal nicknaming, that’ll be possible.

Step #3 is to write up some example data: I’d say I’ve just done that.

Step #4 is to template the functions.

Oh. Well, that’s asking for a lot, especially considering I don’t really know Racket’s syntax.

But, even failing that, I can take a lot of what I’ve written here and flesh it out to create a fair number of function templates: I’ll just have to look up how Racket suggests doing that.

(I know it has some way of doing literate programming, and another for in-source documentation, but I’m not sure if either of those will be appropriate. I’ll read the documentation, then get to templating, however I best see fit.


  1. I’m glossing over a lot of how we would’ve gotten here: logging in as a specific client, parsing commands, etc. Most of that works the same way that the request we’re going to examine would, just with more domain-specific knowledge. [return]