Weekend project to come up with automated strategies to solve Wordle.
High water mark of my solver:
Solves dictionary with 99.83%
success rate, 3.66696
average guesses in under 3 seconds.
$ cmake -DCMAKE_BUILD_TYPE=Release .
$ time make
[ 16%] Building CXX object CMakeFiles/solver.dir/wordle_selector.cpp.o
[ 33%] Building CXX object CMakeFiles/solver.dir/wordlist_wordle_solver.cpp.o
[ 50%] Building CXX object CMakeFiles/solver.dir/wordle_trie.cpp.o
[ 66%] Building CXX object CMakeFiles/solver.dir/wordle_checker.cpp.o
[ 83%] Building CXX object CMakeFiles/solver.dir/main.cpp.o
[100%] Linking CXX executable solver
[100%] Built target solver
real 0m9.517s
user 0m8.867s
sys 0m0.521s
- Solve Entire Dictionary
$ time ./solver --mode all
Wordle Solver v4
mode:all
guess1cands,guess2cands,guess3cands,guess4cands,guess5cands,guess6cands,result,words_left,num_guesses,answer
2315,48,4,3,2,1,success,1,6,aback
2315,6,2,1,1,1,success,1,4,abase
2315,6,3,2,1,1,success,2,4,abate
2315,61,1,1,1,1,success,1,3,abbey
2315,51,4,1,1,1,success,1,4,abbot
2315,136,15,2,1,1,success,1,5,abhor
...
2294/2315=0.9909
done.
real 0m11.157s
user 0m10.390s
sys 0m0.698s
- Solve Entire Dictionary, Fast
$ time ./solver --mode all --multi
Wordle Solver v4
mode:all
guess1cands,guess2cands,guess3cands,guess4cands,guess5cands,guess6cands,result,words_left,num_guesses,answer
2315,48,4,3,2,1,success,1,6,aback
2315,6,2,1,1,1,success,1,4,abase
2315,6,3,2,1,1,success,2,4,abate
2315,61,1,1,1,1,success,1,3,abbey
2315,51,4,1,1,1,success,1,4,abbot
2315,136,15,2,1,1,success,1,5,abhor
...
2294/2315=0.9909
done.
real 0m2.577s
user 0m19.079s
sys 0m1.619s
- Original Interactive Mode
$ ./solver --mode interactive
Wordle Solver v4
mode:interactive
Guess #1: sling
> GBGBB
Guess #2: shiny
> GGGBB
Guess #3: shirk
> GGGGG
Success!
Wordle 3/7
- Debug Mode (
#define DEBUG_UNICODE=true
for pretty print)
$ ./solver --mode debug --word brain
Wordle Solver v4
mode:debug
⬛⬛🟨🟩🟩
⬛⬛⬛🟩🟩
🟩🟩🟩🟩🟩
Wordle 3/6
- Cheat Mode
$ ./solver --mode cheat
Wordle Solver v4
Size of wordlist: 2315
Size of wordlist: 2315
mode:cheat
Guess #1
guessing> chart
Guess #1: chart
checking> gbbbg
Remaining Candidates: (4)
covet:22
clout:20
count:19
cleft:16
Guess #2
guessing> clout
Guess #2: clout
checking> gbyyg
Remaining Candidates: (1)
count:25
- View Scoring
$ sort -hk 2 -t'=' scores.txt > sorted_scores.txt
- Current usage
$ time ./solver --mode all 2>guess_nums_6.csv
Wordle Solver v4
mode:all
2294/2315=0.9909
done.
real 0m18.768s
user 0m17.029s
sys 0m1.063s
$ grep "success" guess_nums_6.csv | cut -d',' -f9 | awk 's+=$1{print s/NR}' | tail -n 1 # Average number of guesses
3.72113
- Fastest
$ time ./solver --mode all --multi 2>guess_nums_6.csv
Wordle Solver v4
mode:all
multi-threaded
done.
real 0m3.050s
user 0m18.391s
sys 0m1.671s
$ grep "success" guess_nums_6.csv | cut -d',' -f9 | awk 's+=$1{print s/NR}' | tail -n 1 # Average number of guesses
X.XXXXX
Number of correct games over entire dictionary.
-
v1.0
: 98.14%- Average guesses on success: ??
-
v2.0
: 98.57%- Average guesses on success: 4.26687
-
v3.0
: 99.83%- Average guesses on success: 3.72113
-
v4.0
: 99.09%- Average guesses on success: 3.66696
There is a Checker
and Solver
. These two entities comprise the Wordle game. The Solver
is the "player" while the Checker
is the "referee."
Each Solver
can be mixed and matched with any Selector
.
Currently the best combo is TrieBasedWordleSolver
& PositionalLetterWordleSelector
.
Role: Generate list of candidate words based on dictionary and results from prior guess.
-
WordleSolver
- Abstract Base Class. Interface for
Solver
s.
- Abstract Base Class. Interface for
-
WordlistWordleSolver
- Abstract Base Class. Adds wordlist functionality.
-
PassthroughWordleSolver
- Intended for debugging
Selector
s. Does no processing of results.
- Intended for debugging
-
TrieBaseWordleSolver
- Most powerful
Solver
. Uses a letter-based trie data structure to efficiently eliminate potential words based on results of prior guess.
- Most powerful
Role: Choose which word in a given list of words should be selected for the current Wordle guess.
-
WordleSelector
- Abstract Base Class. Interface for
Selector
s.
- Abstract Base Class. Interface for
-
RandomWordleSelector
- From an iterable list of candidate words, chooses candidate randomly.
-
EnhancedRandomWordleSelector
- Randomly choose candidate words that contain more than one vowel and do not contain double letters.
-
MostCommonLetterWordleSelector
- Abstract Base Class. Interface for
Selector
s that want to compute frequency scores over remaining candidate words.
- Abstract Base Class. Interface for
-
NaiveMostCommonLetterWordleSelector
- Basic approach to computing score based on most common letters in all remaining words.
-
ImprovedMostCommonLetterWordleSelector
- Improved approach that doesn't score letters that show up multiple times (they're less common) AND letters that are already green (no effect, but it stands to reason).
-
PositionalLetterWordleSelector
- Computes which letter is most common in each position. Scores each candidate word based on this and selects best candidate.
-
FrequencyAndPositionalLetterWordleSelector
- Blend of overall scoring (frequency) and positional letter scoring
-
answers.txt
- Primitive 5-letter dictionary from the Internet
-
answers_extended.txt
- All allowed guesses, larger dictionary than
answers.txt
- All allowed guesses, larger dictionary than
-
game_modes.[h|cpp]
- Defines each game mode, defines the rules and orchestration of each game type
-
guess_nums_6.csv
- Results from current algorithm, 6 guesses allowed (default)
-
guess_nums_7.csv
- Results from current algorithm, 7 guesses allowed
-
main.cpp
main()
lives here, arg parsing
-
wordle_buffer.h
- Used for the multi-threaded solver scenario, collects all output then dumps when done
-
wordle_checker.[h|cpp]
- Automated checking against an answer
-
wordle_checker_test.cpp
- Tests for the checker
-
wordle_helpers.h
- Static plumbing to make user interaction easier
-
wordle_rules.h
- Basic game constraints defined here
-
wordle_selectors.[h|cpp]
- Selection Algorithms to feed to
Solver
- Selection Algorithms to feed to
-
wordle_solver.h
- Abstract Base class/interface for the
Solver
- Abstract Base class/interface for the
-
wordle_trie.[h|cpp]
- Trie data structure used for Wordle
-
wordlist_wordle_solver.[h|cpp]
- More intelligent
Solver
s that use a dictionary
- More intelligent
-
Better/Additional dictionary - i.e. include allowed guesses dict
-
Select strategy from cmd line
-
Select mode from cmd line
-
Measure success rates of various algos against whole dictionary
-
Define richer exceptions and catch them in main to help in debugging
-
Thread each parallel execution (Clang Mac doesn't support threading for loops :( )
-
Break ties with more common letter in dictionary. TieBreaker class???? - mostly an unhit case
-
Add aggressive
easy mode
Solver
to knock out many letters with words not in remaining set. Likely to lead to 100% accuracy + lower average guesses. -
Implement
hard mode
Solver
-
Implement
hard mode
verifier (experimental branch) -
Replace several size checks with NUM_LETTERS to consolidate understanding of what is tied to this global
-
Raw pointers -> smart pointers (in progress, done?)
-
Track lowest score of letter in word, sort on this somehow in getBestCandidate. Don't pick words with low lowest letter scores even if their score is the highest.
-
How to optimize with easy (non-hard) mode guessing?
-
Track biggest string of ties (ensure guess busts worst case scenarios, to help reach 100% solve rate)
-
Wordle Cheat Mode, allow user to select a non-top choice and let algo run with that instead of the auto chosen word
-
Make Selectors Composable (scoring, then selection should be done at another layer)
-
Add wordle unicode decoder
-
Add arg parsing OR multiple binaries
-
Check guess against guess dict
-
Support one output buffer per game, will help unlock multi-threaded game
-
Best Wordle guessing strategy(HN) https://slc.is/archive/best-wordle-strategy-explore-or-exploit/
-
Wordle-Solver - solves 99.7% of common five-letter English words(HN) (github)
-
Wordle-solving state of the art: all optimality results so far(HN) https://www.poirrier.ca/notes/wordle-optimal/
-
https://codereview.stackexchange.com/questions/32817/multithreading-c-loop
WordleSolver
^
|
WordleSolverImpl
^
|
WordlistWordleSolver ---------------------------------> WordleSelector
^ ^
| |
PassthroughWordleSolver PositionalLetterWordleSolver
^ ^
| |
TrieBasedWordleSolver -----> WordleTrie FrequencyAndPositionalLetterWordleSelector
TrieBasedWordleSolver
|- WordleTrie* (owns list of current correct answers)
|- FrequencyAndPositionalLetterWordleSelector* (owns behavior of selecting from a list of words)
WordleTrie::makeXXGuess() main