Skip to content

lang_tools.exercises.wordle

Wordle exercise (from worldly-words).

Guess a hidden word within word_length + 1 attempts. After each guess, each letter receives a state: correct (right letter, right position), misplaced (right letter, wrong position), or wrong. Comparison is done on accent-stripped (normalized) forms.

Classes:

LetterResult

Bases: BaseModel

Per-letter evaluation of a guess.

Attributes:

  • letter (str) –

    The character (in the guess form, accent-stripped).

  • state (LetterState) –

    One of "correct", "misplaced", "wrong".

WordleExercise dataclass

WordleExercise(**kwargs: object)

Bases: _BaseExercise

Wordle round factory.

Initialize the exercise.

Parameters:

  • **kwargs (object, default: {} ) –

    Forwarded to _BaseExercise.

Methods:

  • start

    Build a Wordle round around target.

  • submit

    Evaluate a single guess.

Source code in src/lang_tools/exercises/wordle.py
def __init__(self, **kwargs: object) -> None:
    """Initialize the exercise.

    Args:
        **kwargs: Forwarded to `_BaseExercise`.
    """
    super().__init__(exercise_type="wordle", **kwargs)  # type: ignore[arg-type]

start

start(
    target: Word, *, max_attempts: int | None = None
) -> ExerciseRound

Build a Wordle round around target.

Parameters:

  • target (Word) –

    The hidden word.

  • max_attempts (int | None, default: None ) –

    Override for the default len(target) + 1.

Returns:

  • ExerciseRound

    ExerciseRound whose expected is the internal _WordleState.

Source code in src/lang_tools/exercises/wordle.py
def start(self, target: Word, *, max_attempts: int | None = None) -> ExerciseRound:
    """Build a Wordle round around `target`.

    Args:
        target: The hidden word.
        max_attempts: Override for the default ``len(target) + 1``.

    Returns:
        `ExerciseRound` whose `expected` is the internal `_WordleState`.
    """
    self._ensure_started()
    normalized = _normalize(target.text)
    state = _WordleState(
        target=target,
        target_normalized=normalized,
        word_length=len(normalized),
        max_attempts=(
            max_attempts if max_attempts is not None else len(normalized) + 1
        ),
    )
    return ExerciseRound(
        prompt={
            "word_length": state.word_length,
            "max_attempts": state.max_attempts,
            "guesses": [],
            "results": [],
            "keyboard_state": {},
        },
        expected=state,
    )

submit

submit(round_: ExerciseRound, guess: str) -> RoundResult

Evaluate a single guess.

Parameters:

  • round_ (ExerciseRound) –

    The round returned by start.

  • guess (str) –

    User's guess. Compared against the normalized target.

Returns:

  • RoundResult

    RoundResult flagging this guess. When the round terminates (win

  • RoundResult

    or attempts exhausted) a WordResult is appended.

Source code in src/lang_tools/exercises/wordle.py
def submit(self, round_: ExerciseRound, guess: str) -> RoundResult:
    """Evaluate a single guess.

    Args:
        round_: The round returned by `start`.
        guess: User's guess. Compared against the normalized target.

    Returns:
        `RoundResult` flagging this guess. When the round terminates (win
        or attempts exhausted) a `WordResult` is appended.
    """
    state: _WordleState = round_.expected

    if state.won or len(state.guesses) >= state.max_attempts:
        return RoundResult(correct=False, feedback="Game already finished.")

    normalized_guess = _normalize(guess)
    if len(normalized_guess) != state.word_length:
        return RoundResult(
            correct=False,
            feedback=f"Guess must be {state.word_length} letters.",
        )

    letter_results = _evaluate(normalized_guess, state.target_normalized)
    state.guesses.append(normalized_guess)
    state.results.append(letter_results)
    _update_keyboard(state.keyboard_state, letter_results)

    round_.prompt["guesses"] = list(state.guesses)
    round_.prompt["results"] = [list(r) for r in state.results]
    round_.prompt["keyboard_state"] = dict(state.keyboard_state)

    correct = normalized_guess == state.target_normalized
    state.won = correct
    terminated = correct or len(state.guesses) >= state.max_attempts

    word_results: list[WordResult] = []
    if terminated:
        word_results.append(WordResult(word_id=state.target.id, correct=correct))

    result = RoundResult(
        correct=correct,
        feedback=None if correct else f"{guess!r} is not the word.",
        word_results=word_results,
    )
    self._bookkeep(result)
    return result