Wordle Solver
A neural network that taught itself to play Wordle, in a simulator I built.
I went through a stretch of being a bit obsessed with Wordle, and at some point I started wondering how good cheating could actually get. How good could I make a system that plays it for me, and how many tries would it need on average?
Wordle gives you six tries to find a hidden five-letter word. After each try the game colours every letter: right letter in the right place, right letter in the wrong place, or not in the word at all. The picture above is one game, with a word I picked myself.
I didn't want to write the strategy by hand. I wanted to see whether a computer could learn to play without anyone teaching it one. So I built a small copy of the game and let a neural network, which is a program that adjusts itself from experience, play it more than a hundred thousand times. The only teaching was a score. It got points for guesses that ruled out lots of words, a bonus for winning, and a big penalty for losing.
One rule I gave it is a restriction a normal player does not have. It can only guess words that still fit everything it has seen so far. It is a bit like twenty questions where every question has to be a real attempt at the final answer. It is a stricter version of what Wordle calls hard mode.
It worked, mostly. I trained two versions. The first won somewhere between 39 and 48 of every 50 practice games I tested it on, depending on how far into training I looked. The second, a different network with a few other changes, won about 48 of 50 on average, and twice won all 50. It needed a little over four guesses per game, counting a loss as six.
Those practice games came from the same list of 2,344 answers it trained on, and I never tried a plain baseline, like picking any word that still fits at random. So I can't say how much of this is the learning and how much is the hard-mode rule doing the work.
Some of it didn't work. The second version is called the attention version because I meant it to learn how words relate to each other. The run that produced those numbers doesn't actually use that part. When I trained the full attention version separately, it ran for about 4,000 steps without winning a single game, and that was the end of it. The two versions also differ in several ways at once, so I can't tell you which change helped.
I also wrote a script that opens a Wordle site in a browser, types in the network's guesses and reads the colours back, and a couple of plain word filters with no learning in them.
I ran that script on an unlimited-Wordle site, where you can keep starting new games, and I did it quite a lot. As I remember it, it solved a game in about three or four guesses on average, sometimes in two, and I don't think it ever lost. That is my memory of it, not a count I kept.
What's next. What this needs is a fair test: answers it never trained on, a simple baseline to beat, and one change at a time between the two versions. I'd also like to run the browser script for a set number of games and write down the real result, so it doesn't rest on my memory. If I come back to it, that comes before anything fancier.
What I wanted
I got a bit obsessed with Wordle and started wondering how good cheating could be: how strong I could make the system, and how many guesses it would need on average. I wanted an agent that picks its guesses from the colour feedback alone, trained entirely in a simulator, and then I wanted to see whether the same agent could play a real site. The training runs are from 26 and 27 November 2025.
How it works
A Gymnasium environment picks a random target from a list of 2,344 answers. The agent picks one of 16,132 allowed guesses, and the environment returns the green, yellow and gray feedback. What the agent sees is a grid of 26 letters by 5 positions by 3 states (unknown, not here, confirmed), plus how many guesses it has used and what fraction of the word list is still possible. v2 adds the previous guesses as 30 more numbers: 6 guesses of 5 letters each.
Training uses MaskablePPO from sb3-contrib. The mask removes every word that contradicts the feedback so far, so the agent never has to learn the rules, only which allowed word is a good pick.
What is PPO?
Proximal Policy Optimization, a standard way to train a policy by trial and error. The agent plays a batch of games, works out which guesses led to better scores than expected, and nudges the network towards them. A clip stops any single update from changing the network too much, so one bad batch can't undo everything it has learned.
What is an action mask?
A list that tells the agent which of its 16,132 options are allowed right now. Mine switches off every word that contradicts the feedback so far. It also means the agent always plays a stricter version of Wordle's hard mode: every guess has to be a word that could still be the answer, so it can never spend a guess just to test some letters.
The reward is made of a few parts. Each guess earns 2 points per bit of information it gains, meaning how far it shrinks the list of words that still fit, plus 0.5 per green and 0.2 per yellow. A win pays 50 plus 5 for each guess left unused. A loss costs 500. That penalty is deliberately huge: the mode in my environment is called safety first, and the idea was that the agent should never lose. v2 keeps the same numbers and adds an extra 3 times the information gain on the first guess.
What is a bit of information?
One bit halves the number of possibilities. A guess that takes 16,132 candidate words down to 44 gains about 8.5 bits, because 16,132 divided by 44 is about 367, which is roughly 2 multiplied by itself 8.5 times. The environment counts these bits over the 16,132 allowed guesses, not over the 2,344 answers.
v2 swaps the network for one that starts with a state encoder (three small branches for the letter grid, the guess count and the guess history, joined into 256 numbers) followed by 256 and 128 unit layers, keeps the same mask and reward shape, and adds four reward modes and code for ensembles and for looking at attention. v1 is a plain 3-layer network of 256, 256 and 128 units for both policy and value.
Around the agent there are a few small tools. One is a script that opens an unlimited-Wordle site in a browser with Playwright, lets the model pick a word, types it in, and reads each tile's state from the page. If the site doesn't know the word it masks it and asks the model again, which matters because my guess list is much looser than a real game's: it has obscure words and names in it. Another is a helper where I type in the colours from a real game and the model suggests a word. The last two are plain solvers with no learning. The first is an interactive candidate filter with a letter-frequency suggestion (December 2025). The second (February 2026) is built around the colour rows of someone else's guesses, where I can see the colours and not the letters, and keeps the answers that some allowed guess could have produced.
How well it plays
While training, each run evaluated itself every so often: 12 evaluations of 50 games, with the model playing its best guess every time and no exploration. A game counts as won when its reward ends up positive, and that is unambiguous here: every win in these evaluations scored between about 82 and 144, and every loss between about minus 471 and minus 435.
Each point is one evaluation of 50 games. v1 was evaluated every 40k steps up to 480k and v2 every 80k up to 960k. The two runs differ in more than the architecture.
| Run | Wins, all evals | Mean guesses | Last eval |
|---|---|---|---|
| v1, MLP | 532/600 | 4.79 | 42/50, 5.08 |
| v2, 1M-step run | 576/600 | 4.33 | 50/50, 3.98 |
Mean guesses count a loss as 6. v2 was best late in training, but it won 50 of 50 twice and 45 of 50 once, so a single point at 50 games is noise. The win rate during training agrees: measured over the last 100 games with exploration still on, it averaged about 83% for v1 and about 95% for v2 across the last ten readings. Training took about 50 minutes for v1 and about an hour and three quarters for v2.
There is no baseline in the same masked environment, for example a random consistent word or the letter-frequency suggester, so these numbers don't show how much the learning itself adds on top of the mask.
I ran the browser script on an unlimited-Wordle site quite a bit. From memory it averaged about 3 to 4 guesses a game, now and then got the word in 2, and I think it never lost. I didn't record those games, so treat that as an impression and not a result.
What didn't work
The comparison between v1 and v2 is not clean. v2 differs in features, reward (the opener bonus), network shape, learning rate (0.001 against v1's 0.0003) and training length (about a million steps against about half a million), and it ran 16 games in parallel. I never changed one thing at a time. At 480k steps, where v1 stopped, v2 was already ahead in these evaluations, 48 of 50 against 42. v1 peaked at 48 of 50 at 320k and slid back from there, so more training did not obviously help it.
I set v2 up with a learning-rate schedule, but the rate stayed at 0.001 the whole run, so the schedule did nothing.
The attention model is also not attention over words in that run. The attention version was meant to match a query from the game state against embeddings of all 16,132 words, with the mask left off so that it learns the rules itself. The run I'm showing numbers for only uses the state encoder, and it does use the mask. The real word attention lives in a separate training loop, and that loop ran for about 4,000 steps and never won a game: every game ran to six guesses, and the average reward sat near minus 547 throughout.
What is attention here?
In a neural network, attention scores how relevant each item in a set is to a question, then mixes the items using those scores. Here the set was meant to be all 16,132 words, each a learned list of 128 numbers, and the question was the current state of the game. That would let the network see which words are similar before choosing. The run behind the numbers above skips it.
I also have a bug in my word lists. Four of the 2,344 answers (admin, cyber, inbox and ramen) are not in the 16,132-word guess list, so the agent can never win those four. It is a tiny share, but it is there.
The browser script has no logged results, only my recollection of the games I watched it play. The helper where I type in colours is set to load a model from a folder that no longer exists, so it needs a path passed in.
What's unfinished
The next step is a fair test: answers the agent never trained on, a simple baseline in the same masked environment, v1 and v2 compared one change at a time, and a logged run of the browser script over a fixed number of games on the real site, to replace my memory of it. The word-attention loop would need another try after that.
- Stack
- Python, PyTorch, Gymnasium, Stable-Baselines3 with sb3-contrib (MaskablePPO), Playwright for the site script
- Status
- Prototype
- Made
- November 2025 for the agent, December 2025 and February 2026 for the two plain solvers
- Code
- Not public