Inspiration

I don’t remember the exact sequence of events that resulted in this idea, but it was spawned in some way from doing Advent of Code in December 2024. While solving one of those problems, part of my brain started wondering what it would be like to solve a grid of letters, and I started ideating.

(After solving that day’s puzzle, of course.)

Process

I already had Norwegian word lists, so I was able to jump straight into building the game, more or less.

Building

I wanted it to be fairly similar to my other games:

  • Live entirely in the browser
  • Work offline

This meant I was able to leverage the infrastructure & learnings from my other games and bootstrap a React-based prototype rather quickly. Of course, that resulted in the challenge of the actual game.

The process of puzzle creation drew from my experience with Bokstavboks.

  1. Start by filling an NxM grid with random1 letters
  2. Filter the dictionary to just words which are longer than the longest side of the grid .. but no longer than double that length. For example:
    • 4x4 grid: 5 ≤ word length < 8
    • 5x6 grid: 7 ≤ word length < 12
  3. Pseudo-randomly pick a word from this list of long-but-not-too-long words
  4. Squish it into the grid

At this point, we have a grid of letters which is guaranteed to be spannable with one word. However, this may not be the shortest solution.

To answer that, we take the grid and feed it back into a solver to determine the shortest possible solution.

Launching

Once the game prototype reached some level of plausibility, I went out and bought ordlabyrint.no and got ready for using my now-standard GitHub Pages hosting.

Reflections

I’m surprised at how fun I find the game. At the 4x4 size, the puzzles are quick and often easy – though I do get stumped from time to time. However, the 5x5 puzzles are a step up, and 6x6 are quite a bit harder.

From a construction perspective, this introduced some fun graph-traversal questions. I originally started with an A* solver, and wound up with a crazy hacked-up implementation before I realized that A* isn’t really appropriate for this.

I started with the A* implementation having “weights” where going from one letter to another letter would be 1000x more costly if a new word was started. However, this resulted in a lot of state needing to be tracked, and it got really messy. Another source of messiness was the notion that there are multiple “goals” – which are dynamic based on the path taken!

In the end, I threw all of that away and used a breadth-first search (BFS) algorithm. In the end, it was much faster to run the BFS on each possible start node and choose the best answer than it was to try and have a crazy A*-inspired search. This became especially true when I introduced the guarantee that every puzzle is solvable with one word, since my BFS now no longer needed to handle multiple words and could early-return.


  1. Not really “random”, of course. These are pseudo-randomly generated so that the grid is repeatable. Additionally, these letters are weighted by the actual distribution of letters in the given word bank. ↩︎