UYLLII

Blog › Engineering

Engineering

Building a word search generator in TypeScript (where every word appears exactly once)

By David4 min read
Word Search feature graphic

A word search looks like the easiest puzzle in the world to generate. Put the words in a grid, fill the gaps with random letters, done. I wrote that version in an hour. Then I found the bug that version always has, and the generator in Word Search grew into something more careful.

The stack

A quick note on the tech, since every game in this blog shares it:

A web stack on Android has a reputation for feeling cheap. In my experience it's fine for puzzle games, as long as you respect the phone (more on battery in a much later post). The upside is that every game also runs in a browser, which makes testing on a real phone trivial.

Seeded and deterministic

Every puzzle comes from a string seed:

The same seed builds the same grid on every phone. That gives me a shared daily puzzle with no server, levels that survive reinstalling, and bug reports I can reproduce exactly.

Placing words

The generator places the longest words first, because they're hardest to fit. For each word it tries candidate positions in all allowed directions and scores them, with a bias towards spots that overlap letters already on the grid. Overlaps make a grid feel hand-made and dense rather than words floating in noise.

It also skips word pairs where one contains the other. If the list has both CAT and CATERPILLAR, finding CAT inside CATERPILLAR is ambiguous, so one of them goes.

If a layout can't fit the words, it retries with a new sub-seed (seed#attempt), up to 40 times, and only then drops a word.

Filler letters that look like the language

Uniform random filler looks wrong. A grid full of Q, X and Z is visibly fake, and it makes the real words jump out. So filler letters are drawn by letter frequency for that language. Spanish grids get lots of E, A and O. Each language also has a fold() function for accents, so a player's swipe across "É" matches an "E" in the word list where that language treats them as the same letter.

The bug every simple generator has

Here it is. You place SEAL. Then you fill the remaining cells with random letters, and somewhere else in the grid the filler happens to spell S-E-A-L diagonally. Now the word is in the grid twice. A player finds the "wrong" one, swipes it, and the game says no. To the player the game is broken, and they're right.

With short words and dense grids this isn't rare. Three- and four-letter words turn up by accident all the time, backwards as well.

The fix is a repair pass. After filling, the generator scans the grid in all eight directions for every placed word. If it finds an extra occurrence that uses at least one filler cell, it redraws those filler cells and checks again. If the extra occurrence is made entirely of letters from placed words (it happens with crossings), filler can't fix it, so the whole layout is rerolled. Palindromes like LEVEL need special handling, because the forward and backward readings are the same word.

The guarantee is simple to state: every word appears exactly once, in any direction. The test suite proves it by building about 4,700 puzzles across all languages and difficulties and checking each one.

The difficulty curve

Generation is only half the job. The other half is deciding what to generate. The journey starts tiny and generous so the first minute is all success:

The biggest grid is 12×12. There's also a "big letters" setting that caps grids at 9×9 for older eyes. It turned out to be one of the most useful things in the game, and I didn't mention it in the store listing for months. Lesson noted.

Content rating starts in the word list

One thing I didn't expect: the content rating depends on the word lists. Google Play's IARC questionnaire asks about alcohol, sexual content and violence. A grid that can contain BEER, or a "body" theme with the wrong words, changes the honest answers. So before the first submission I went through every theme in every language and took those words out. It's a small job, and it's easier than explaining a mature rating on a word search.

Word Search screenshot 1Word Search screenshot 2Word Search screenshot 3
Word Search on Android.

Next: Spider Solitaire, the first game forked from this engine, and the first card game.