diff --git a/dictionary.py b/dictionary.py new file mode 100644 index 0000000..5327077 --- /dev/null +++ b/dictionary.py @@ -0,0 +1,80 @@ +#!/usr/bin/python + + +WORDLE_LENGTH = 5 + + +_wordle_dictionary = set() + + +_invalid_words = set( + [ + "amala", + "arara", + "araru", + "araua", + "arawa", + "balak", + "batak", + "bayal", + "beala", + "beata", + "beele", + "boily", + "bolty", + "bruke", + "carlo", + "caroa", + "carot", + "carum", + "divet", + "doray", + "erept", + "fikie", + "genae", + "ghole", + "gotra", + "hirse", + "hyrse", + "katat", + "korah", + "macco", + "mitra", + "muang", + "nurry", + "odell", + "odell", + "petro", + "pindy", + "quito", + "retan", + "roter", + "sisel", + "skeel", + "staia", + "stail", + "sussy", + "tebet", + "telae", + "theet", + "undig", + "uninn", + "unkin", + "vedet", + "whalm", + "whaly", + ] +) + + +def words(): + if not _wordle_dictionary: + with open("words_alpha.txt") as word_file: + all_words = word_file.read().split() + _wordle_dictionary.update( + filter( + lambda w: len(w) == WORDLE_LENGTH and w not in _invalid_words, all_words + ) + ) + + return _wordle_dictionary diff --git a/wordle.py b/wordle.py index 9d90b90..af1cb9a 100644 --- a/wordle.py +++ b/wordle.py @@ -6,7 +6,7 @@ import string from enum import Enum from collections import defaultdict -WORDLE_LENGTH = 5 +import dictionary class LetterResult(Enum): @@ -24,92 +24,17 @@ class InvalidWord(Exception): pass -_wordle_dictionary = set() - - -_invalid_words = set( - [ - "amala", - "arara", - "araru", - "araua", - "arawa", - "balak", - "batak", - "bayal", - "beala", - "beata", - "beele", - "boily", - "bolty", - "bruke", - "carlo", - "caroa", - "carot", - "carum", - "divet", - "doray", - "erept", - "fikie", - "genae", - "ghole", - "gotra", - "hirse", - "hyrse", - "katat", - "korah", - "macco", - "mitra", - "muang", - "nurry", - "odell", - "odell", - "petro", - "pindy", - "quito", - "retan", - "roter", - "sisel", - "skeel", - "staia", - "stail", - "sussy", - "tebet", - "telae", - "theet", - "undig", - "uninn", - "unkin", - "vedet", - "whalm", - "whaly", - ] -) - - -def dictionary(): - if not _wordle_dictionary: - with open("words_alpha.txt") as word_file: - all_words = word_file.read().split() - _wordle_dictionary.update( - filter( - lambda w: len(w) == WORDLE_LENGTH and w not in _invalid_words, all_words - ) - ) - - return _wordle_dictionary - def select_word(): - return random.choice(list(dictionary())) + return random.choice(list(dictionary.words())) def grade_word(target, guess): # We don't check word length, since all valid words are 5 letters. - if guess not in dictionary(): + if guess not in dictionary.words(): raise InvalidWord(f"{guess} is not a valid Wordle.") - result = [LetterResult.UNKNOWN] * WORDLE_LENGTH + result = [LetterResult.UNKNOWN] * dictionary.WORDLE_LENGTH # We copy target, and remove letters if we find them. This handles duplicate letters correctly. # For example, if the target is "pulls" and we guess "apple", only the first "p" should be a @@ -117,12 +42,12 @@ def grade_word(target, guess): remaining = list(target) # Find all correct results first. - for i in range(WORDLE_LENGTH): + for i in range(dictionary.WORDLE_LENGTH): if target[i] == guess[i]: result[i] = LetterResult.CORRECT remaining.remove(guess[i]) - for i in range(WORDLE_LENGTH): + for i in range(dictionary.WORDLE_LENGTH): if result[i] == LetterResult.UNKNOWN: if guess[i] in remaining: # Letter is in the wrong place. @@ -198,7 +123,7 @@ def score_word(position_matches, word_matches, word): return result -def scored_words(wordle_dictionary=dictionary()): +def scored_words(wordle_dictionary=dictionary.words()): # word: score scored_words = dict() @@ -216,9 +141,9 @@ def scored_words(wordle_dictionary=dictionary()): class Constraints: def __init__(self): # Array of known letters in result with None for unknown. - self.correct = [None] * WORDLE_LENGTH + self.correct = [None] * dictionary.WORDLE_LENGTH # Array with per-letter sets of known bad letters. - self.incorrect = [set() for _ in range(WORDLE_LENGTH)] + self.incorrect = [set() for _ in range(dictionary.WORDLE_LENGTH)] # Dict of letter -> int with minimum required count of letter in word. self.count = defaultdict(int) # If letter is present in set, value in min is both min and max. @@ -272,7 +197,7 @@ class Constraints: return True -def filter_dictionary(constraints, wordle_dictionary=dictionary()): +def filter_dictionary(constraints, wordle_dictionary=dictionary.words()): return set(filter(lambda w: constraints.matches(w), wordle_dictionary))