Skip to content

Waqas01CP/WordPy-Solver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WordPy Solver

An autonomous Wordle-style solver that reads game state directly from PIL Images using pixel color sampling, then applies constraint-based filtering with an information-gain heuristic to solve the word in as few guesses as possible.

Built across three progressively harder assignments — text feedback, then image feedback, then an optimised solving strategy — and packaged here as a standalone, runnable project.


How It Works

The Game

WordPy is a Wordle clone. A target word is chosen from a dictionary of 5,922 real 5-letter English words. The bot has 6 guesses to find it. After each guess the game engine renders a feedback image: one colored block per letter.

Block color Hex Meaning
Dark blue #00274C Correct letter, correct position
Yellow #FFCB05 Letter exists in the word, wrong position
Grey #D3D3D3 Letter is not in the word

Step 1 — Image Reading (Bot._process_image)

The bot doesn't receive text feedback — it reads the PIL Image directly. For each letter block, it samples a pixel from the top-left corner of the block (x=block_left+2, y=2). The corner is always pure background color regardless of font or antialiasing, so color classification is exact:

block_x     = i * (block_width + space_between_letters)
sample_x, y = block_x + 2, 2
hex_color   = f"#{r:02X}{g:02X}{b:02X}"   # _tuple_to_str()

Block geometry comes from DisplaySpecification, so the pixel math automatically adjusts if you change block size, spacing, or font.

Step 2 — Constraint Tracking (Bot.record_guess_results)

After decoding each image, three constraint sets are updated:

known_letters[i]   — confirmed letter at position i        (blue blocks)
in_word_letters    — letters present but position unknown  (yellow blocks)
excluded_letters   — letters absent from the word          (grey blocks)

Step 3 — Information-Gain Guessing (Bot.make_guess)

From the filtered candidate pool, the bot picks the word with the most unique letters — a greedy information-gain heuristic that maximises new letters tested per guess:

best = max(remaining_words, key=lambda w: len(set(w)))

Project Structure

WordPy-Solver/
├── main.py                  # CLI entry point — run and configure everything from here
├── requirements.txt
├── wordpy/
│   ├── __init__.py          # Package exports
│   ├── letter.py            # Letter class — single character with feedback state
│   ├── display_spec.py      # DisplaySpecification — colors, fonts, pixel geometry
│   ├── game_engine.py       # GameEngine — word validation, PIL rendering, game loop
│   └── bot.py               # Bot — image reader + constraint solver (your code)
├── assets/
│   ├── words.txt            # 5,922 unique 5-letter English words (real Wordle list)
│   └── fonts/               # 8 bundled fonts — swap without changing any code
│       ├── Poppins-Bold.ttf          (modern geometric sans-serif)
│       ├── Poppins-Regular.ttf       (lighter weight)
│       ├── DejaVuSans-Bold.ttf       (clean sans, similar to Open Sans)
│       ├── DejaVuSerif-Bold.ttf      (traditional serif)
│       ├── Caladea-Bold.ttf          (Calibri-compatible)
│       ├── Carlito-Bold.ttf          (Calibri-compatible, metrically identical)
│       ├── LiberationSans-Bold.ttf   (Arial-compatible)
│       └── Lora-Bold.ttf             (elegant display serif)
└── tests/
    └── test_all.py          # 36 tests covering all classes and the full pipeline

Attribution: game_engine.py is based on the GameEngine provided in the course assignments. letter.py, display_spec.py, bot.py, and the solving strategy are my own work.


Setup

git clone https://github.com/Waqas01CP/WordPy-Solver
cd WordPy-Solver
python -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate
pip install -r requirements.txt

Running

# Random target word, default Michigan blue/maize theme
python main.py

# Specific target word
python main.py --word FIELD

# Different visual theme
python main.py --word CRANE --theme dark
python main.py --word STATE --theme neon

# Different font (any filename from assets/fonts/ without .ttf)
python main.py --word FIELD --font Caladea-Bold
python main.py --word FIELD --font DejaVuSerif-Bold
python main.py --word FIELD --font Lora-Bold

# Save each guess as a PNG image (for demos)
python main.py --word FIELD --save-images

# List all available fonts
python main.py --list-fonts

# Benchmark solve rate over 100 random games
python main.py --benchmark 100

Example Output

Playing a game of WordyPy using the word list file of assets/words.txt.
The target word for this round is FIELD

Evaluating bot guess of ABHOR
Was this guess correct? False
Sending guess results to bot: ?????

Updated known letters: [None, None, None, None, None]
Updated excluded letters: {'A', 'B', 'H', 'O', 'R'}

Evaluating bot guess of SWEPT
Was this guess correct? False
Sending guess results to bot: ?????

Evaluating bot guess of GUILD
Was this guess correct? False
Sending guess results to bot: ?*I*D

Updated known letters: [None, None, 'I', None, 'D']
Updated excluded letters: {...}

Evaluating bot guess of FIELD
Was this guess correct? True
Sending guess results to bot: FIELD

Great job, you found the target word in 4 guesses!

Running Tests

# Run directly
python tests/test_all.py

# Or with pytest
pip install pytest
python -m pytest tests/ -v

The test suite covers:

  • Letter class: attributes, feedback states, uppercase handling
  • Bot._tuple_to_str: RGB/RGBA to hex conversion (including the assignment's example cases)
  • Bot._process_image: correct, in-word, absent, and mixed pixel patterns
  • Full game integration: 5-word demo list, invalid words, no repeats
  • DisplaySpecification: defaults, all four themes, font loading

Adding Your Own Fonts

Drop any .ttf file into assets/fonts/ and refer to it by filename (without extension):

cp ~/Downloads/MyFont-Bold.ttf assets/fonts/
python main.py --font MyFont-Bold --word FIELD

No code changes needed — display_spec.py discovers all .ttf files in that directory automatically.


Tech Stack

Python 3.10+ · Pillow (PIL) · Object-Oriented Design · Constraint Filtering · Greedy Information-Gain Heuristic

About

Autonomous Wordle solver — reads game state from PIL Images via pixel color mapping, applies constraint-based filtering with an information-gain heuristic

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages