A Proper Cup of Tea

This article is a repost promoting content originally published elsewhere. See more things Dan's reposted.

Screenshot from "A Proper Cup of Tea", showing the start of the game.

This “choose your own adventure”-style game about making the perfect cup of tea is just… excellent.

If you lack the imagination to understand how a game like this could have dozens of possible endings, you desperately need to play it. My favourite path so far through the game was to add a teabag, then hot water, then remove the teabag, then add some milk, then add a second teabag, then drink it.

Genuinely can’t stop laughing at this masterpiece.

My Favourite Video Game Easter Egg

Spoiler: it’s Alorik’s crystal ball in Ultima Underworld II.

This blog post is also available as a vlog: why not watch & listen to me as I demonstrate my favourite video game Easter egg!

Video preview showing Dan overlaid on a screenshot of Ultima Underworld II.

Ultima Underworld II

My favourite video game Easter egg is found in Ultima Underworld II: Labyrinth of Worlds1.

Released early in 1993 after missing a target of Christmas 19922, it undersold despite being almost universally well-received by reviewers3.

Composite of PC Zone's review of Ultima Underworld II, overlaid with their final score: "94%: Just go out now and buy it, okay."
I don’t know how print magazine video game reviews read today, but back in the early 90s they seemed to be frivolous and flippant approximately 100% of the time.

Developed by Looking Glass Technologies, it used an enhanced version of the engine they’d used for the game’s prequel a year earlier4.

The engine is particularly cool for it’s time; it’s sometimes compared to Wolfenstein5, but that’s not entirely fair… on Wolfenstein! The original version of Underworld‘s 3D engine predated Wolfenstein… and yet supported several features that Wolfenstein lacked, like the ability for the player to look up and down and jump over chasms, for example.

Screenshots of the same piles of bones and detritus in Ultima Underworld I, seen from two different angles.
Move around and you’ll see the 3D walls shift to your new perspective, but you’ll always see the same side of the 2D objects on the floor. Turn as you might, you’ll never see the back of that skull!

The team’s expertise and code would eventually be used to produce System Shock in 1994. The team’s producer, Warren Spector, would eventually draw from his experience of the Ultima Underworld games when he went on to make Thief: The Dark Project and Deus Ex.

But the technology of Ultima Underworld II and its prequel aren’t as interesting as its approach to storytelling and gameplay. They’re:

  • real-time
  • first-person
  • non-linear
  • fantasy roleplaying games

This was a highly innovative combination6.

Highlighted part of the Designers Notes, reading: "We feel that one of Underworld’s strongest features is its capacity to generate situations and strategies that we did not script, but that arose from the scenarios we created. For example: Suppose there’s a Despoiler daemon guarding the key to that door. Maybe I should come back when I can take him hand-to-hand … or bring up my picklock skill … or throw this sling stone at him, see if he’ll chase me … or maybe I can sneak past him — how good is a Despoiler’s eyesight? And can he swim …"
Underworld II encourages lateral thinking and provides multiple solutions to many challenges, perhaps best-described by this section in the Designers’ Notes page at the back of the manual.

What’s being described there is what we’d now call emergent gameplay, and while it wasn’t completely new in 19937 it was still uncommon enough to be noteworthy.

The Easter Egg

The Ultima series are riddled with Easter eggs, but my favourite is one that I feel is well-hidden, beautiful… and heavily laden with both fan service and foreshadowing!

Screenshot showing a frozen fountain in an icy realm.
The third of the interdimensional planes the Avatar visits in the game contains a city frozen solid by the Guardian’s magic.

To find the Easter egg, you must first travel to Anodunos. This city was once the capital of a tropical city-state which had become allied to the Guardian, the the principal antagonist of Ultima VII through IX.

Box art showing a hero dressed in leather armour wielding a staff with a glowing tip in a frozen cave.
The original box art for Underworld II, painted by Denis Loubet (who’ll draw your RPG character for you if you like!) showed the Avatar in the ice cavern, wielding an important late-game artefact.

After the city’s major, Beatrice, attempted to put an end to the red titan’s growing demands, the Guardian cursed the city fountain to radiate out a magical cold that eventually froze the entire settlement under a cave of ice.

Screenshot of the conversation interface as Dan talks to a ghost called Beatrice.
Mayor Beatrice lives on here, as a ghost. While she’s a great source of information about the ice caverns as a whole and has information highly useful to the primary quest, that’s not the thing we’re interested in right now.

On the Eastern bank of the city’s river we find the remnants of the workshop of the magician Alorik, and in it – if we look in the right place8 – a secret door. We can’t open it though: unusually for a secret door in this game, it’s locked.

Looking at a blank patch of wall in a frozen room, the player is told "You see a secret door."
In the original, unpatched release of the game, you couldn’t even cast the “open” spell on it to unlock it: the only way through was to use a powerful late-game spell like “portal” to teleport to the other side.

I didn’t even find this chamber on my first playthrough of the game. It was only on my second, while using the Map Area spell to help me to draw accurate maps of the entire game world, that I found the room… and even then I spent some time hunting for a switch on the “outside” before eventually giving up and teleporting into the secret room.

An open secret door (the one from before, but viewed from the other side), and a thrown switch.
Once you’re on the other side, there’s a switch. I guess it’s a Alorik’s panic room?

There’s valuable treasure here including a sceptre of mana restoration, a “grav” runestone (probably still easier to get than the one at the Scintillus Academy), but what’s most interesting is the crystal ball, which the player can look into to see a vision of another place and, in the case of this orb, another time.

The first time you look into it, you’re told:

You see yourself striving against the forces of Mondain and Minax in the lands of ancient Sosaria.9

Mondain and Minax are the antagonists in Ultima I and Ultima II. We’re seeing the earliest parts of the player character’s adventures.

In the game: looking into the crystal ball.
It’s long been argued that the “Stranger” – the protagonist of Ultima I through Ultima III – is a different person to the Avatar of Ultima IV but I feel like this vision is canonical proof that they’re supposed to be interpreted as being the same person…

If we look into the crystal ball a second time:

You see yourself climbing to the peak of Olympus Mons on the planet Mars.

This is a reference to the plot of Ultima: Worlds of Adventure 2: Martian Dreams… which is a… weird choice of game to reference.

In my mind, a more logical leap forward in time might have been to jump to Ultima IV10, in which the protagonist first becomes the Avatar of the Eight Virtues and the Hero of Britannia. Martian Dreams is… a sequel to a spinoff of Ultima VI. So why pick that?

Screenshot from Martian Dreams showing Dr. Spector.
Little-known and oft-forgotten, Martian Dreams is apparently nonetheless a source of pride for the real Spector.

Martian Dreams starts with a friend of the Avatar’s from Earth facilitating the Avatar and their companions to set out on an adventure to the planet Mars. That friend is called Dr. Spector, obviously named for Warren Spector, who helped develop Ultima VI and, of course, this game. This usual choice of vision of the past is a cryptic nod to the producer of Underworld II.

Let’s look again:

You see yourself in the Deep Forest, speaking with the peace-loving simian race of Emps.

This one’s a reference to Ultima VII, the game whose story immediately precedes this one. The Deep Forest seems an strange part of the adventure to choose, though. The Avatar goes to the Deep Forest where, via some emps and then a wisp are eventually lead to the Time Lord11. The Time Lord provides a whole heap of exposition and clues that the Avatar needs to eventually close the Black Gate and win the game.

Ultima VII: the Avatar converses with the Time Lord in the Shrine of Spirituality. He says "Thou must free me and we must work together in battling the Guardian. The fate of thy people depends upon it. Dost thou accept?"
Tardis noises intensify.

Do these references serve to hint that this crystal ball, too, is a source of exposition and guidance? Let’s see what it says next.

You see yourself peering into a crystal ball.

I remember the moment I first saw this happen in the game: serious chills! You’ve just found a long-lost, centuries-buried secret chamber, in which there’s a crystal ball. You peer into it and observe a series of moments from throughout your life. You continue to watch, and eventually you see yourself, staring into the crystal ball: you’re seeing the present. So what’s next?

Frame from 1984's The NeverEnding Story, showing Atreyu seeing the prophetic painting that shows the beast he's about to meet.
Alorik’s crystal ball from Ultima Underworld II and the mural of G’mork from The NeverEnding Story totally have the same energy.

If you look again, you’re asking to see… the unwritten future:

You see yourself winding a great war horn in the throne room of Castle British.

To save Britannia in Ultima Underworld II, the Avatar needs to exploit symmetries implicit in The Guardian’s spellcasting to travel to eight different parallel worlds, find a place from which His power stems, dispel it, encase themselves in a shell of basilisk oil-infused magic mud, immerse themselves in lava to bake it on, find a magic sigil, consume a djinn… it’s a whole thing. But ultimately it all leads to a climactic end scene in which the Avatar raises a horn retrieved from the Tomb of Praecor Loth and blows it to shatter a dome of blackrock.

Under a starry sky, a blackrock dome grows green cracks and shatters.
Blackrock’s really heavy, right? I’m not sure that shattering it above the building you’re inside is wise.

If you happen to find this clue on your first playthrough, it’s helpful exposition.

But that’s the end of this game, right? How can we possibly peer into the orb again?

You see yourself sailing through majestic pillars cropping up out of the sea, on a voyage of discovery.

What’s being described there is the opening scene from the next game in the series, the as-yet-unreleased Ultima VII Part 2: Serpent Isle!

Ultima VII Part 2 introduction, showing a boat sailing through an icy sea corridor towards two serpent pillars.
Serpent Isle begins with the Avatar and their companions sailing out to some special pillars in pursuit of a bad guy.

This vision is a teaser of what’s to come. That’s just… magical, for both the character and the player.

The character uses fortune-telling magic to see their future, but the player is also seeing their future: if they’re playing Ultima Underworld II at or close to its release date, or they’re playing through the games in chronological order, they’re in a literal sense being shown what comes next in their life. That’s really cool.12

Let’s look again:

You see the obscure form of an old and dear friend, as he sacrifices his life for the good of all.

Some time after the party arrives on Serpent Isle, the Avatar’s companions are possessed by the Banes of Chaos and go on a murderous rampage. Later, there’s a ritual that will save the world, but at the cost of the death of one of the heroes. The Avatar is willing to make the ultimate sacrifice, but in the end Sir Dupre takes his place, unwilling to live within himself after seeing the carnage he has wrought.

Sir Dupre says "I cannot live with the shame of the deaths I have caused... If I can redeem myself by becoming the required martyr, so be it!"
The death of Sir Dupre, who first appeared way back in Ultima II, is somewhat undercut by his resurrection in Ultima IX. But perhaps you’ll let me pretend for a paragraph longer that Ultima IX doesn’t exist, okay?

At the end of Serpent Isle, the Avatar is plucked out of space and time and deposited into Pagan, The Guardian’s home base. The plot of Ultima VIII and Ultima IX revolve around the Avatar working to return to a radically-changed Britannia, attempting to fight The Guardian and bring to an end the Age of Armageddon, and ultimately merging and become one with Him before vanishing completely from the world.

An ankh symbol picked out in the constellations.
I don’t disagree with how Ultima IX got to where it was going, but I don’t like the route it took to get there. Or the hilariously-terrible bugs.

Which is why it’s perhaps quite fitting that if the Avatar in Underworld II looks into the orb one final time, they’re told…

You see nothing.

That’s it. That’s the end.

The end of the vision, certainly, but also: a vision of the end.

Depending on how you count the Ultima games13, this is the 13th of 17 in the series. We’re approaching the final chapter, and this Easter egg foreshadows that finale.

I feel hugely privileged that I got to experience it “organically”, by accident, as its authors presumably intended, back in 1993. But it also makes me happy to be able to share the story of it with you14.

If you haven’t seen it yet, you might enjoy watching the vlog version of this post, through which my enthusiasm for the topic might be more-palpable.

Footnotes

1 I’ve doubtless mentioned Ultima Underworld II before: for example both it and Ultima VII, as well as NetHack (mentioned elsewhere in this post) made it into my 2007 list of top 10 computer games that stole my life.

2 The release was delayed owing to testing revealing just too-many bugs, the penultimate of which was squashed on 18 December leaving just one more that the team couldn’t reproduce until the New Year

3 It suffered perhaps for the time of year it was released, but perhaps also for the fact that 1993 was a big year for video games and it was competing with The 7th Guest, Star Wars: Rebel Assault, Return to Zork , Myst, Disney’s Aladdin and, of course – later in the year – Doom.

4 Director/designer Paul Neurath apparently sang the praises of his team for improving texture mapping and viewport size constraints, and he’s right: they’re a huge improvement on Underworld I‘s. Neurath would later go on create the crowdfunded “spiritual successor” Underworld Ascendant, which was critically panned, which just goes to show that sometimes it’s better to get a tight team together and make it “until it’s done” than to put your half-baked idea on Kickstarter and hope you can work it out what you’re making before the money runs out.

5 Like Wolfenstein, the engine uses a mixture of software-rendered 3D (for walls and furniture) overlaid with traditionally-produced sprites (for characters and items).

6 All executed over a year before the release of the very first Elder Scrolls game. Just sayin’.

7 That king of emergent gameplay NetHack was showcasing emergent gameplay in a fantasy roleplaying game way back in the 1980s!

8 An interesting quirk of the game was that if you turned the graphics settings down to their lowest, secret doors would become just as visible as regular doors. If you’re sure there is one but you can’t quite find it, tweaking your graphics settings is much easier than casting a spell!

9 Do you like the “in the style of Underworld II” scrolls I’ve used in this post? I’ve made available the source code you need if you want to use them yourself.

10 Ultima IV is my personal favourite Ultima game, but I see the argument of people who claim that Ultima VII is the best of the series.

11 The Time Lord turns up throughout the game series. Way back in Ultima III, he appears in the Dungeon of Time where he provides a clue essential to defeating Exodus, and he appears or is referenced in most games from Ultima VII onwards. He doesn’t seem to appear in Ultima IV through Ultima VI, except… in Ultima IX, which wouldn’t be released until six years after Underworld II, it’s revealed that the Time Lord is the true identity of the seer Hawkwind… who provided the same kind of exposition and guidance in Ultima IV!

12 How did the Underworld II team know with such certainty what was being planned for Serpent Isle? At some point in 1992 project director Jeff George left Origin Studios and was replaced by lead designer Bill Armintrout, and the role of producer was assigned to… Warren Spector again! For some time, Spector was involved with both projects, providing an easy conduit for inter-team leaks.

13 How you count Ultima games and what specifically should be counted is a source of controversy in fan circles.

14 I’m sure many people reading this will have heard me talk about this particular Easter egg in-person before, over the last couple of decades. Some of you might even have heard me threaten to write a blog post about it, someday. Well: now I have. Tada! It only took me thirty years after experiencing it to write about it here, which is still faster than some things I’ve blogged about!

Composite of PC Zone's review of Ultima Underworld II, overlaid with their final score: "94%: Just go out now and buy it, okay."× Screenshots of the same piles of bones and detritus in Ultima Underworld I, seen from two different angles.× Highlighted part of the Designers Notes, reading: "We feel that one of Underworld’s strongest features is its capacity to generate situations and strategies that we did not script, but that arose from the scenarios we created. For example: Suppose there’s a Despoiler daemon guarding the key to that door. Maybe I should come back when I can take him hand-to-hand … or bring up my picklock skill … or throw this sling stone at him, see if he’ll chase me … or maybe I can sneak past him — how good is a Despoiler’s eyesight? And can he swim …"× Screenshot showing a frozen fountain in an icy realm.× Box art showing a hero dressed in leather armour wielding a staff with a glowing tip in a frozen cave.× Screenshot of the conversation interface as Dan talks to a ghost called Beatrice.× Looking at a blank patch of wall in a frozen room, the player is told "You see a secret door."× An open secret door (the one from before, but viewed from the other side), and a thrown switch.× In the game: looking into the crystal ball.× Screenshot from Martian Dreams showing Dr. Spector.× Ultima VII: the Avatar converses with the Time Lord in the Shrine of Spirituality. He says "Thou must free me and we must work together in battling the Guardian. The fate of thy people depends upon it. Dost thou accept?"× Frame from 1984's The NeverEnding Story, showing Atreyu seeing the prophetic painting that shows the beast he's about to meet.× Under a starry sky, a blackrock dome grows green cracks and shatters.× Ultima VII Part 2 introduction, showing a boat sailing through an icy sea corridor towards two serpent pillars.× Sir Dupre says "I cannot live with the shame of the deaths I have caused... If I can redeem myself by becoming the required martyr, so be it!"× An ankh symbol picked out in the constellations.×

[Bloganuary] Playtime

This post is part of my attempt at Bloganuary 2024. Today’s prompt is:

Do you play in your daily life? What says “playtime” to you?

How do I play? Let me count the ways!

RPGs

I’m involved in no fewer than three different RPG campaigns (DMing the one for The Levellers) right now, plus periodic one-shots. I love a good roleplaying game, especially one that puts character-building and storytelling above rules-lawyering and munchkinery, specifically because that kind of collaborative, imaginative experience feels more like the kind of thing we call “play” when done it’s done by children!

Composite photo showing a young boy rolling a D20 onto a character sheet in front of a tabletop battlemap, and three monitors in a dark room showing a video chat between people and a digital gameboard.
Family D&D and Abnib D&D might have a distinctly different tone, but they’re still both playtime activities.

Videogames

I don’t feel like I get remotely as much videogaming time as I used to, and in theory I’ve become more-selective about exactly what I spend my time on1.

Dan with his thumbs-up in front of the high-score table (with the top-ranking spot about to be filled) of Wonder Boy, on a generic "80s Arcade Classics" arcade cabinet.
I managed to beat Wonder Boy last week, and it “only” took me three and a half decades!

Board Games

Similarly, I don’t feel like I get as much time to grind through my oversized board games collection as I used to2, but that’s improving as the kids get older and can be roped-into a wider diversity of games3.

A girl, sat in front of an Agricola farmyard board, holds up a "sheeple" (small wooden sheep game piece) for the camera.
Our youngest wakes early on weekend mornings and asks to kick off his day with board games. Our eldest, pictured, has grown to the point where she’s working her way through all of the animal-themed games at our local board games cafe.

Escape Rooms

I love a good escape room, and I can’t wait until the kids are old enough for (more of) them too so I’ve an excuse to do more of them. When we’re not playing conventional escape rooms, Ruth and I can sometimes be found playing board game-style boxed “kit” ones (which have very variable quality, in my experience) and we’ve recently tried a little Escape Academy.

Ruth and Dan hold up an Alice In Wonderland themed sign reading "it went like a dream" underneath the sign for escape room company Escape Hunt. Both are wearing silly hats, and Dan is also wearing white rabbit ears.
Ruth and I make a great duo when we remember to communicate early-and-often and to tag-team puzzles by swapping what we’re focussing on when we get stuck.

GNSS Activities

I’m sure everybody knows I do a modest amount of geocaching and geohashing.4

Dan, outdoors in a field on a grey day and with the wind whipping his hair across his face, wearing a high-vis jacket over a warm fleece, holds up a GPS receiver which shows he's zero metres from his destination.
I’m out standing in my field.

They’re not the only satnav-based activities I do at least partially “for fun” though! I contribute to OpenStreetMap, often through the “gamified” experience of the StreetComplete app, and I’m very slowly creeping up the leader board at OpenBenches. Are these “play”? Sure, maybe.

And all of the above is merely the structured kinds of play I engage in. Playing “let’s pretend”-style games with the kids (even when they make it really, really weird) adds a whole extra aspect. Also there’s the increasingly-rare murder mystery parties we sometimes hold: does that count as roleplaying, or some other kind of play?

Guests dressed as a chef, a priest, and a librarian sit around a dining table at a murder mystery party.
A chef, a priest, and a librarian walk into a party… stop me if you’ve heard this one.

Suffice to say, there’s plenty of play in my life, it’s quite varied and diverse, and there is, if anything, not enough of it!

Footnotes

1 I say that, and yet somehow Steam tells me that one of my most-played games this year was Starfield, which was… meh? Apparently compelling enough that I’ve “ascended” twice, but in hindsight I wish I hadn’t bothered.

2 Someday my group and I will finish Pandemic Legacy: Season 2 so we can get started on Season 0 which has sat unplayed on my shelves since I got it… oooh… two or three years ago‽

3 This Christmas, I got each of them their first “legacy” game: Zombie Kids for the younger one, My City for the elder. They both seem pretty good.

4 Geocaching is where you use military satellite networks to find lost tupperware. Geohashing uses the same technology but what you find is a whole lot of nothing. I don’t think I can explain why I find the latter more-compelling.

Composite photo showing a young boy rolling a D20 onto a character sheet in front of a tabletop battlemap, and three monitors in a dark room showing a video chat between people and a digital gameboard.× Dan with his thumbs-up in front of the high-score table (with the top-ranking spot about to be filled) of Wonder Boy, on a generic "80s Arcade Classics" arcade cabinet.× A girl, sat in front of an Agricola farmyard board, holds up a "sheeple" (small wooden sheep game piece) for the camera.× Ruth and Dan hold up an Alice In Wonderland themed sign reading "it went like a dream" underneath the sign for escape room company Escape Hunt. Both are wearing silly hats, and Dan is also wearing white rabbit ears.× Dan, outdoors in a field on a grey day and with the wind whipping his hair across his face, wearing a high-vis jacket over a warm fleece, holds up a GPS receiver which shows he's zero metres from his destination.× Guests dressed as a chef, a priest, and a librarian sit around a dining table at a murder mystery party.×

Wonder Boy

There are video games that I’ve spent many years playing (sometimes on-and-off) before finally beating them for the first time. I spent three years playing Dune II before I finally beat it as every house. It took twice that to reach the end of Ultima Underworld II. But today, I can add a new contender1 to that list.

Today, over thirty-five years after I first played it, I finally completed Wonder Boy.

Entryway to "West View Leisure Centre", decorated in a bright, abstract, 80s style.
I first played Wonder Boy in 1988 at West View Leisure Centre, pictured here mostly as-I-remember-it in a photo by Keith Wright (used under CC BY-SA 2.0 license).

My first experience of the game, in the 1980s, was on a coin-op machine where I’d discovered I could get away with trading the 20p piece I’d been given by my parents to use as a deposit on a locker that week for two games on the machine. I wasn’t very good at it, but something about the cutesy graphics and catchy chip-tune music grabbed my attention and it became my favourite arcade game.

Of all the video games about skateboarding cavemen I’ve ever played, it’s my favourite.

I played it once or twice more when I found it in arcades, as an older child. I played various console ports of it and found them disappointing. I tried it a couple of times in MAME. But I didn’t really put any effort into it until a hotel we stayed at during a family holiday to Paris in October had a bank of free-to-play arcade machines rigged with Pandora’s Box clones so they could be used to play a few thousand different arcade classics. Including Wonder Boy.

A young girl in a pink leopard-print top plays Wonder Boy on an arcade cabinet.
Our eldest was particularly taken with Wonder Boy, and by the time we set off for home at the end of our holiday she’d gotten further than I ever had at it (all without spending a single tenpence).

Off the back of all the fun the kids had, it’s perhaps no surprise that I arranged for a similar machine to be delivered to us as a gift “to the family”2 this Christmas.

A large, arcade-cabinet-shaped present, wrapped in black paper and a red ribbon, stands alongside a Christmas tree.
If you look carefully, you can work out which present it it, despite the wrapping.

And so my interest in the game was awakened and I threw easily a hundred pounds worth of free-play games of Wonder Boy3 over the last few days. Until…

…today, I finally defeated the seventh ogre4, saved the kingdom, etc. It was a hell of a battle. I can’t count how many times I pressed the “insert coin” button on that final section, how many little axes I’d throw into the beast’s head while dodging his fireballs, etc.

So yeah, that’s done, now. I guess I can get back to finishing Wonder Boy: The Dragon’s Trap, the 2017 remake of a 1989 game I adored!5 It’s aged amazingly well!

Footnotes

1 This may be the final record for time spent playing a video game before beating it, unless someday I ever achieve a (non-cheating) NetHack ascension.

2 The kids have had plenty of enjoyment out of it so far, but their time on the machine is somewhat eclipsed by Owen playing Street Fighter II Turbo and Streets of Rage on it and, of course, by my rediscovered obsession with Wonder Boy.

3 The arcade cabinet still hasn’t quite paid for itself in tenpences-saved, despite my grinding of Wonder Boy. Yet.

4 I took to calling the end-of-world bosses “ogres” when my friends and I swapped tips for the game back in the late 80s, and I refuse to learn any different name for them.[footnote], saved Tina[footnote]Apparently the love interest has a name. Who knew?

5 I completed the original Wonder Boy III: The Dragon’s Trap on a Sega Master System borrowed from my friend Daniel back in around 1990, so it’s not a contender for the list either.

A young girl in a pink leopard-print top plays Wonder Boy on an arcade cabinet.× A large, arcade-cabinet-shaped present, wrapped in black paper and a red ribbon, stands alongside a Christmas tree.×

Easy FoundryVTT Cloud Hosting

Foundry is a wonderful virtual tabletop tool well-suited to playing tabletop roleplaying games with your friends, no matter how far away they are. It compares very favourably to the market leader Roll20, once you get past some of the initial set-up challenges and a moderate learning curve.

Screenshot from FoundryVTT, showing a party of three adventurers crossing a rickety bridge through a blood-red swamp, facing off against a handful of fiends coming the other way. A popup item card for a "Dragon Slayer Longsword" is visible, along with two 20-sided dice.
The party of adventurers I’ve been DMing for since last summer use Foundry to simulate a tabletop (alongside a conventional video chat tool to let us see and hear one another).

You can run it on your own computer and let your friends “connect in” to it, so long as you’re able to reconfigure your router a little, but you’ll be limited by the speed of your home Internet connection and people won’t be able to drop in and e.g. tweak their character sheet except when you’ve specifically got the application running.

A generally better option is to host your Foundry server in the cloud. For most of its history, I’ve run mine on Fox, my NAS, but I’ve recently set one up on a more-conventional cloud virtual machine too. A couple of friends have asked me about how to set up their own, so here’s a quick guide:

Screenshot from Linode showing a server, "Foundry", running, with specs as described below.
I used Linode to spin up a server because I still had a stack of free credits following a recent project. The instructions will work on any cloud host where you can spin up a Debian 12 virtual machine, and can be adapted for other distributions of Linux.

You will need…

  • A Foundry license ($50 USD / £48 GBP, one-off payment1)
  • A domain name for which you control the DNS records; you’ll need to point a domain, like “danq.me” (or a subdomain of it, e.g. “vtt.danq.me”), at an IP address you’ll get later by creating an “A” record: your domain name registrar can probably help with this – I mostly use Gandi and, ignoring my frustration with recent changes to their email services, I think they’re great
  • An account with a cloud hosting provider: this example uses Linode but you can adapt for any of them
  • A basic level of comfort with the command-line

1. Spin up a server

Getting a virtual server is really easy nowadays.

Annotated screenshot showing a Linode provisioning form, with "Debian 12", the "London, UK", region, and "Dedicated 4GB" plan options selected.
Click, click, click, and you’ve got yourself a server.

You’ll need:

  • The operating system to be Debian 12 (or else you’ll need to adapt the instructions below)
  • The location to be somewhere convenient for your players: pick a server location that’s relatively-local to the majority of them to optimise for connection speeds
  • Approximately 2 CPUs and 4GB of RAM, per Foundry’s recommended server specifications
  • An absolute minimum of 1GB of storage space, I’d recommend plenty more: The Levellers’ campaign currently uses about 10GB for all of its various maps, art, videos, and game data, so give yourself some breathing room (space is pretty cheap) – I’ve gone with 80GB for this example, because that’s what comes as standard with the 2 CPU/4GB RAM server that Linode offer

Choose a root password when you set up your server. If you’re a confident SSH user, add your public key so you can log in easily (and then disable password authentication entirely!).

For laziness, this guide has you run Foundry as root on your new server. Ensure you understand the implications of this.2

2. Point your (sub)domain at it

DNS propogation can be pretty fast, but… sometimes it isn’t. So get this step underway before you need it.

Your newly-created server will have an IP address, and you’ll be told what it is. Put that IP address into an A-record for your domain.

Screenshot from Gandi showing adding an A record for vtt.danq.me -> 1.2.3.4.
The interface for adding a new DNS record in Gandi is pretty simple – record type, time to live, name, address – but it’s rarely more complicated that this with any registrar that provides DNS services.

3. Configure your server

In my examples, my domain name is vtt.danq.me and my server is at 1.2.3.4. Yours will be different!

Connect to your new server using SSH. Your host might even provide a web interface if you don’t have an SSH client installed: e.g. Linode’s “Launch LISH Console” button will do pretty-much exactly that for you. Log in as root using the password you chose when you set up the server (or your SSH private key, if that’s your preference). Then, run each of the commands below in order (the full script is available as a single file if you prefer).

3.1. Install prerequisites

You’ll need unzip (to decompress Foundry), nodejs (to run Foundry), ufw (a firewall, to prevent unexpected surprises), nginx (a webserver, to act as a reverse proxy to Foundry), certbot (to provide a free SSL certificate for Nginx), nvm (to install pm2) and pm2 (to keep Foundry running in the background). You can install them all like this:

apt update
apt upgrade
apt install -y unzip nodejs ufw nginx certbot nvm
npm install -g pm2

3.2. Enable firewall

By default, Foundry runs on port 30000. If we don’t configure it carefully, it can be accessed directly, which isn’t what we intend: we want connections to go through the webserver (over https, with http redirecting to https). So we configure our firewall to allow only these ports to be accessed. You’ll also want ssh enabled so we can remotely connect into the server, unless you’re exclusively using an emergency console like LISH for this purpose:

ufw allow ssh
ufw allow http
ufw allow https
ufw enable

3.3. Specify domain name

Putting the domain name we’re using into a variable for the remainder of the instructions saves us from typing it out again and again. Make sure you type your domain name (that you pointed to your server in step 2), not mine (vtt.danq.me):

DOMAIN=vtt.danq.me

3.4. Get an SSL certificate with automatic renewal

So long as the DNS change you made has propogated, this should Just Work. If it doesn’t, you might need to wait for a bit then try again.

certbot certonly --agree-tos --register-unsafely-without-email --rsa-key-size 4096 --webroot -w /var/www/html -d $DOMAIN

Don’t continue past this point until you’ve succeeded in getting the SSL certificate sorted.

The certificate will renew itself automatically, but you also need Nginx to restart itself whenever that happens. You can set that up like this:

printf "#!/bin/bash\nservice nginx restart\n" > /etc/letsencrypt/renewal-hooks/post/restart-nginx.sh
chmod +x /etc/letsencrypt/renewal-hooks/post/restart-nginx.sh

3.5. Configure Nginx to act as a reverse proxy for Foundry

You can, of course, manually write the Nginx configuration file: just remove the > /etc/nginx/sites-available/foundry from the end of the printf line to see the configuration it would write and then use/adapt to your satisfaction.

set +H
printf "server {\n listen 80;\n listen [::]:80;\n server_name $DOMAIN;\n\n # Redirect everything except /.well-known/* (used for ACME) to HTTPS\n root /var/www/html/;\n if (\$request_uri !~ \"^/.well-known/\") {\n return 301 https://\$host\$request_uri;\n }\n}\n\nserver {\n listen 443 ssl http2;\n listen [::]:443 ssl http2;\n server_name $DOMAIN;\n\n ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;\n ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;\n\n client_max_body_size 300M;\n\n location / {\n # Set proxy headers\n proxy_set_header Host \$host;\n proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto \$scheme;\n\n # These are important to support WebSockets\n proxy_set_header Upgrade \$http_upgrade;\n proxy_set_header Connection \"Upgrade\";\n\n proxy_pass http://127.0.0.1:30000/;\n }\n}\n" > /etc/nginx/sites-available/foundry
ln -sf /etc/nginx/sites-available/foundry /etc/nginx/sites-enabled/foundry
service nginx restart

3.6. Install Foundry

3.6.1. Create a place for Foundry to live

mkdir {vtt,data}
cd vtt

3.6.2. Download and decompress it

Screenshot from FoundryVTT showing where to find the "Timed URL" download link button.
For this step, you’ll need to get a Timed URL from the Purchased Licenses page on your FoundryVTT account.

Substitute in your Timed URL in place of <url from website> (keep the quotation marks – " – though!):

wget -O foundryvtt.zip "<url from website>"
unzip foundryvtt.zip
rm foundryvtt.zip

3.6.3. Configure PM2 to run Foundry and keep it running

Now you’re finally ready to launch Foundry! We’ll use PM2 to get it to run automatically in the background and keep running:

pm2 start --name "Foundry" node -- resources/app/main.js --dataPath=/root/data

You can watch the logs for Foundry with PM2, too. It’s a good idea to take a quick peep at them to check it launched okay (press CTRL-C to exit):

pm2 logs 0

4. Start adventuring!

Screenshot showing FoundryVTT requesting a license key.
Point your web browser at your domain name (e.g. I might go to https://vtt.danq.me) and you should see Foundry’s first-load page, asking for your license key.

Provide your license key to get started, and then immediately change the default password: a new instance of Foundry has a blank default password, which means that anybody on Earth can administer your server: get that changed to something secure!

Now you’re running on Foundry!

Footnotes

1 Which currency you pay in, and therefore how much you pay, for a Foundry license depends on where in the world you are where your VPN endpoint says you are. You might like to plan accordingly.

2 Running Foundry as root is dangerous, and you should consider the risks for yourself. Adding a new user is relatively simple, but for a throwaway server used for a single game session and then destroyed, I wouldn’t bother. Specifically, the risk is that a vulnerability in Foundry, if exploited, could allow an attacker to reconfigure any part of your new server, e.g. to host content of their choice or to relay spam emails. Running as a non-root user means that an attacker who finds such a vulnerability can only trash your Foundry instance.

Screenshot from FoundryVTT, showing a party of three adventurers crossing a rickety bridge through a blood-red swamp, facing off against a handful of fiends coming the other way. A popup item card for a "Dragon Slayer Longsword" is visible, along with two 20-sided dice.× Screenshot from Linode showing a server, "Foundry", running, with specs as described below.× Annotated screenshot showing a Linode provisioning form, with "Debian 12", the "London, UK", region, and "Dedicated 4GB" plan options selected.× Screenshot from Gandi showing adding an A record for vtt.danq.me -> 1.2.3.4.× Screenshot from FoundryVTT showing where to find the "Timed URL" download link button.× Screenshot showing FoundryVTT requesting a license key.×

Woodward Draw

This article is a repost promoting content originally published elsewhere. See more things Dan's reposted.

Screenshot showing a completed game of Woodward Draw; the final word was "goat".

  • Explore the set of 4 letter words
  • Either change one letter of the previous word
  • Or rearrange all the letters of the previous word
  • Find all 105 picture words!

Daniel Linssen (via itch.io)

Woodward Draw by Daniel Linssen is the kind of game that my inner Scrabble player both loves and hates. I’ve been playing on and off for the last three days to complete it, and it’s been great. While not perfectly polished1 and with a few rough edges2, it’s still a great example of what one developer can do with a little time.

It deserves a hat tip of respect, but I hope you’ll give it more than that by going and playing it (it’s free, and you can play online or download a copy3). I should probably check out their other games!

Footnotes

1 At one point the background colour, in order to match a picture word, changed to almost the same colour as the text of the three words to find!

2 The tutorial-like beginning is a bit confusing until you realise that you have to play the turn you’re told to, to begin with, for example.

3 Downloadable version is Windows only.

Have Fun with Missions, Visions, and Values

I just spent a lightweight week in Rome with fellow members of Automattic‘s Team Fire.

Among our goals for the week was an attempt to strengthen the definition of who are team are, what we work on, and how and why we do so. That’s basically a team-level identity, mission, vision, and values, right?

In front of the Colosseum in Rome, Dan - wearing a rainbow-striped bandana atop which his sunglasses are perched - takes a selfie. Behind him stand a man with dark hair and a closely-trimmed beard wearing a purple "woo" t-shirt, a woman with long brown hair wearing beads and a multicoloured dress, a man wearing spectacles and a dark t-shirt on which the number "23" can be made out, and a man in sunglasses with a ginger beard, wearing an open blue shirt.
We were missing two members of our team, but one was able to remote-in (the other’s on parental leave!).

Fellow Automattician Ben Dwyer recently wrote about his experience of using a deck of Dixit cards to help his team refine their values in a fun and engaging way. I own a Dixit set, so we decided to give it a go too.

A deck of Dixit cards, bound by a twisted elastic band, sits on a flight itinerary for the journey "LGW to FCO" taking place on May 21, 2023 and costing $367.60.
The cards sat on my ‘plane tickets for a fortnight because it was just about the only way I’d remember to pack them.

Normally when you play Dixit, you select a card from your hand – each shows a unique piece of artwork – and try to describe it in a way that’s precise enough that some of the other players will later be able to pick it out of a line-up, but ambiguous enough that not all the other players will. It’s a delicate balancing act. Even when our old Geek Night was in full swing we didn’t used to play it often because our well-established group’s cornucopia of  in-jokes and references  made it trivially easy to “target” your descriptions at specific players1, but it’s still a solid icebreaker activity.

A trio of Dixit cards within a grid of nine. From left to right, they show: a heart, on fire, beneath a glass jar; a cubbyhole containing childrens' toys; a fairy leaping from a book towards a small person atop a stack of books.
Can you see your team’s values symbolised in any Dixit cards?

Perhaps it was the fantasy artwork that inspired us or maybe it just says something about how my team sees themselves, but what we came up with had a certain… swords-and-sorcery… even Dungeons & Dragons… feel to it.

Partial screenshot from a document entitled "Team Fire". The visible part is titled "Who we are (identity)" and reads:We are a band of brave adventurers who bring light into the wild forests of Extend. We tame the monsters who lurk in the dungeons beneath the Castle of Vendor Experience. The beasts we keep at bay include: PBS, which helps ensure code quality and extension standards compliance; the Vendor Dashboard, haunt of third-party developers, as well as their documentation and analytics platforms; Integrations with Payments Admin, to ensure that treasure is shared, and other tools.
The projects my team are responsible for aren’t actually monsters, but they can be complex, multifaceted, and unintuitive. And have a high AC.

Ou team’s new identity isn’t finalised, but I love the fact that we’ve been able to inject a bit of fun and whimsy into it. At our last draft, my team looks to be defined as comprising:

  • Gareth, level 62 Pathfinder, leading the way through the wilds
  • Bero, Level 5 Battlesmith, currently lost in the void
  • Dan (me!), Level 5 Arcane Trickster, breaking locks and stealing treasure
  • Cem, Level 4 Dragonslayer, smashing doors and bugs alike
  • Lae, Level 7 Pirate, seabound rogue with eyes on the horizon
  • Kyle, Level 5 Apprentice Bard, master of words and magic
  • Simran, Level 6 Apprentice Code Witch, weaving spells from nature

I think that’s pretty awesome.

Footnotes

1 Also: I don’t own any of the expansion packs and playing with the same cards over and over again gets a bit samey.

2 The “levels” are simply the number of years each teammate has been an Automattician, plus one.

In front of the Colosseum in Rome, Dan - wearing a rainbow-striped bandana atop which his sunglasses are perched - takes a selfie. Behind him stand a man with dark hair and a closely-trimmed beard wearing a purple "woo" t-shirt, a woman with long brown hair wearing beads and a multicoloured dress, a man wearing spectacles and a dark t-shirt on which the number "23" can be made out, and a man in sunglasses with a ginger beard, wearing an open blue shirt.× A deck of Dixit cards, bound by a twisted elastic band, sits on a flight itinerary for the journey "LGW to FCO" taking place on May 21, 2023 and costing $367.60.× A trio of Dixit cards within a grid of nine. From left to right, they show: a heart, on fire, beneath a glass jar; a cubbyhole containing childrens' toys; a fairy leaping from a book towards a small person atop a stack of books.× Partial screenshot from a document entitled "Team Fire". The visible part is titled "Who we are (identity)" and reads:We are a band of brave adventurers who bring light into the wild forests of Extend. We tame the monsters who lurk in the dungeons beneath the Castle of Vendor Experience. The beasts we keep at bay include: PBS, which helps ensure code quality and extension standards compliance; the Vendor Dashboard, haunt of third-party developers, as well as their documentation and analytics platforms; Integrations with Payments Admin, to ensure that treasure is shared, and other tools.×

Nightmares & Noggins

Last night I had a nightmare about Dungeons & Dragons. Specifically, about the group I DM for on alternate Fridays.

In their last session the party – somewhat uncharacteristically – latched onto a new primary plot hook rightaway. Instead of rushing off onto some random side quest threw themselves directly into this new mission.

Four humanoid silhouettes fling themselves off the side of a floating city, which is chained to a desert hellscape below.
They flung themselves not only figuratively but also literally into their new quest, leaping from the side of a floating city.

This effectively kicked off a new chapter of their story, so I’ve been doing some prep-work this last week or so. Y’know: making battlemaps, stocking treasure chests with mysterious and powerful magical artefacts, and inventing a plethora of characters for the party to either befriend or kill (or, knowing this party: both).

I also put together a “cut scene” video welcoming the party into this new chapter of their adventure.

Anyway: in the dream, I sat down to complete the prep-work I want to get done before this week’s play session. I re-checked my notes about what the adventurers had gotten up to last time around, and… panicked! I was wrong, they hadn’t thrown themselves off the side of a city floating above the first layer of Hell at all! I’d mis-remembered completely and they’d actually just ventured into a haunted dungeon. I’d been preparing all the wrong things and now there wasn’t time to correct my mistakes!

Screenshot from donjon's "5e Encounter Size Calculator", configured for a party of four 7th-level characters, with an "extra" checkbox (not found in the real application) for "Can the party Turn Undead?" highlighted.
Also in my dream – conveniently for my new “haunted dungeon” environment – my favourite encounter size calculator included a tool to compensate for a player character who can cast Turn Undead, when making an undead encounter.

This is, of course, an example of the “didn’t prepare for the test” trope of dreams. Clearly I’m still feeling underprepared for this week’s game! But probably a bigger reason for the dream, and remembering it, was that I’ve had a cold and kept waking up to cough.

Right, better do a little more prep work!

Four humanoid silhouettes fling themselves off the side of a floating city, which is chained to a desert hellscape below.× Screenshot from donjon's "5e Encounter Size Calculator", configured for a party of four 7th-level characters, with an "extra" checkbox (not found in the real application) for "Can the party Turn Undead?" highlighted.×

Satoru Iwata’s first commercial game has a secret

This article is a repost promoting content originally published elsewhere. See more things Dan's reposted.

Codex (YouTube)

This was a delightful vlog. It really adds personality to what might otherwise have been a story only about technology and history.

I subscribed to Codex’s vlog like… four years ago? He went dark soon afterwards, but thanks to the magic of RSS, I got notified as soon as he came back from his hiatus.

Beating Children at Mastermind

This blog post is also available as a video. Would you prefer to watch/listen to me tell you about how I’ve implemented a tool to help me beat the kids when we play Mastermind?

I swear that I used to be good at Mastermind when I was a kid. But now, when it’s my turn to break the code that one of our kids has chosen, I fail more often than I succeed. That’s no good!

Black, white, brown, blue, green, orange and yellow Mastermind pegs in a disordered heap.
If you didn’t have me pegged as a board gamer… where the hell have you been?

Mastermind and me

Maybe it’s because I’m distracted; multitasking doesn’t help problem-solving. Or it’s because we’re “Super” Mastermind, which differs from the one I had as a child in that eight (not six) peg colours are available and secret codes are permitted to have duplicate peg colours. These changes increase the possible permutations from 360 to 4,096, but the number of guesses allowed only goes up from 8 to 10. That’s hard.

A plastic Mastermind board in brown and green; it has twelve spots for guessing and shows six coloured pegs. The game has been won on the sixth guess.
The set I had as a kid was like this, I think. Photo courtesy ZeroOne; CC-BY-SA license.

Or maybe it’s just that I’ve gotten lazy and I’m now more-likely to try to “solve” a puzzle using a computer to try to crack a code using my brain alone. See for example my efforts to determine the hardest hangman words and make an adverserial hangman game, to generate solvable puzzles for my lock puzzle game, to cheat at online jigsaws, or to balance my D&D-themed Wordle clone.

Hey, that’s an idea. Let’s crack the code… by writing some code!

Screenshot showing Mastermind game from WebGamesOnline.com. Seven guesses have been made, each using only one colour for each of the four pegs, and no guesses are corect; only red pegs have never been guessed.
This online edition plays a lot like the version our kids play, although the peg colours are different. Next guess should be an easy solve!

Representing a search space

The search space for Super Mastermind isn’t enormous, and it lends itself to some highly-efficient computerised storage.

There are 8 different colours of peg. We can express these colours as a number between 0 and 7, in three bits of binary, like this:

Decimal Binary Colour
0 000 Red
1 001 Orange
2 010 Yellow
3 011 Green
4 100 Blue
5 101 Pink
6 110 Purple
7 111 White

There are four pegs in a row, so we can express any given combination of coloured pegs as a 12-bit binary number. E.g. 100 110 111 010 would represent the permutation blue (100), purple (110), white (111), yellow (010). The total search space, therefore, is the range of numbers from 000000000000 through 111111111111… that is: decimal 0 through 4,095:

Decimal Binary Colours
0 000000000000 Red, red, red, red
1 000000000001 Red, red, red, orange
2 000000000010 Red, red, red, yellow
…………
4092 111111111100 White, white, white, blue
4093 111111111101 White, white, white, pink
4094 111111111110 White, white, white, purple
4095 111111111111 White, white, white, white

Whenever we make a guess, we get feedback in the form of two variables: each peg that is in the right place is a bull; each that represents a peg in the secret code but isn’t in the right place is a cow (the names come from Mastermind’s precursor, Bulls & Cows). Four bulls would be an immediate win (lucky!), any other combination of bulls and cows is still valuable information. Even a zero-score guess is valuable- potentially very valuable! – because it tells the player that none of the pegs they’ve guessed appear in the secret code.

A plastic Mastermind board in blue and yellow with ten guess spaces and eight pegs. The sixth guess is unscored but looks likely to be the valid solution.
If one of Wordle‘s parents was Scrabble, then this was the other. Just ask its Auntie Twitter.

Solving with Javascript

The latest versions of Javascript support binary literals and bitwise operations, so we can encode and decode between arrays of four coloured pegs (numbers 0-7) and the number 0-4,095 representing the guess as shown below. Decoding uses an AND bitmask to filter to the requisite digits then divides by the order of magnitude. Encoding is just a reduce function that bitshift-concatenates the numbers together.

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
 * Decode a candidate into four peg values by using binary bitwise operations.
 */
function decodeCandidate(candidate){
  return [
    (candidate & 0b111000000000) / 0b001000000000,
    (candidate & 0b000111000000) / 0b000001000000,
    (candidate & 0b000000111000) / 0b000000001000,
    (candidate & 0b000000000111) / 0b000000000001
  ];
}

/**
 * Given an array of four integers (0-7) to represent the pegs, in order, returns a single-number
 * candidate representation.
 */
function encodeCandidate(pegs) {
  return pegs.reduce((a, b)=>(a << 3) + b);
}

With this, we can simply:

  1. Produce a list of candidate solutions (an array containing numbers 0 through 4,095).
  2. Choose one candidate, use it as a guess, and ask the code-maker how it scores.
  3. Eliminate from the candidate solutions list all solutions that would not score the same number of bulls and cows for the guess that was made.
  4. Repeat from step #2 until you win.

Step 3’s the most important one there. Given a function getScore( solution, guess ) which returns an array of [ bulls, cows ] a given guess would score if faced with a specific solution, that code would look like this (I’m convined there must be a more-performant way to eliminate candidates from the list with XOR bitmasks, but I haven’t worked out what it is yet):

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/**
 * Given a guess (array of four integers from 0-7 to represent the pegs, in order) and the number
 * of bulls (number of pegs in the guess that are in the right place) and cows (number of pegs in the
 * guess that are correct but in the wrong place), eliminates from the candidates array all guesses
 * invalidated by this result. Return true if successful, false otherwise.
 */
function eliminateCandidates(guess, bulls, cows){
  const newCandidatesList = data.candidates.filter(candidate=>{
    const score = getScore(candidate, guess);
    return (score[0] == bulls) && (score[1] == cows);
  });
  if(newCandidatesList.length == 0) {
    alert('That response would reduce the candidate list to zero.');
    return false;
  }
  data.candidates = newCandidatesList;
  chooseNextGuess();
  return true;
}

I continued in this fashion to write a full solution (source code). It uses ReefJS for component rendering and state management, and you can try it for yourself right in your web browser. If you play against the online version I mentioned you’ll need to transpose the colours in your head: the physical version I play with the kids has pink and purple pegs, but the online one replaces these with brown and black.

Testing the solution

Let’s try it out against the online version:

As expected, my code works well-enough to win the game every time I’ve tried, both against computerised and in-person opponents. So – unless you’ve been actively thinking about the specifics of the algorithm I’ve employed – it might surprise you to discover that… my solution is very-much a suboptimal one!

A young boy sits cross-legged on the floor, grinning excitedly at a Mastermind board (from the code-maker's side).
My code has only failed to win a single game… and that turned out to because my opponent, playing overexcitedly, cheated in the third turn. To be fair, my code didn’t lose either, though: it identified that a mistake must have been made and we declared the round void when we identified the problem.

My solution is suboptimal

A couple of games in, the suboptimality of my solution became pretty visible. Sure, it still won every game, but it was a blunt instrument, and anybody who’s seriously thought about games like this can tell you why. You know how when you play e.g. Wordle (but not in “hard mode”) you sometimes want to type in a word that can’t possibly be the solution because it’s the best way to rule in (or out) certain key letters? This kind of strategic search space bisection reduces the mean number of guesses you need to solve the puzzle, and the same’s true in Mastermind. But because my solver will only propose guesses from the list of candidate solutions, it can’t make this kind of improvement.

Animation showing how three clues alone are sufficient to derive a unique answer from the search space of the original "break into us" lock puzzle.
My blog post about Break Into Us used a series of visual metaphors to show search space dissection, including this one. If you missed it, it might be worth reading.

Search space bisection is also used in my adverserial hangman game, but in this case the aim is to split the search space in such a way that no matter what guess a player makes, they always find themselves in the larger remaining portion of the search space, to maximise the number of guesses they have to make. Y’know, because it’s evil.

Screenshot showing a single guess row from Online Mastermind, with the guess Red, Red, Green, Green.
A great first guess, assuming you’re playing against a random code and your rules permit the code to have repeated colours, is a “1122” pattern.

There are mathematically-derived heuristics to optimise Mastermind strategy. The first of these came from none other than Donald Knuth (legend of computer science, mathematics, and pipe organs) back in 1977. His solution, published at probably the height of the game’s popularity in the amazingly-named Journal of Recreational Mathematics, guarantees a solution to the six-colour version of the game within five guesses. Ville [2013] solved an optimal solution for a seven-colour variant, but demonstrated how rapidly the tree of possible moves grows and the need for early pruning – even with powerful modern computers – to conserve memory. It’s a very enjoyable and readable paper.

But for my purposes, it’s unnecessary. My solver routinely wins within six, maybe seven guesses, and by nonchalantly glancing at my phone in-between my guesses I can now reliably guess our children’s codes quickly and easily. In the end, that’s what this was all about.

Black, white, brown, blue, green, orange and yellow Mastermind pegs in a disordered heap.× A plastic Mastermind board in brown and green; it has twelve spots for guessing and shows six coloured pegs. The game has been won on the sixth guess.× Screenshot showing Mastermind game from WebGamesOnline.com. Seven guesses have been made, each using only one colour for each of the four pegs, and no guesses are corect; only red pegs have never been guessed.× A plastic Mastermind board in blue and yellow with ten guess spaces and eight pegs. The sixth guess is unscored but looks likely to be the valid solution.× A young boy sits cross-legged on the floor, grinning excitedly at a Mastermind board (from the code-maker's side).× Screenshot showing a single guess row from Online Mastermind, with the guess Red, Red, Green, Green.×