Skip to content

Instantly share code, notes, and snippets.

@ftrain
Last active September 17, 2020 04:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ftrain/2e16deb9f89add31cf853f6e5cb5b801 to your computer and use it in GitHub Desktop.
Save ftrain/2e16deb9f89add31cf853f6e5cb5b801 to your computer and use it in GitHub Desktop.
Spelling Bee solver
import argparse
from math import ceil
from more_itertools import powerset
from ordered_set import OrderedSet
"""
$ pip install more_itertools ordered_set
$ python spellingbee.py RACFKOT -h
usage: spellingbee.py [-h] [--words WORDS] CHARACTERS
Look for solutions for Spelling Bee (https://www.nytimes.com/puzzles/spelling-bee)
positional arguments:
CHARACTERS 7 letters, required letter first, i.e. LWDATOF
optional arguments:
-h, --help show this help message and exit
--words WORDS Path to a file containing words, default is /usr/share/dict/words
$ python spellingbee.py RACFKOT
AFAR KROC TART CROCK CARROT
AFRO OKRA TORT CROOK FACTOR
CARA OORT TROT FRACK KARROO
CARR RACK ACCRA FROCK ORATOR
CART RAFT ACTOR KARAT ROCOCO
CORA ROAR AORTA KRAFT TARTAR
CORK ROCK ATTAR ROCCO TARTAR
FART ROCK CARAT ROTOR ATTRACT
FORA ROOF COROT TAROT TRACTOR
FORK ROOK CRACK TATAR CATARACT
FORT ROOT CRAFT TRACK KRAKATOA
FRAT ROOT CRAFT TRACT
KARA TARA CROAK ARAFAT
KARO TARO CROAT ARARAT
"""
# turn a list into a list of n lists (useful for printing columns)
def chunkdiv(l, n):
for i in range(0, n):
yield l[i::n]
# use powerset to make permutations of a list, keeping things in alph
# order
def get_powerset(l):
chars = list(l)
first_char = chars[0]
chars.sort()
fset = OrderedSet(["".join(x) for x in powerset(chars)])
return fset, first_char
# transform all the words in the dictionary so that "DOGGIES" becomes
# "DEIGS" and then check if that's in the powerset from get_powerset()
def check_words(chars=None, words_file=None):
the_words = []
ps, first_char = get_powerset(chars)
with open(words_file) as words_file_handle:
words = list(words_file_handle)
for word in words:
uppered = word.upper()
trimmed = uppered.rstrip()
filtered = [x for x in list(trimmed) if x.isalnum()]
filtered.sort()
setted = OrderedSet(filtered)
key = "".join(setted)
if key in ps and len(trimmed) > 3 and first_char in setted:
the_words.append(trimmed)
# sort normally...
the_words.sort()
# ...then by length of word
lengthed_words = sorted(the_words, key=len)
# figure out how many rows we need (we want 5 columns)
rows = ceil(len(lengthed_words) / 5)
chunked_words = chunkdiv(lengthed_words, rows)
return chunked_words
def __main__():
parser = argparse.ArgumentParser(
description="Look for solutions for Spelling Bee (https://www.nytimes.com/puzzles/spelling-bee)"
)
parser.add_argument(
"txt",
metavar="CHARACTERS",
type=str,
help="7 letters, required letter first, i.e. LWDATOF",
)
parser.add_argument(
"--words",
type=str,
help="Path to a file containing words, default is /usr/share/dict/words",
default="/usr/share/dict/words",
)
args = parser.parse_args()
words = check_words(chars=args.txt, words_file=args.words)
for l in words:
fmted = ["{:15}".format(w) for w in l]
print("".join(fmted))
if __name__ == "__main__":
__main__()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment