26 September 2015 —
A walk-through of the author's word search puzzle generator
My daughter (age 11) was writing an article this week for a local student newsletter, and had the idea to include a word search puzzle. After spending ten minutes looking online and being fairly disappointed in the quality of what we found, I decided to take a stab at writing a word search puzzle generator myself.
I mean, how hard could it be?
Fortunately for me it wasn’t too hard at all, though I’m sure my implementation is far from optimal. It generates puzzles that look like this:
(Bonus: the letters left after finding all the words spell out one of my favorite features of Ruby…)
The core of the algorithm (after deciding on the word list and the size of the puzzle grid) is just this:
Pick the next word in the list.
Add it to a random location in the grid.
If the word fails to fit anywhere on the grid, backtrack and try from step #2 with the previous word.
If there is no previous word, fail (because the words cannot all fit on the grid).
Once the word has been placed successfully, repeat from step #1.
Once all words have been placed, fill in the unused squares with random letters.
The first thing to do was to represent the grid itself. Visually, it’s a two-dimensional grid of rows and columns:
Since the algorithm requires that I be able to try a word against every possible location in the grid, I chose to implement the grid as a one-dimensional array. This way I can represent each location as a single integer, which is cleaner than trying to juggle (row, column) tuples.
It also makes it really easy to duplicate the grid, so that the state of the grid can be saved and restored as the algorithm backtracks:
The algorithm itself begins by initializing a list of possible directions that each word might be drawn in (right-to-left, top-to-bottom, etc.), as well as building a list of all possible positions in the grid:
I could implement this algorithm via recursive function calls, but I opted to use a stack, instead. I initialize it like this (words is the list of vocabulary words that will be used to build the puzzle):
Each stack element remembers the current state of the grid, the word that is currently being placed on the grid, the list of possible directions that haven’t yet been tried, and the list of possible positions that haven’t yet been tried.
Once all of that’s ready, the algorithm itself runs in a loop:
That _try_word method isn’t too magical:
Once all of the words have been placed, we just fill in the unused squares with random letters:
All that’s left, then, is to display the puzzle:
Given a vocabulary list of “mazes,” “word,” “search,” “puzzle,” “games,” and “program,” and a 7x7 grid, our puzzle might look something like this:
(For this puzzle, the words are drawn in all possible directions: forwards, backwards, and diagonally.)
The version I wrote for my daughter actually emits the puzzles as PDF (so that she could embed them in her article). If you’d like to check it out, it’s hosted on GitHub here: http://github.com/jamis/wordsearch.