Some puzzle-crafters are able to do amazing work by hand. I am not among their number. Instead, I rely on a program I wrote to verify that the puzzle has a unique solution. Consider the following puzzles:
This one has cages filled with letters in a way that violates the rule that each row has exactly the letters in the bank.
This one has two possible solutions that there’s no way to tell apart.
Good luck finding a word with three Qs, three Xs, three Zs, and no other consonants! (Also, like the last puzzle, there’s not a unique placement.)
I don’t want to generate puzzles like these, and when the puzzles get bigger and tougher, I don’t trust my own evaluatory ability to guarantee that that won’t happen. Fortunately, I didn’t have to rely solely on my feeble human intellect to make this puzzle:
To avoid the myriad pitfalls of puzzle-making with insufficient skill, I used z3, a theorem-proving system out of Microsoft Research1. When I design a puzzle, I claim that, given for each cage an unordered list of consonants in it, there exists a way of filling the grid such that each cage has the proper letters in it, and that each row and each column have exactly the letters of the letter pool. Moreover, I claim that that configuration is unique: that is, that if I try to find a different placement of the letters onto the grid, I will fail. My input to z3 is the shapes of the cages and the letters in each, and my output is the unique placement of letters on the grid or a notification that a unique placement does not exist.
If a certain assignation of letters to cages doesn’t work, the program will reroll and try again with a different assignation. Hopefully one of these will work, but even if it doesn’t, I’ll figure out that I probably made a bad grid and start from scratch. If I do get a valid letter placement, though, I’m still a ways away from having a finished puzzle, and unfortunately the NP-complete-tackling marvel of z3 can’t carry me any further. But computers are pretty handy tools, and I can still get some help!
Once I have a letter assignation to cages that results in a unique placement on the grid, my program draws the solution and for each cage, offers me a list of answers (drawn from a pretty extensive crossword answer database I downloaded) that could fit. It’s possible that while there do exist words using exactly a cage’s assigned letters, none of them are a good fit. (This is especially likely if I’m trying to make the puzzle themed.) The puzzle might be technically solvable, but it won’t be good. In that case, I can start over the regeneration, just as would happen automatically if the assignation failed to yield a good grid.
When I accept a grid, my program prompts me to choose an answer for each cage and to provide a clue for that answer:
At the end, I get a nice, detailed specification file with the cage shapes, the solution placement, and the clues and answers for the cages:
mrst
0,0,1,1
0,2,2,1
0,3,2,2
0,3,2,4
S,T,M,R
M,S,R,T
R,M,T,S
T,R,S,M
0|SMATTER|A small amount, as of applause|4
1|TUMOR|Uncontrolled growth|2
2|SISTERS|Best of friends and worst of enemies|1
3|RIME|Frost that limns|0
4|IMO|In my opinion, a challenging math competition?|3
Because I apparently had decided that I had had enough of computers being helpful and wanted to experience the awfulness of using them, for a long time, I then used my word processor2 to turn this sort of configuration into a nicely formatted puzzle like you see up above. This entailed adjusting the thickness of individual cell borders and wrangling the confusion of columns.
After a concerningly long time of stubbornly making puzzles this way, I decided that it was time for a change, and in the course of a major refactor of my program, I added typesetting. Those of you who’ve been in academic math or CS will no doubt groan at the mention of LaTeX3, but I actually think this is the perfect place for it. I have procedurally-generated material that I need formatted into a typeset template in a pretty precise manner, so why not use the typesetting programming language?
Answer: Because LaTeX is horrible to work with. I’m sure some of this is a skill issue; I hadn’t used LaTeX for years, was never too experienced with it anyhow, and I was trying to do the formatting in a not-maximally LaTeX-y manner by writing a file of LaTeX code rather than… I don’t know what, I’m not a LaTeX guru4. Anyhow, LaTeX has some very strong opinions about how documents should look—as much as possible like academic papers—that didn’t agree with how I wanted my puzzles to look. The way I had been making the grid out of a table was right out: LaTeX knows how tables should look and it will not be swayed to my unscientific “square cells” and “variable-point borders”. Fortunately, I could just draw a shape out of lines. The final LaTeX is tolerable to work with:
\documentclass[12pt]{article}
\usepackage{tikz}
\usepackage[inline]{enumitem}
\usepackage{setspace}
\usepackage{geometry}
\usepackage{multicol}
\usepackage{fdsymbol}
\usepackage[dvipsnames]{xcolor}
\geometry{letterpaper, left=2cm, right=2cm, top=1.5cm, bottom=1.5cm}
\pagenumbering{gobble}
\title{Sample letter puzzle}
\author{euclid11}
\date{September 2024}
\begin{document}
\begin{center}
\begin{tikzpicture}
\draw[step=2.5cm, color=gray, line width=0.8] (0,0) grid (10, 10);
\draw[line width=2.0] (0.0, 10.0) -- (0.0, 7.5) -- (0.0, 5.0) -- (0.0, 2.5) -- (0.0, 0.0) -- (2.5, 0.0) -- (2.5, 2.5) -- (2.5, 5.0) -- (2.5, 7.5) -- (5.0, 7.5) -- (5.0, 10.0) -- (2.5, 10.0) -- cycle;
\draw[line width=2.0] (5.0, 10.0) -- (5.0, 7.5) -- (7.5, 7.5) -- (7.5, 5.0) -- (10.0, 5.0) -- (10.0, 7.5) -- (10.0, 10.0) -- (7.5, 10.0) -- cycle;
\draw[line width=2.0] (2.5, 7.5) -- (2.5, 5.0) -- (5.0, 5.0) -- (5.0, 2.5) -- (5.0, 0.0) -- (7.5, 0.0) -- (7.5, 2.5) -- (10.0, 2.5) -- (10.0, 5.0) -- (7.5, 5.0) -- (7.5, 7.5) -- (5.0, 7.5) -- cycle;
\draw[line width=2.0] (2.5, 5.0) -- (2.5, 2.5) -- (2.5, 0.0) -- (5.0, 0.0) -- (5.0, 2.5) -- (5.0, 5.0) -- cycle;
\draw[line width=2.0] (7.5, 2.5) -- (7.5, 0.0) -- (10.0, 0.0) -- (10.0, 2.5) -- cycle;
\node[anchor=north west] at (0.0, 10.0) [node contents={\small 1}];
\node[anchor=north west] at (5.0, 10.0) [node contents={\small 2}];
\node[anchor=north west] at (2.5, 7.5) [node contents={\small 3}];
\node[anchor=north west] at (2.5, 5.0) [node contents={\small 4}];
\node[anchor=north west] at (7.5, 2.5) [node contents={\small 5}];
\end{tikzpicture}
\end{center}
\begin{center}
{\Huge Rules}
\end{center}
\begin{enumerate}[noitemsep]
\item Each row and column must have exactly one of each of the following letters:
\par
\end{enumerate}
{\centering \textbf{\large
M R S T} \par}
\begin{enumerate}[noitemsep]
\setcounter{enumi}{1}
\item The letters in each outlined cage of squares constitute the missing consonants in the answer to the corresponding numbered template.
\item The order of the letters in the answer to a template is unrelated to the order they are placed in the corresponding cage.
\item If an answer has a repeated consonant, it will appear that many times in its cage.
\item Each template is the answer to a different clue from the bank at the bottom, and has one consonant in each blank. Clues are in a random order.
\end{enumerate}
\begin{center}
{\Huge Templates and Clues}
\begin{multicols}{2}
\raggedcolumns
\begin{enumerate}[itemsep=2pt]
\item \rule{3mm}{0.5pt} \rule{3mm}{0.5pt} A \rule{3mm}{0.5pt} \rule{3mm}{0.5pt} E \rule{3mm}{0.5pt}
\item \rule{3mm}{0.5pt} U \rule{3mm}{0.5pt} O \rule{3mm}{0.5pt}
\item \rule{3mm}{0.5pt} I \rule{3mm}{0.5pt} \rule{3mm}{0.5pt} E \rule{3mm}{0.5pt} \rule{3mm}{0.5pt}
\item \rule{3mm}{0.5pt} I \rule{3mm}{0.5pt} E
\item I \rule{3mm}{0.5pt} O
\end{enumerate}
\end{multicols}
\begin{itemize*}[itemjoin={\:}]
\item[$\smallblackdiamond$] Frost that limns
\item[$\smallblackdiamond$] Best of friends and worst of enemies
\item[$\smallblackdiamond$] Uncontrolled growth
\item[$\smallblackdiamond$] In my opinion, a challenging math competition?
\item[$\smallblackdiamond$] A small amount, as of applause
\end{itemize*}
\end{center}
\end{document}
There’s some more refinement in the typesetting that I haven’t yet gotten around to. For instance, in LaTeX, you need to write left quote marks and right quote marks differently. But there are quite a few more changes and improvements I still want to make to my puzzle generation process. Some of these will be internal improvements (perhaps I could compile the LaTeX myself?), but others will open up new variants and improvements for solvers. I hope you all see improvement with me!
WARNING: Things will get more technical from here in this post.
Usually Apple’s Pages, but sometimes Google Docs, which formats differently in all sorts of minor and annoying ways.
For those unfamiliar, yes, that is how it’s styled.
At a guess, templates? Would those let me essentially write LaTeX functions? Would that even be nicer than just procedurally generating static TeX code?