I built a small solver for the New York Times Connections puzzle. Not because the world needed one, but because the puzzle turns out to be a near-perfect toy for thinking about what similarity search, language embeddings, and NLP actually are. The code lives here: github.com/jrmcauliffe00/nyt-connections-solver, built lesson by lesson as a pair of Jupyter notebooks.
If you have not played it: Connections gives you 16 words and asks you to split them into 4 groups of 4, where each group shares some hidden theme. The catch is that the puzzle is designed so words look like they belong to several groups at once. Those red herrings are the whole game — and, as it happens, the whole problem in natural language processing.
The Idea: Meaning as Geometry
The philosophical premise underneath modern NLP is deceptively simple: you can turn meaning into geometry. An embedding model reads a word (or phrase) and returns a vector — a point in a few hundred dimensions of space — positioned so that things which mean similar things land near each other. "Glad" sits close to "merry"; "trout" sits close to "salmon"; "Jupiter" sits close to "Saturn."
This is the distributional hypothesis in action: you shall know a word by the company it keeps. The model never gets a dictionary definition. It learns geometry from context, seen across billions of sentences, and "similarity" becomes something you can literally measure with a ruler. In this case the ruler is cosine similarity — the angle between two vectors. Small angle, similar meaning.
Connections is the ideal test bed for that claim. If meaning really is geometry, then the four hidden groups should show up as four tight clusters of points. Solving the puzzle becomes: find the arrangement of 16 points into 4 clusters that is geometrically the cleanest.
Part 1: Embed, Compare, Search
The first notebook is the thinnest version that works end to end. The pipeline is four steps:
- Embed. Load a pretrained Hugging Face model (
all-MiniLM-L6-v2, ~80MB, runs happily on a laptop) and turn each of the 16 words into a 384-dimension unit vector. No training, no dataset — the meaning is already baked into the downloaded model. - Compare. Because the vectors are normalized to length 1, a single matrix multiply produces the full 16×16 cosine-similarity matrix: entry
[i, j]is how related word i is to word j. - Score. Define a group's cohesion as the average similarity across its 6 internal word-pairs. A tight, on-theme group scores high; a mixed bag scores low.
- Search. Find the 4-4-4-4 split that maximizes total cohesion.
That last step sounds scary but is refreshingly dumb. There are only
C(16,4) = 1,820 possible groups of four, and about 2.6 million ways to
partition 16 words into four unlabeled groups. That is small enough to just
enumerate every partition, score it, and keep the best. No k-means, no
cleverness — a brute-force search that is guaranteed to find the global optimum for whatever
scoring function you hand it. The solver then presents its groups most-confident-first,
mimicking how a human plays their surest guess before spending a mistake.
On a clean, meaning-based puzzle — happy synonyms, fish, planets, dog breeds — this simple
approach does genuinely well. The first notebook even swaps in a couple of stronger small
embedders (BGE-small, GTE-small) behind the same interface and
compares them with similarity heatmaps and a "separation score" (within-group similarity
minus between-group similarity). When a model is good, you can literally see four bright
4×4 blocks glowing down the diagonal of the heatmap. Meaning, made visible.
The Wall: One Word, Many Meanings
Then the philosophy bites back. Give a word like BASS a single vector and the
model is forced to average all of its meanings — a fish, a low musical note, a guitar — into
one compromise point that sits nowhere in particular. PERCH (a fish, or to sit
on a ledge), BOXER (a dog, a fighter, an item of underwear), SALMON
(a fish, or a color): every one of them gets smeared across meanings.
This is polysemy, and it is exactly the weapon Connections uses against you. The puzzle deliberately picks words whose alternate senses pull them toward the wrong group. A single vector per word has no way to say "in this context I mean the fish." The geometry that made the easy puzzle trivial is the same geometry that collapses on the hard one.
Part 2: Give Each Word Its Senses Back
The second notebook fixes this with a small, satisfying move. Instead of one vector per
word, give each word a short list of candidate senses, written as
disambiguating phrases — "bass, a type of fish",
"bass, a low, deep musical sound", "bass, an electric bass guitar"
— and embed each sense separately. A word is now represented by a little set of
points instead of one blurry average.
The scoring adapts accordingly. When evaluating a candidate group of four, the solver tries
every combination of one-sense-per-word (at most 3×3×3×3 = 81 combinations) and
keeps the one that makes the group most cohesive. In other words, each group is allowed to
choose the interpretation of each word that fits it best. The Fish group reaches for
the fish sense of BASS; the Dog group reaches for the breed
sense of BOXER. Everything downstream — the exhaustive partition search — stays
exactly the same; only the meaning of "how related are these words" got smarter.
The payoff is that the solver can now explain itself: it reports which sense it
chose for each word in each group. Watching PERCH resolve to the fish and
BOXER to the dog is the moment the whole "meaning as geometry" idea clicks —
context is what selects a point out of the cloud.
Why This Is a Good Way to Think About NLP
The honest limitation is that Part 2's sense lists are hand-written, which does not scale to an arbitrary puzzle. The natural next lesson (Part 3) is to let an LLM generate the candidate senses automatically — which closes the loop nicely: an LLM proposes the possible meanings, embeddings place them in space, and a dumb-but-optimal search picks the arrangement that holds together. Three different tools, each doing the one thing it is good at.
That layering is really the lesson. Similarity search gives you a measurable notion of "close." Embeddings are the bridge that turns language into something you can measure. And the hard part — the part Connections is built to exploit — is that meaning is contextual, so a single point is never quite enough. Building a toy solver made those ideas concrete in a way no diagram ever did.
The full notebooks, the plan, and the reasoning behind each decision are on GitHub: jrmcauliffe00/nyt-connections-solver. Clone it, paste in today's puzzle, and watch meaning turn into geometry.