Rooter's Wordle Solver
Wordle solver WordPress plugin
by Shaun Root · github.com/shaunroot/rooter-wordle-solver · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/shaunroot/rooter-wordle-solver/archive/refs/heads/main.zipA WordPress plugin that renders an interactive Wordle solver. Live at shaunroot.net/rooters-wordle-solver.
The player types their guesses into a 6×5 grid, marks the feedback colors, and the Suggest button proposes the best next word. The word list is deliberately broader than the NYT answer list (~15,000 words including obscure words and slang) so the solver also works on fan-made Wordle clones with unconventional answers.
How it works
Data
Two tables, created on plugin activation and imported from the bundled CSVs
(words.csv, letters.csv):
| Table | Contents |
|---|---|
wp_rws_words |
~15,000 five-letter words, each with a score 0–100 |
wp_rws_letters |
the 26 letters, each with a usage score 1–100 |
Word scores are log-scaled frequencies from Norvig's Google Web Trillion
Word Corpus, mapped to 1–100 (about = 100). Words absent from the corpus get
- Three adjustments on top:
- S-plurals are demoted to 0 (BOOKS, YEARS...). Detected by stem lookup:
a word ending in
s(notss/us) whose stem is a common corpus word. Real Wordle never uses S-plurals as answers; they stay guessable but sink to the bottom tier. - NYT answer-list words get a floor score of 25, which puts every one of them inside the top 4,000 ranks.
- Slang/profanity from curated lists is merged in at score 0.
Proper names that aren't real words (DAVID, GROFF) were deleted: a word was removed if it appears in the US census name lists but not in the Scrabble-based Wordle-valid dictionary — that test keeps PETER and JENNY (real words) while dropping the pure names.
Letter scores are usage-weighted letter frequencies from the same corpus (each word's letters counted once per occurrence of the word), scaled linearly with E = 100 down to Q/Z = 1.
Suggestion engine (rws_get_suggestion)
The front end sends the grid state to an admin-ajax endpoint: green letters
by position, yellow letters with their excluded position, gray letters, the
user's manually blocked keyboard letters, and every completed row with its
per-tile marks.
- Constraints. A candidate must match all greens by position, contain every yellow letter somewhere other than its marked position, and avoid gray letters. A gray on a letter that's green/yellow elsewhere isn't a ban — it caps the number of copies (the LEVEL/LEVEE case). Already-guessed words are excluded outright.
- Tiers. Words are ranked by
score DESC, word ASCand split into pools: top 4,000, then 4,000 at a time, then the remainder. Each tier is only consulted if every higher tier has zero matching candidates — so obscure words are suggested only when the common ones are exhausted. - Ranking. Within the active tier each candidate is valued as
word score + Σ letter scores of its distinct letters not yet known. High-frequency words with fresh letters win; ties are broken at random.
One-step lookahead (rws_min_expected_probe)
When the active tier holds 3–40 candidates and at least two rows remain, the solver stops picking "the most likely candidate" and instead picks the guess that minimizes the expected number of candidates remaining — considering every word in the full list as a possible guess, not just candidates:
E[remaining | guess g] = Σ over feedback-groups (n_group² ) / C
− 1/C if g is itself a candidate
For each potential guess it simulates duplicate-aware Wordle feedback against
all C candidates, partitions them by feedback pattern, and scores the split
(the Σn²/C term is the probability-weighted size of the surviving group; the
−1/C credit accounts for the guess winning outright). This is what lets the
solver break "rhyme families": knowing _ILLS with SILLS/DILLS/RILLS left, it
plays WORLD — not a candidate, but its D and R split the three into singletons.
Cost is C × ~15k feedback simulations, sub-second in PHP for C ≤ 40. The opening suggestion never triggers it (thousands of candidates), so requests stay ~150 ms.
Front end
- Type letters (auto-advance, backspace steps back); click a filled tile to cycle plain → yellow → green → cleared. Unmarked letters in completed rows count as gray.
- Suggestions fill the next empty row; known green positions arrive pre-colored. When all rows are used, an Add row button appends a 7th+.
- A QWERTY keyboard under the button auto-dims letters the grid has eliminated; clicking a key blocks it manually (shown darker) and excludes it from suggestions.
- Reset (↺) clears everything; a fully green row disables Suggest.
- On solver pages the plugin hides the theme header and title (body class
rws-page) and shows the logo on a full-width blue band instead. Tiles and keys scale with viewport height so grid + keyboard fit on one screen.
Simulation results
Playing every top-2,400-ranked word as the hidden answer (simulate3.py
methodology — a faithful port of the PHP engine):
| Metric | Value |
|---|---|
| Win rate within 6 rows | 100% |
| Average guesses | 3.72 |
| Worst case | 6 |
For reference: provably optimal play on the curated 2,315-word NYT list averages 3.42 (Bertsimas & Paskov, MIT); typical human averages are 3.8–4.0. On bottom-tier obscure words the solver still wins ~84% of the time within 6.
Files
rooter-wordle-solver.php plugin: activation/import, shortcode, suggestion engine, ajax
words.csv word,score — imported into wp_rws_words
letters.csv letter,score — imported into wp_rws_letters
assets/css/wordle-solver.css
assets/js/wordle-solver.js
assets/img/logo.jpg
Install: drop the folder into wp-content/plugins/, activate (creates and
fills the tables), and put [rooter_wordle_solver] on a page.