C++20 Wordle solver with two strategies sharing a precomputed pattern matrix: an entropy solver minimizing average guesses, and a minimax + alpha-beta solver minimizing worst-case guesses.
| Strategy | Avg. guesses |
|---|---|
| Entropy (greedy) | 3.46 |
| Minimax + alpha-beta | 3.52 |
- Guess set (
data/guess-set.txt, 12,972 words) — all valid guesses. - Candidate set (
data/candidate-set.txt, 2,315 words) — possible answers.
A guess need not be a candidate; non-candidate guesses can still be maximally informative.
Feedback (GREEN/YELLOW/GREY per letter) is encoded as a base-3 integer in [0, 242]. computePattern uses a two-pass green-then-yellow scan with a letter-frequency array to handle duplicate letters per official Wordle rules.
patternMatrix[guess][candidate] precomputes every (guess, candidate) pattern once (OpenMP-parallelized), cached to data/pattern-matrix.bin.
For guess
The solver picks
Endgame: at ≤2 candidates, entropy is degenerate, so the solver guesses a candidate directly — provably optimal (
Solves:
directly optimizing worst-case depth instead of expected depth.
- Alpha-beta pruning:
alphatracks the best worst-case found so far; a guess is abandoned the moment its running worst case meets or exceedsalpha. - Entropy-ordered search: guesses are tried in entropy order (
sortByEntropy) so a strongalphais found early, maximizing pruning. BelowCANDIDATE_ONLY_THRESHOLD(15) only remaining candidates are tried; above it, only the topENTROPY_SORT_CAP(300) guesses by entropy are searched. - Memoization: each call is keyed by the sorted candidate-index set in
mmCache, since the same reduced set is reachable via many guess paths. Precomputed once and persisted todata/mmcache.bin. - Bounds:
MINIMAX_MAX_DEPTH(30) and analpha < 2early-out cap the recursion.
Entropy minimizes soare maximizes entropy (5.886 bits) but minimax may prefer salet/crane for a shallower worst case, since entropy only sees bucket sizes, not how hard each bucket is to resolve afterward. Neither is "wrong" — each is optimal for its own objective.
include/ pattern.h (PatternEngine), solver.h (Solver)
src/ pattern.cpp, solver.cpp, main.cpp
data/ word lists, cached pattern matrix, cached minimax results
candidateSet: vector<pair<int,int>> — .first indexes patternMatrix columns, .second indexes the guess set. filterWords partitions in place via swaps (no reallocation).
Requires CMake ≥ 3.14, C++20, OpenMP.
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make
./WordleSolverpattern-matrix.bin and mmcache.bin are built and cached on first run if missing.
main() runs an interactive loop (playGame): prints the best entropy and minimax guesses each turn, accepts guess pattern (e.g. crane 02001, digits = grey/yellow/green), and filters candidates.
For a full benchmark across all 2,315 answers, call testAvgGuess(s) instead — reports guess-count distribution, failures, and average for both strategies.
cd data && python3 order-sets.pyRe-sorts guess-set.txt and rewrites candidate-set-indices.bin. Delete pattern-matrix.bin and mmcache.bin to force a rebuild.