Hello again! I return during this week of winter solstice to tell you about my experience participating in the Langjam Gamejam. I planned to use Raku, partially so that you could have an advent blogpost to read today, but also because Raku’s builtin support for grammars ensure that I would not get stuck when writing my parser.
Preparation
I did a few things to ensure that I would be able to complete the game jam. The first was to be realistic about what I could achieve; with seven days of time, I could realistically expect to produce about three weekends worth of working code. This is only going to be a few hundred lines, maybe one or two files total, and prioritizing basic functionality over any fancy features.
I decided to make an idle game.
There’s no rule against deciding that ahead of time. I also decided to use Raku. That’s allowed too. I read the source of a couple different idle games too, mostly to get ideas of what not to do. In particular, big thanks to Idle Game Maker by Orteil, Antimatter Dimensions by Ivar K., and Trimps by the Trimp authors for publishing reasonably-readable source code. All three of these have some notion of programmability, although I ended up doing something quite different.
Sunday
The first place to start when making a game is with the scenario that the
player will be asked to experience. Games are fundamentally about roleplay,
and roles only exist within scenarios. Fortunately, I didn’t have to come up
with any of this.
Instead, I asked my friend Remi to come up with something interesting. We spent a couple hours adapting an idea for a Zelda-style fishing minigame, with the novel twist that the game would mechanically be an idle game; instead of putting in the athletic effort to retrieve the fish, the player manages a fishing business and delegates the work to employees.
It’s important to allow a genuine brainstorm at the beginning of the process.
Yes-and reasoning is essential for developing concepts. At the same time, it was important that we not plan for work that we couldn’t schedule. Remi committed to drawing a few icons and I committed to carrying out the core of the gamejam objectives:
- Design and implement a programming language
- Design and implement a game using that language
Monday
The first place to start when making a language is with the objects of that language. I don’t mean object-oriented design but the idea that the language expresses some sort of manipulation of reality. What are we manipulating? How do we manipulate them?
At a high level, idle and incremental games are about resource management. They can also include capacity planning. Thus, I decided that resources are the main objects of study. I also needed some way for the player to interact with the game world, and clickable buttons are a traditional way to express idle games. For each button, I’d thought to have a corresponding action in the game, which I’d also express in language.
I also needed to figure out what substrate I’m going to use. I mean, of course I’m using Raku, but how deeply do I want to embed the game? At one end, I could imagine compiling the game into a single blob which runs wholly in the end user’s windowing system or Web browser, so that there’s nothing of Raku in the end product.
At the other end, I could imagine shallowly embedding the game by writing some Raku subroutines and having the game developer write in ordinary Raku. I initially decided to go with the shallowest embedding that would still allow me to use Raku’s syntax for arithmetic: a Raku sublanguage, or Raku slang. Technically, a slang
is its own programming language, or so I was prepared to argue.
One open question concerned the passage of time. A resource evolves in time, perhaps growing or shrinking; it also has some invariants in time, particularly identity. What did I actually want to store internally? All hand-coded games devolve into a soup of objects cross-referenced by string-keyed maps, or at least that was the case for a half-dozen idle games that I’ve looked at. Maybe we can organize all of that into one big string-keyed map?
Another question is how the game will be experienced. I’d assumed that it should be possible to put up some simple HTTP server and run it locally. My notes are unclear, but I think that this is around the first time that I took a serious look at Humming-Bird.
Tuesday
Let’s actually write some code. I started by writing a slang that abused the Raku metamodel. I was inspired by OO::Actors, which introduces an actor keyword, as well as the implementation of the standard grammar keyword. I can just introduce my own resource and action keywords which manage some subexpressions, including Raku arithmetic, and that’ll be my language. To prototype this, I first wrote out a file which I want to be able to load, and then I wrote the parser which handles it.
Here’s a snippet from that first prototype:
resource fishmonger {
flavor-text "employee with knives and a booming voice for telling stories";
eats seafood by 0.017 per second;
eats bux by 15 per second;
converts from seafood into bux by 75 per second;
}
action hire-fishmonger {
flavor-text "employ a fishmonger to sell seafood";
costs 10 bux;
pays 1 fishmonger;
}
Several features are very important here. One big deal is that flavor text is inalienable from the resources and actions. I was very conflicted about this. Languages like Idle Game Maker are basically enlightened CSS and HTML; they are extremely concerned with presentation details rather than getting to the essential mechanics and handling time.
At the same time, Remi and I are both big fans of flavor text both for its immersive value as well as for its ability to create a memorable experience. Another important idea here is that costs and pays are two distinct attributes in concrete syntax, even though they’re going to be implemented as the same underlying sort of amount-and-currency pair.
This syntax is a little heavy. I was imagining that this would be a sort of Ruby or Tcl DSL where each command takes a row of arguments, some of which are literal tokens, and imperatively builds the corresponding resources and actions.
At this point, the scenario is complete. The game will have a few natural resources, like plankton, fish, and sharks; a conversion from fish to seafood; employees like fishers, fishmongers, and white mages; and an enhancement that white mages apply to fishers. There is no objective; it’s a population-dynamics sandbox.
Wednesday
After a day of trying to understand Raku’s metamodel, I concluded that a slang is the wrong layer of integration. I really wanted to run an input file through a parser in order to build a small nest of Resource and Action objects in memory, set up an HTTP server displaying them, and repeatedly take one tick per second, integrating changes over all of those objects.
This was a gumption trap for me; I completely lost motivation for a few hours. In those times, it is essential to allow one’s emotions to flow in order to move past them, and also essential to rest in order to restore energy.
After recovering a bit, I cleaned up my repository and thought about what I should do next. I might as well write a proper grammar. What should that language look like? I agonized over this for a few minutes, went through the possibilities of fixity and bracketing, and eventually decided that a nice little S-expression language would work for my needs.
This did mean that I would need to internalize arithmetic, but I also knew one of the standard cheats of game development: it’s okay to not implement arithmetic operations which aren’t actually used. Consider the following snippet:
(resource plankton 1e15
"little crunchy floaty things"
(growth 0.004 /s)
(view water-color (if (< .count 1e20) "clear" "cloudy"))
(view concentration (str (/ .count 2e14)))
)
(action look-at-water-color
"gaze at the ocean"
(enables view plankton water-color)
)
(action measure-plankton
"buy a plankton meter and put it in the water"
(enables view plankton concentration)
(costs 10 bux)
)
This is from my prototype. The only arithmetic that’s required is in the views, which format internal numbers about resources into strings. For those, I have a mini-language which allows the user to specify any arithmetic they want, as long as it’s either division or less-than comparisons. The formatting language is strongly typed; the parser won’t allow a non-Boolean operation as an if conditional, for example.
Some other design decisions stand out. Flavor text is now required. Resources have starting counts, which are also required. Rates always end with “/s”, an abbreviation for “per second” that is supposed to easily distinguish them from non-rates.
Gumption management requires not just succeeding, but having a feeling of understanding and competence. I probably could have started on the parser that night, but instead I walked to the bar and speedran Zelda 3, doing any% No Major Glitches and finishing in about two hours and change. Not a superb time, because I grabbed quite a few backups, including an entire extra heart and two bottles; but I didn’t die. The parser can wait until tomorrow.
Thursday
Parsing an S-expression is really easy, especially when the list of special forms (the words that can legally follow an opening parenthesis) is short. For each special form, we have a rule that parses each of the required components in order, followed by an optional zero-or-more collection of modifiers / attributes / members / components / accessories. The resource special form from Wednesday is parsed with a rule like:
rule thing:sym { '(resource' <s> * ')' }
The parser bottoms out on some very simple tokens. For parsing numbers, we parse a subset of what Raku accepts and then use .Rat or .Num methods to convert those strings to live values by reusing Raku’s parser. I may not have been able to reuse arithmetic but I was certainly able to reuse the numerals!
token id { + }
token s { '"' + '"' }
token n { + ('.' +)? ('e' +)? }
As I wired up the parser, I also set up a Humming-Bird application. I’m a fan of Ruby’s Sinatra and Python’s Flask, so it seemed like Humming-Bird would be a good fit for me. It doesn’t come with a preferred HTML-emitting library, so I tried a few options. I started with HTML::Tag, which I had added to the project on either Tuesday or Wednesday, but after a few minutes of practical usage, it became totally unusable due to syntactic zones of ceremony (Subramaniam, Seemann, myself): making a fresh HTML tag requires many source characters. I ended up using HTML::Functional, which is much lighter-weight but occasionally allows me to misuse Nil as a string.
I’m hacking out two roles. I’m presenting them here in their final versions; initially they didn’t take any parameters, which was too restrictive. One role is for rendering HTML and the other role is for evolving with each tick.
The %context is all of the resources and actions, and the $resource is the resource currently being acted upon. This sort of late-bound approach is technically too flexible for what I’m building, but I don’t feel like restricting it.
role Render { method html(%context, $resource) { ... } }
role Evolve { method tick(%context, $resource) {;} }
I committed, pushed, and asked Remi for feedback.
Friday
Remi approves! They’ll make a few cute little icons for some resources. At this point, I stopped and reflected upon what I’d made so far. Pastafarians typically take Fridays off, and I’m not about to work when I could rest instead. What works? What doesn’t work? Where should I spend the rest of my time? What should I have for dinner?
The parser works. The Resource and Action objects operate as nodes of an AST. Exporting the AST as HTML with Render.html() works. Traversing the AST for a tick with Evolve.tick() also works. The Nix environment, which Ihaven’t mentioned yet, also works; I’m using direnv to configure the environment and
install Raku packages.
Arithmetic operations don’t work yet. Actions don’t actually act on anything. Remi’s artwork isn’t visible and I haven’t split out the CSS yet.
I should spend the rest of my time getting the core mechanics of rendering and evolution to work properly. Easy to say; harder to do.
For dinner, I’ll have noodles of some sort, because it’s Friday. I ended up having spaghetti and meatballs in red sauce.
Before dinner, I went to the bar and speedran Mario 1. I played for about 90 minutes but I didn’t finish a single run. On 8-3, the penultimate level, I was repeatedly defeated by a gauntlet of tough enemies.
Saturday
Humming-Bird got in my way a little; it blocks by default and the
documentation doesn’t explain how to fix it. After reading the relevant code,
I had to change this line:
listen(8080);
To have a non-blocking annotation:
listen(8080, :no-block);
I also explore how to perform ticks in the background. I do find Supply.interval, but that will let the interpreter exit. Instead, I end up with the following hack:
while 1 { sleep 1; $venture.tick };
As I wired up operations and fixing display bugs, I became increasingly stressed as my CSS changes aren’t being applied. By doing some testing, I discovered that the Humming-Bird convenience helper for attaching static directories is not working. I had initially written:
static('/static', 'static');
But this doesn’t work, or it had worked on Friday but not on Saturday, or I had somehow mistyped “static”, or any of a dozen other impossible considerations. I knew that I can’t get distracted by this, and I finished up all of the rest of the functionality; the game works, but it’s not styled and Remi’s artwork isn’t visible.
That’s the end of the game jam. I produced a language and a game. However, the game doesn’t display properly and I wouldn’t consider it to be playable. What a frustration.
Sunday
I’m not done yet! I want to ensure that the release version has Remi’s artwork displayed. First, I hand-wrote the static routes; these do correctly route the CSS and images.
$router.get('/static/style.css', -> $req, $resp {
$resp.file('static/style.css');
});
$router.get('/static/icons/:icon', -> $req, $resp {
my $name = $req.param('icon');
1$name.contains('..') ?? $resp.status(400) !! $resp.file('static/icons/' ~ $name);
});
I found a few holes in our scenario. For example, there’s no way to see how many Bux the user has. By default, resource amounts are hidden both to keep the UI uncluttered and to provide a sense of mystery; however, for Bux or seafood, we want to give the user precise numbers. Our existing syntax can fully accommodate this! The view is enabled by an action which doesn’t have any line items (costs or pays) and it prints the .count variable as-is.
(resource bux 1000
"wireless cash"
(view cash-on-hand (str .count))
)
(action check-balance
"become aware of our earnings"
(enables view bux cash-on-hand)
)
With these two fixes, we now have a working interface that allows the scenario to be fully accessed! The new view looks like this:

Finally, I’m not going to be able to deploy this version as written. I’ll have to do some reading on production HTTP setups for Raku. When the game loads, it tries to load one image for every visible resource. If more than about five images are requested then the page fails to load. Every action is an HTTP POST which causes everything to reload again.
I imagine that this is properly fixed by adding entity tags to the HTTP backend so that images can be cached. For example, I took the screenshot in the header of this blog post while Firefox was still considering whether it could load the image for plankton; it eventually gives up:

Every load of the page causes a different set of images to not load. This is an unacceptable game experience.
Closing thoughts
The idea of a declarative idle-game maker is reasonable and it was only a week’s effort to prototype a basic interpreter which simulates a simple scenario. I think that the biggest time sinks were trying to make a slang instead of a deeper language with a parser, fighting with Humming-Bird, and generally trying to keep code clean. On that last point: I found that cleaning up my code was necessary to let bugs and mistakes become visible.
The game comes out to about three hundred lines of Raku and fewer than one hundred lines of S-expressions. It’s within my coding budget for sure. I don’t think that I went for more than I could reasonably accomplish. The entire code is available in this gist. Remi quite reasonably doesn’t want their art uploaded to GitHub, but you can check out more of their work at their website.
Have a happy winter solstice and Holiday!