public
Last active

Program to find Shortest Word Ladders

  • Download Gist
Ladders.lhs
Literate Haskell
{-# LANGUAGE BangPatterns #-}
import Prelude hiding (foldl, foldr, foldl1, foldr1, (.), id)
import Data.Functor
import Data.Foldable
import Data.Traversable
import Data.Monoid
import Control.Applicative
import Control.Monad hiding (mapM, mapM_, forM, forM_)
import Control.Category
import Control.Arrow
import qualified Data.List as L
import System.Environment

Finding a Shortest Word Ladder

So, there is a programming challenge on reddit, to make a program to find the shortest possible 'word ladder' between two words, given a limited dictionary of words.

So how might one go about this? Well, first of all, we could obviously try every possibility of a word ladder between the two words. We will improve this later, but for now, let's assume we are going to try every possibility and pick the best. So, finding one possibility, we will need to be able to find the 'adjacent' words. A word ladder is a set of steps through different words, where each step changes only one letter, and each side of the step is a word. So how can we find what steps we can make from a single word? Well, as all the words we have are 4 letters long (the list of words is stored at the end of the post), we can cheat a little. We will use a very loose form of Trie.

data Trie a = Trie !Bool [Node a] deriving (Show, Eq)
data Node a = Node !a    (Trie a) deriving (Show, Eq)

Don't be worried by the strange pragmas and bangs here - these are just slight tweaks for performance, and don't actually affect the functionality. Having defined the data type of our trie, we need to be able to build one from the word list.

buildTrie :: (Eq a) => [[a]] -> Trie a
buildTrie [] = Trie False [] -- The empty tree
buildTrie xs = Trie hasEmpty steps
    where
      -- Remove any empty items from the list
      (hasEmpty, toAdd) = preFilter xs id
      preFilter     []  c = (False, c [])
      preFilter ([]:xs) c = (True, c $ filter (not . null) xs)
      preFilter ( x:xs) c = preFilter xs $ (x:) >>> c
      steps = makeSteps toAdd
      makeSteps    []  = []
      makeSteps (x:xs) = Node first next : makeSteps different
          where
            first = head x
            (same, different) = span ((first ==) . head) xs
            next = buildTrie $ fmap tail $ x:same
wordTrie = buildTrie wordList

Now in order to check that this works, and also to make clearer how the trie works, we will create a function to read a Trie back into a list.

foldTrie :: (Eq a) => ([a] -> b -> b) -> b -> Trie a -> b
foldTrie f = foldTrie' id
    where
      foldTrie' before e (Trie yield children) = if yield then f (before []) m else m
          where
            m = foldDigits' before e children
      foldDigits' _ e [] = e
      foldDigits' before e (x:xs) = foldDigit' before (foldDigits' before e xs) x
      foldDigit' before e (Node c trie) = foldTrie' (before . (c:)) e trie

If you try building a Trie from the wordlist, and then folding over it using cons and the empty tree to rebuild the list, you should find that the list you get is equal to the original word list. So we have our trie structure, now how do we use it to find similar words? Well, we will define a maximum number of mistakes. Then we move down the tree, and for each child, either it matches the key, or we use up one of our mistakes. If we run out of mistakes, we stop traversing the tree in that branch. First, we define the exact find (as we will use this anyway when we run out of mistakes).

findExact :: (Eq a) => [a] -> Trie a -> [[a]]
findExact k t = replicate (count k 0 t) k
    where
      count    []  n (Trie yield        _) = if yield then n + 1 else n
      count (x:xs) n (Trie     _ children) = foldl' (folder x xs) n children
      folder x xs n (Node c trie) = if x == c then
                                         count xs n trie
                                     else
                                         n

Now, we will perform a similar (in some ways) search, but keeping track of our mistakes.

findFuzzy :: (Eq a, Integral n) => n -> [a] -> Trie a -> [[a]]
findFuzzy = findFuzzy' id []
    where
      findFuzzy' b e 0 k t = (fmap b $ findExact k t) ++ e
      findFuzzy' b e n    []  (Trie yield    _) = if yield then b [] :e else e
      findFuzzy' b e n (x:xs) (Trie _ children) = foldr (folder b x xs n) e children
      folder b x xs n (Node c trie) e = n' `seq` findFuzzy' (b . (c:)) e n' xs trie
          where
            n' = if x == c then n else n - 1

So, we can now use a fuzzy find routine to find words which we can reach in one step from our current word. But this isn't really enough on its own - how do we know which word to go to next? For this, we can bring in a heuristic search algorithm, which is a way of guessing where on this massive invisible set of paths we want to go next. The algorithm I am going to use is called A* search, and it is very simple. We simply visit the next possibility based on whichever possibility is nearest to the goal according to a heuristic of the distance. The only requirement on the heuristic is that it will never over-estimate the distance (i.e. it returns the minimum possible). So in this case, we can simply return the number of substitutions we would need, if all possible 4 letter words were in our word list.

distance :: (Eq a, Integral n) => [a] -> [a] -> n
distance l r = distance' l r 0
    where
      distance' [] [] n = n
      distance' (l:ls) (r:rs) n = distance' ls rs $! n'
          where
            n' = if l == r then n else n + 1

Now we need a really quick and dirty priority queue to use to keep track of the possibilities. I have written this in another file (I say quick and dirty, it's very mathematically neat, but not very efficient probably). We can then use this, to find our path from the start word to the finish word.

ladders :: (Ord a, Integral n) => Trie a -> [a] -> [a] -> [(n, [[a]])]
ladders trie from target = consume $ push [(distance from target, 0, [from])] mempty
    where
      consume queue = maybe [] produce $ pop queue
      produce ((_, cost, p@(mid:_)), queue) = if mid == target then
                                                  (cost, p) : consume queue
                                              else
                                                  consume nextQueue
          where
            nextQueue = push (stepFunc <$> findFuzzy 1 mid trie) queue
            stepFunc step = c `seq` e `seq` (e, c, step:p)
                where
                  c = cost + 1
                  e = c + distance step target

Wow, that was crazy. But if you try it, you should find it will work. The consume step merely removes the best possible trail from the queue, and then the produce step produces the possible further steps, if any. Producing the further steps is relatively easy - we simply find all the words that can be reached in one additional step (using the Trie). Then we just recompose these slightly to add in all the book-keeping information.

Now, the final step is to write the actual main method to output the best ladders.

main = do
  (from:to:_) <- getArgs
  let answers = ladders wordTrie from to
  let best    = takeWhile ((==) (fst $ head $ answers) . fst) answers
  forM_ fmap (reverse . snd) best $ \answer -> do
         putStrLn "----------"
         forM_ answer $ show >>> putStrLn

This concludes the main part of this program. What follows are supporting sections, which are probably not as interesting.

Extremely Simple Priority Queues

So, we want a really simple version of priority queues. Let's start with a really simple related structure - an ordered list. We start then, with a simple newtype alias for a sorted list.

newtype Ordered a = Ordered { unOrdered :: [a] } deriving (Show, Eq, Ord)

The standard list sort function works brilliantly. It seems a nice idea to specialise the sort function to return a specifically ordered list.

sort :: (Ord a) => [a] -> Ordered a
sort = Ordered . L.sort

We will also want to create single item lists later. These are of course trivially ordered.

single :: a -> Ordered a
single = Ordered . (:[])

And largely for convenience, these lists are foldable like normal.

instance Foldable Ordered where
    foldl f s = foldl f s . unOrdered
    foldl1  f = foldl1  f . unOrdered
    foldr f e = foldr f e . unOrdered
    foldr1  f = foldr1  f . unOrdered

Then, as these are ordered lists, we should define a special monoid over them. The normal list monoid is append, but this will not work for ordered list, as the result is not neccessarily ordered. However, we can do a classic pairwise merge to join together two ordered lists to make a new one containing the items from both. It also has an identity (the empty list as normal), and so is a prime candidate for a monoid.

instance (Ord a) => Monoid (Ordered a) where
    mempty = Ordered mempty
    mappend l r = Ordered $ unOrdered l `merge` unOrdered r
-- | Merge two ordered lists, preserving duplicates.
merge :: (Ord a) => [a] -> [a] -> [a]
merge [] r = r
merge l [] = l
merge ls@(l:lt) rs@(r:rt) = if r < l then r : merge ls rt else l : merge lt rs

However, we don't really want to be merging all the lists all the time. We can create a structure that allows us to notionally delay merges so that merges are made, in this case, between lists of hopefully more similar length. The structure is based on a representation of binary numbers, using a technique I learned from Chris Okasaki's fantastic book, Purely Functional Data Structures.

newtype Merging m = Merging { unMerging :: [Digit m] } deriving (Show, Eq)
data Digit m = One m | Two m m deriving (Show, Eq)

We need a way of adding another item into this representation (which will be in this case, another ordered list), which corresponds to incrementing the number by one.

cons :: (Monoid m) => m -> Merging m -> Merging m
cons x = Merging . cons' x . unMerging
    where
      cons' x            [] = One x   : []
      cons' x ((One   r):t) = Two x r : t
      cons' x ((Two l r):t) = One x   : cons' (l <> r) t

We will then use a fold across this structure to support adding one structure to another. This merge monoid which we get very loosely corresponds to addition, but whereas Okasaki did describe using functions corresponding to addition quite closely, this is really stretching the analogy.

instance Foldable Merging where
    foldl f s = foldl folder s . unMerging
        where
          folder s (One l  ) = f s l
          folder s (Two l r) = f (f s l) r
    foldr f e = foldr folder e . unMerging
        where
          folder (One l  ) e = f l e
          folder (Two l r) e = f l (f r e)
instance (Monoid m) => Monoid (Merging m) where
    mempty = Merging mempty
    mappend l r = foldr cons r l

Now, having both the ordered list monoid, and the delayed merging structure, we can define simple priority queues by just combining the two.

newtype Queue a = Queue { unQueue :: Merging (Ordered a) }

To add a new set of items onto the queue, we simply sort it and start merging the oridered list.

push :: (Ord a) => [a] -> Queue a -> Queue a
push xs = Queue . cons (sort xs) . unQueue

Popping is slightly more complex. But we simply reduce it to a recursive solution, where we try popping from the latter parts of the structure, pop an item from the current part instead if needed, and then rebuild the entire structure. This means we do more merging than we might want to, but performance is not too important for this simple task.

pop :: (Ord a) => Queue a -> Maybe (a, Queue a)
pop = fmap (second Queue) . foldr popper Nothing . unQueue
    where
      popper (Ordered       [] ) t = t
      popper (Ordered xs@(x:xt)) t = case t of
                                       Nothing -> Just (x, cons (Ordered xt) mempty)
                                       Just (y, q) -> if y < x then
                                                          Just (y, cons (Ordered xs) q)
                                                      else
                                                          Just (x, cons (single y) $ cons (Ordered xt) q)

And then we simply use the underlying monoid to merge together queues.

instance (Ord a) => Monoid (Queue a) where
    mempty = Queue mempty
    mappend l r = Queue $ unQueue l <> unQueue r

The Mighty Word List

Finally, we need the haskell encoding of the huge word list. It's worth noting that all the words here are of the same length. This meant we didn't have to worry too much about the length of the keys in our algorithms. Although it may well have worked anyway, as we did match on the basis of the length of our keys when searching the trie.

wordList = [
      "aahs", "aals", "abas", "abba", "abbe", "abed", "abet", "able", "ably", "abos",
      "abut", "abye", "abys", "aced", "aces", "ache", "achy", "acid", "acme", "acne",
      "acre", "acta", "acts", "acyl", "adds", "adit", "ados", "aeon", "aero", "aery",
      "afar", "agar", "agas", "aged", "agee", "ager", "ages", "agha", "agin", "agio",
      "agly", "agma", "agog", "agon", "ague", "ahem", "aide", "aids", "ails", "aims",
      "ains", "airn", "airs", "airt", "airy", "aits", "ajar", "ajee", "akee", "akin",
      "alae", "alan", "alar", "alas", "alba", "albs", "alec", "alee", "alef", "ales",
      "alfa", "alga", "alif", "alit", "alky", "alls", "ally", "alma", "alme", "alms",
      "aloe", "alow", "alps", "also", "alto", "alts", "alum", "amah", "amas", "amen",
      "amia", "amid", "amie", "amin", "amir", "amis", "amps", "amus", "amyl", "anal",
      "anas", "ands", "anes", "anew", "anga", "anil", "anis", "anna", "anoa", "anon",
      "ansa", "anta", "ante", "anti", "ants", "anus", "aped", "aper", "apes", "apex",
      "apod", "arbs", "arch", "arco", "arcs", "area", "ares", "arfs", "aria", "arid",
      "aril", "arks", "arms", "army", "arts", "arty", "arum", "arvo", "aryl", "asea",
      "ashy", "asks", "asps", "atap", "ates", "atma", "atom", "atop", "auks", "aunt",
      "aura", "auto", "aver", "aves", "avid", "avos", "avow", "away", "awed", "awee",
      "awes", "awls", "awns", "awny", "awry", "axal", "axed", "axel", "axes", "axil",
      "axis", "axle", "axon", "ayah", "ayes", "ayin", "azan", "azon", "baal", "baas",
      "baba", "babe", "babu", "baby", "bach", "back", "bade", "bads", "baff", "bags",
      "baht", "bail", "bait", "bake", "bald", "bale", "balk", "ball", "balm", "bals",
      "bams", "band", "bane", "bang", "bani", "bank", "bans", "baps", "barb", "bard",
      "bare", "barf", "bark", "barm", "barn", "bars", "base", "bash", "bask", "bass",
      "bast", "bate", "bath", "bats", "batt", "baud", "bawd", "bawl", "bays", "bead",
      "beak", "beam", "bean", "bear", "beat", "beau", "beck", "beds", "bedu", "beef",
      "been", "beep", "beer", "bees", "beet", "begs", "bell", "bels", "belt", "bema",
      "bend", "bene", "bens", "bent", "berg", "berm", "best", "beta", "beth", "bets",
      "bevy", "beys", "bhut", "bias", "bibb", "bibs", "bice", "bide", "bids", "bier",
      "biff", "bigs", "bike", "bile", "bilk", "bill", "bima", "bind", "bine", "bins",
      "bint", "bios", "bird", "birk", "birl", "birr", "bise", "bisk", "bite", "bits",
      "bitt", "bize", "blab", "blae", "blah", "blam", "blat", "blaw", "bleb", "bled",
      "blet", "blew", "blin", "blip", "blob", "bloc", "blot", "blow", "blub", "blue",
      "blur", "boar", "boas", "boat", "bobs", "bock", "bode", "bods", "body", "boff",
      "bogs", "bogy", "boil", "bola", "bold", "bole", "boll", "bolo", "bolt", "bomb",
      "bond", "bone", "bong", "bonk", "bony", "boob", "book", "boom", "boon", "boor",
      "boos", "boot", "bops", "bora", "bore", "born", "bort", "bosh", "bosk", "boss",
      "bota", "both", "bots", "bott", "bout", "bowl", "bows", "boxy", "boyo", "boys",
      "bozo", "brad", "brae", "brag", "bran", "bras", "brat", "braw", "bray", "bred",
      "bree", "bren", "brew", "brie", "brig", "brim", "brin", "brio", "bris", "brit",
      "broo", "bros", "brow", "brrr", "brut", "bubo", "bubs", "buck", "buds", "buff",
      "bugs", "buhl", "buhr", "bulb", "bulk", "bull", "bumf", "bump", "bums", "bund",
      "bung", "bunk", "bunn", "buns", "bunt", "buoy", "bura", "burd", "burg", "burl",
      "burn", "burp", "burr", "burs", "bury", "bush", "busk", "buss", "bust", "busy",
      "bute", "buts", "butt", "buys", "buzz", "byes", "byre", "byrl", "byte", "cabs",
      "caca", "cade", "cadi", "cads", "cafe", "caff", "cage", "cagy", "caid", "cain",
      "cake", "caky", "calf", "calk", "call", "calm", "calo", "calx", "came", "camp",
      "cams", "cane", "cans", "cant", "cape", "caph", "capo", "caps", "carb", "card",
      "care", "cark", "carl", "carn", "carp", "carr", "cars", "cart", "casa", "case",
      "cash", "cask", "cast", "cate", "cats", "caul", "cave", "cavy", "caws", "cays",
      "ceca", "cede", "cedi", "cees", "ceil", "cell", "cels", "celt", "cent", "cepe",
      "ceps", "cere", "cero", "cess", "cete", "chad", "cham", "chao", "chap", "char",
      "chat", "chaw", "chay", "chef", "chew", "chez", "chia", "chic", "chid", "chin",
      "chip", "chis", "chit", "chon", "chop", "chow", "chub", "chug", "chum", "ciao",
      "cine", "cion", "cire", "cist", "cite", "city", "clad", "clag", "clam", "clan",
      "clap", "claw", "clay", "clef", "clew", "clip", "clod", "clog", "clon", "clop",
      "clot", "cloy", "club", "clue", "coal", "coat", "coax", "cobb", "cobs", "coca",
      "cock", "coco", "coda", "code", "cods", "coed", "coff", "coft", "cogs", "coho",
      "coif", "coil", "coin", "coir", "coke", "cola", "cold", "cole", "cols", "colt",
      "coly", "coma", "comb", "come", "comp", "cone", "coni", "conk", "conn", "cons",
      "cony", "coof", "cook", "cool", "coon", "coop", "coos", "coot", "cope", "cops",
      "copy", "cord", "core", "corf", "cork", "corm", "corn", "cory", "cosh", "coss",
      "cost", "cosy", "cote", "cots", "coup", "cove", "cowl", "cows", "cowy", "coxa",
      "coys", "cozy", "crab", "crag", "cram", "crap", "craw", "crew", "crib", "cris",
      "croc", "crop", "crow", "crud", "crus", "crux", "cube", "cubs", "cuds", "cued",
      "cues", "cuff", "cuif", "cuke", "cull", "culm", "cult", "cunt", "cups", "curb",
      "curd", "cure", "curf", "curl", "curn", "curr", "curs", "curt", "cusk", "cusp",
      "cuss", "cute", "cuts", "cwms", "cyan", "cyma", "cyme", "cyst", "czar", "dabs",
      "dace", "dada", "dado", "dads", "daff", "daft", "dago", "dags", "dahl", "dahs",
      "dais", "daks", "dale", "dals", "dame", "damn", "damp", "dams", "dang", "dank",
      "daps", "darb", "dare", "dark", "darn", "dart", "dash", "data", "date", "dato",
      "daub", "daut", "davy", "dawk", "dawn", "daws", "dawt", "days", "daze", "dead",
      "deaf", "deal", "dean", "dear", "debs", "debt", "deck", "deco", "deed", "deem",
      "deep", "deer", "dees", "deet", "defi", "deft", "defy", "deil", "deke", "dele",
      "delf", "deli", "dell", "dels", "deme", "demo", "demy", "dene", "dens", "dent",
      "deny", "dere", "derm", "desk", "deva", "devs", "dews", "dewy", "dexy", "deys",
      "dhak", "dhal", "dhow", "dial", "dibs", "dice", "dick", "dido", "didy", "died",
      "diel", "dies", "diet", "digs", "dike", "dill", "dime", "dims", "dine", "ding",
      "dink", "dins", "dint", "diol", "dips", "dipt", "dire", "dirk", "dirl", "dirt",
      "disc", "dish", "disk", "diss", "dita", "dite", "dits", "ditz", "diva", "dive",
      "doat", "doby", "dock", "docs", "dodo", "doer", "does", "doff", "doge", "dogs",
      "dogy", "doit", "dojo", "dole", "doll", "dols", "dolt", "dome", "doms", "dona",
      "done", "dong", "dons", "doom", "door", "dopa", "dope", "dopy", "dore", "dork",
      "dorm", "dorp", "dorr", "dors", "dory", "dose", "doss", "dost", "dote", "doth",
      "dots", "doty", "doum", "dour", "doux", "dove", "down", "dows", "doxy", "doze",
      "dozy", "drab", "drag", "dram", "drat", "draw", "dray", "dree", "dreg", "drek",
      "drew", "drib", "drip", "drop", "drub", "drug", "drum", "drys", "duad", "dual",
      "dubs", "duce", "duci", "duck", "duct", "dude", "duds", "duel", "dues", "duet",
      "duff", "dugs", "duit", "duke", "dull", "duly", "duma", "dumb", "dump", "dune",
      "dung", "dunk", "duns", "dunt", "duos", "dupe", "dups", "dura", "dure", "durn",
      "duro", "durr", "dusk", "dust", "duty", "dyad", "dyed", "dyer", "dyes", "dyke",
      "dyne", "each", "earl", "earn", "ears", "ease", "east", "easy", "eath", "eats",
      "eaux", "eave", "ebon", "eche", "echo", "ecus", "eddo", "eddy", "edge", "edgy",
      "edhs", "edit", "eels", "eely", "eery", "effs", "efts", "eger", "eggs", "eggy",
      "egis", "egos", "eide", "eked", "ekes", "elan", "elds", "elks", "ells", "elms",
      "elmy", "else", "emes", "emeu", "emfs", "emic", "emir", "emit", "emus", "ends",
      "engs", "enol", "enow", "eons", "epic", "epos", "eras", "ergo", "ergs", "erne",
      "erns", "eros", "errs", "erst", "eses", "etas", "etch", "eths", "etic", "euro",
      "even", "ever", "eves", "ewer", "ewes", "exec", "exes", "exit", "exon", "eyas",
      "eyed", "eyen", "eyer", "eyes", "eyne", "eyra", "eyre", "eyry", "face", "fact",
      "fade", "fado", "fads", "fags", "fail", "fain", "fair", "fake", "fall", "falx",
      "fame", "fane", "fang", "fano", "fans", "fard", "fare", "farl", "farm", "faro",
      "fart", "fash", "fast", "fate", "fats", "faun", "faux", "fava", "fave", "fawn",
      "fays", "faze", "feal", "fear", "feat", "feck", "feds", "feed", "feel", "fees",
      "feet", "fehs", "fell", "felt", "feme", "fems", "fend", "fens", "feod", "fere",
      "fern", "fess", "feta", "fete", "fets", "feud", "feus", "fiar", "fiat", "fibs",
      "fice", "fico", "fido", "fids", "fief", "fife", "figs", "fila", "file", "fill",
      "film", "filo", "fils", "find", "fine", "fink", "fino", "fins", "fire", "firm",
      "firn", "firs", "fisc", "fish", "fist", "fits", "five", "fixt", "fizz", "flab",
      "flag", "flak", "flam", "flan", "flap", "flat", "flaw", "flax", "flay", "flea",
      "fled", "flee", "flew", "flex", "fley", "flic", "flip", "flit", "floc", "floe",
      "flog", "flop", "flow", "flub", "flue", "flus", "flux", "foal", "foam", "fobs",
      "foci", "foes", "fogs", "fogy", "fohn", "foil", "foin", "fold", "folk", "fond",
      "fons", "font", "food", "fool", "foot", "fops", "fora", "forb", "ford", "fore",
      "fork", "form", "fort", "foss", "foul", "four", "fowl", "foxy", "foys", "fozy",
      "frae", "frag", "frap", "frat", "fray", "free", "fret", "frig", "frit", "friz",
      "froe", "frog", "from", "frow", "frug", "fubs", "fuci", "fuck", "fuds", "fuel",
      "fugs", "fugu", "fuji", "full", "fume", "fumy", "fund", "funk", "funs", "furl",
      "furs", "fury", "fuse", "fuss", "futz", "fuze", "fuzz", "fyce", "fyke", "gabs",
      "gaby", "gadi", "gads", "gaed", "gaen", "gaes", "gaff", "gaga", "gage", "gags",
      "gain", "gait", "gala", "gale", "gall", "gals", "gama", "gamb", "game", "gamp",
      "gams", "gamy", "gane", "gang", "gaol", "gape", "gaps", "gapy", "garb", "gars",
      "gash", "gasp", "gast", "gate", "gats", "gaud", "gaum", "gaun", "gaur", "gave",
      "gawk", "gawp", "gays", "gaze", "gear", "geck", "geds", "geed", "geek", "gees",
      "geez", "geld", "gels", "gelt", "gems", "gene", "gens", "gent", "genu", "germ",
      "gest", "geta", "gets", "geum", "ghat", "ghee", "ghis", "gibe", "gibs", "gids",
      "gied", "gien", "gies", "gift", "giga", "gigs", "gild", "gill", "gilt", "gimp",
      "gink", "gins", "gips", "gird", "girl", "girn", "giro", "girt", "gist", "gits",
      "give", "glad", "gled", "glee", "gleg", "glen", "gley", "glia", "glib", "glim",
      "glob", "glom", "glop", "glow", "glue", "glug", "glum", "glut", "gnar", "gnat",
      "gnaw", "gnus", "goad", "goal", "goas", "goat", "gobo", "gobs", "goby", "gods",
      "goer", "goes", "gogo", "gold", "golf", "gone", "gong", "good", "goof", "gook",
      "goon", "goop", "goos", "gore", "gorp", "gory", "gosh", "gout", "gowd", "gowk",
      "gown", "goys", "grab", "grad", "gram", "gran", "grat", "gray", "gree", "grew",
      "grey", "grid", "grig", "grim", "grin", "grip", "grit", "grog", "grot", "grow",
      "grub", "grue", "grum", "guan", "guar", "guck", "gude", "guff", "guid", "gulf",
      "gull", "gulp", "guls", "gums", "gunk", "guns", "gush", "gust", "guts", "guvs",
      "guys", "gybe", "gyms", "gyps", "gyre", "gyri", "gyro", "gyve", "haaf", "haar",
      "habu", "hack", "hade", "hadj", "haed", "haem", "haen", "haes", "haet", "haft",
      "hags", "haha", "hahs", "haik", "hail", "hair", "haji", "hajj", "hake", "hale",
      "half", "hall", "halm", "halo", "halt", "hame", "hams", "hand", "hang", "hank",
      "hant", "haps", "hard", "hare", "hark", "harl", "harm", "harp", "hart", "hash",
      "hasp", "hast", "hate", "hath", "hats", "haul", "haut", "have", "hawk", "haws",
      "hays", "haze", "hazy", "head", "heal", "heap", "hear", "heat", "hebe", "heck",
      "heed", "heel", "heft", "hehs", "heil", "heir", "held", "hell", "helm", "helo",
      "help", "heme", "hemp", "hems", "hens", "hent", "herb", "herd", "here", "herl",
      "herm", "hern", "hero", "hers", "hest", "heth", "hets", "hewn", "hews", "hick",
      "hide", "hied", "hies", "high", "hike", "hila", "hili", "hill", "hilt", "hind",
      "hins", "hint", "hips", "hire", "hisn", "hiss", "hist", "hits", "hive", "hoar",
      "hoax", "hobo", "hobs", "hock", "hods", "hoed", "hoer", "hoes", "hogg", "hogs",
      "hoke", "hold", "hole", "holk", "holm", "holp", "hols", "holt", "holy", "home",
      "homo", "homy", "hone", "hong", "honk", "hons", "hood", "hoof", "hook", "hoop",
      "hoot", "hope", "hops", "hora", "horn", "hose", "host", "hots", "hour", "hove",
      "howe", "howf", "howk", "howl", "hows", "hoya", "hoys", "hubs", "huck", "hued",
      "hues", "huff", "huge", "hugs", "hula", "hulk", "hull", "hump", "hums", "hung",
      "hunh", "hunk", "huns", "hunt", "hurl", "hurt", "hush", "husk", "huts", "hwan",
      "hyla", "hype", "hypo", "hyps", "hyte", "iamb", "ibex", "ibis", "iced", "ices",
      "ichs", "icky", "idea", "idem", "ides", "idle", "idly", "ikat", "ilea", "ilex",
      "ilia", "ilka", "ilks", "ills", "illy", "imid", "impi", "imps", "inby", "inch",
      "info", "inia", "inks", "inky", "inly", "inns", "inro", "inti", "into", "ions",
      "iota", "ired", "ires", "irid", "iris", "irks", "isle", "itch", "item", "iwis",
      "ixia", "izar", "jabs", "jack", "jade", "jagg", "jags", "jail", "jake", "jamb",
      "jams", "jane", "jape", "jarl", "jars", "jato", "jauk", "jaup", "java", "jaws",
      "jays", "jazz", "jean", "jeed", "jeep", "jeer", "jees", "jeez", "jefe", "jell",
      "jeon", "jerk", "jess", "jest", "jete", "jets", "jews", "jiao", "jibb", "jibe",
      "jibs", "jiff", "jigs", "jill", "jilt", "jimp", "jink", "jinn", "jins", "jinx",
      "jive", "jobs", "jock", "joes", "joey", "jogs", "john", "join", "joke", "joky",
      "jole", "jolt", "josh", "joss", "jota", "jots", "jouk", "jowl", "jows", "joys",
      "juba", "jube", "juga", "jugs", "juke", "jump", "junk", "jupe", "jura", "jury",
      "just", "jute", "juts", "kaas", "kabs", "kadi", "kaes", "kafs", "kaif", "kail",
      "kain", "kaka", "kaki", "kale", "kame", "kami", "kana", "kane", "kaon", "kapa",
      "kaph", "karn", "kart", "kata", "kats", "kava", "kayo", "kays", "kbar", "keas",
      "keck", "keef", "keek", "keel", "keen", "keep", "keet", "kefs", "kegs", "keir",
      "kelp", "kemp", "keno", "kens", "kent", "kepi", "keps", "kept", "kerb", "kerf",
      "kern", "keto", "keys", "khaf", "khan", "khat", "khet", "khis", "kibe", "kick",
      "kids", "kief", "kier", "kifs", "kike", "kill", "kiln", "kilo", "kilt", "kina",
      "kind", "kine", "king", "kink", "kino", "kins", "kips", "kirk", "kirn", "kirs",
      "kiss", "kist", "kite", "kith", "kits", "kiva", "knap", "knar", "knee", "knew",
      "knit", "knob", "knop", "knot", "know", "knur", "koan", "koas", "kobo", "kobs",
      "koel", "kohl", "kola", "kolo", "konk", "kook", "koph", "kops", "kore", "kors",
      "koss", "koto", "kris", "kues", "kvas", "kyak", "kyar", "kyat", "kyte", "labs",
      "lace", "lack", "lacs", "lacy", "lade", "lads", "lady", "lags", "laic", "laid",
      "lain", "lair", "lake", "lakh", "laky", "lall", "lama", "lamb", "lame", "lamp",
      "lams", "land", "lane", "lang", "lank", "laps", "lard", "lari", "lark", "lars",
      "lase", "lash", "lass", "last", "late", "lath", "lati", "lats", "laud", "lava",
      "lave", "lavs", "lawn", "laws", "lays", "laze", "lazy", "lead", "leaf", "leak",
      "leal", "lean", "leap", "lear", "leas", "lech", "leek", "leer", "lees", "leet",
      "left", "legs", "lehr", "leis", "leke", "leks", "leku", "lend", "leno", "lens",
      "lent", "lept", "less", "lest", "lets", "leud", "leva", "levo", "levy", "lewd",
      "leys", "liar", "libs", "lice", "lich", "lick", "lido", "lids", "lied", "lief",
      "lien", "lier", "lies", "lieu", "life", "lift", "like", "lilt", "lily", "lima",
      "limb", "lime", "limn", "limo", "limp", "limy", "line", "ling", "link", "linn",
      "lino", "lins", "lint", "liny", "lion", "lips", "lira", "lire", "liri", "lisp",
      "list", "lite", "lits", "litu", "live", "load", "loaf", "loam", "loan", "lobe",
      "lobo", "lobs", "loca", "loch", "loci", "lock", "loco", "lode", "loft", "loge",
      "logo", "logs", "logy", "loin", "loll", "lone", "long", "loof", "look", "loom",
      "loon", "loop", "loos", "loot", "lope", "lops", "lord", "lore", "lorn", "lory",
      "lose", "loss", "lost", "lota", "loth", "loti", "lots", "loud", "loup", "lour",
      "lout", "love", "lowe", "lown", "lows", "luau", "lube", "luce", "luck", "lude",
      "lues", "luff", "luge", "lugs", "lull", "lulu", "lump", "lums", "luna", "lune",
      "lung", "lunk", "lunt", "luny", "lure", "lurk", "lush", "lust", "lute", "lutz",
      "luvs", "luxe", "lyes", "lyre", "lyse", "maar", "mabe", "mace", "mach", "mack",
      "macs", "made", "mads", "maes", "mage", "magi", "mags", "maid", "mail", "maim",
      "main", "mair", "make", "mako", "male", "mall", "malm", "malt", "mama", "mana",
      "mane", "mano", "mans", "many", "maps", "marc", "mare", "mark", "marl", "mars",
      "mart", "mash", "mask", "mass", "mast", "mate", "math", "mats", "matt", "maud",
      "maul", "maun", "maut", "mawn", "maws", "maxi", "maya", "mayo", "mays", "maze",
      "mazy", "mead", "meal", "mean", "meat", "meed", "meek", "meet", "meld", "mell",
      "mels", "melt", "memo", "mems", "mend", "meno", "menu", "meou", "meow", "mere",
      "merk", "merl", "mesa", "mesh", "mess", "meta", "mete", "meth", "mewl", "mews",
      "meze", "mhos", "mibs", "mica", "mice", "mick", "midi", "mids", "mien", "miff",
      "migg", "migs", "mike", "mild", "mile", "milk", "mill", "milo", "mils", "milt",
      "mime", "mina", "mind", "mine", "mini", "mink", "mint", "minx", "mire", "miri",
      "mirk", "mirs", "miry", "mise", "miso", "miss", "mist", "mite", "mitt", "mity",
      "mixt", "moan", "moas", "moat", "mobs", "mock", "mocs", "mode", "modi", "mods",
      "mogs", "moil", "mojo", "moke", "mola", "mold", "mole", "moll", "mols", "molt",
      "moly", "mome", "momi", "moms", "monk", "mono", "mons", "mony", "mood", "mool",
      "moon", "moor", "moos", "moot", "mope", "mops", "mopy", "mora", "more", "morn",
      "mors", "mort", "mosk", "moss", "most", "mote", "moth", "mots", "mott", "moue",
      "move", "mown", "mows", "moxa", "mozo", "much", "muck", "muds", "muff", "mugg",
      "mugs", "mule", "mull", "mumm", "mump", "mums", "mumu", "muni", "muns", "muon",
      "mura", "mure", "murk", "murr", "muse", "mush", "musk", "muss", "must", "mute",
      "muts", "mutt", "myna", "myth", "nabe", "nabs", "nada", "nags", "naif", "nail",
      "name", "nana", "nans", "naoi", "naos", "nape", "naps", "narc", "nard", "nark",
      "nary", "nave", "navy", "nays", "nazi", "neap", "near", "neat", "nebs", "neck",
      "need", "neem", "neep", "neif", "nema", "nene", "neon", "nerd", "ness", "nest",
      "nets", "nett", "neuk", "neum", "neve", "nevi", "news", "newt", "next", "nibs",
      "nice", "nick", "nide", "nidi", "nigh", "nill", "nils", "nims", "nine", "nipa",
      "nips", "nisi", "nite", "nits", "nixe", "nixy", "nobs", "nock", "node", "nodi",
      "nods", "noel", "noes", "nogg", "nogs", "noil", "noir", "nolo", "noma", "nome",
      "noms", "nona", "none", "nook", "noon", "nope", "nori", "norm", "nose", "nosh",
      "nosy", "nota", "note", "noun", "nous", "nova", "nows", "nowt", "nubs", "nude",
      "nuke", "null", "numb", "nuns", "nurd", "nurl", "nuts", "oafs", "oaks", "oars",
      "oast", "oath", "oats", "obes", "obey", "obia", "obis", "obit", "ocas", "odds",
      "odea", "odes", "odic", "ofay", "offs", "ogee", "ogle", "ogre", "ohed", "ohia",
      "oils", "oily", "oink", "okas", "okay", "okeh", "okes", "okra", "olds", "oldy",
      "olea", "oleo", "oles", "olio", "olla", "omen", "omer", "omit", "ones", "only",
      "onto", "onus", "oohs", "oops", "oots", "ooze", "oozy", "opah", "opal", "oped",
      "open", "opes", "opts", "opus", "orad", "oral", "orbs", "orby", "orca", "orcs",
      "ores", "orgy", "orle", "orra", "orts", "osar", "oses", "otic", "otto", "ouch",
      "ouds", "ouph", "ours", "oust", "outs", "oval", "oven", "over", "owed", "owes",
      "owls", "owns", "oxen", "oxes", "oyer", "oyes", "oyez", "paca", "pace", "pack",
      "pacs", "pact", "padi", "pads", "page", "paid", "paik", "pail", "pain", "pair",
      "pale", "pall", "palm", "palp", "pals", "paly", "pams", "pane", "pang", "pans",
      "pant", "papa", "paps", "para", "pard", "pare", "park", "parr", "pars", "part",
      "pase", "pash", "pass", "past", "pate", "path", "pats", "paty", "pave", "pawl",
      "pawn", "paws", "pays", "peag", "peak", "peal", "pean", "pear", "peas", "peat",
      "pech", "peck", "pecs", "peds", "peed", "peek", "peel", "peen", "peep", "peer",
      "pees", "pegs", "pehs", "pein", "peke", "pele", "pelf", "pelt", "pend", "pens",
      "pent", "peon", "pepo", "peps", "peri", "perk", "perm", "pert", "peso", "pest",
      "pets", "pews", "phat", "phew", "phis", "phiz", "phon", "phot", "phut", "pial",
      "pian", "pias", "pica", "pice", "pick", "pics", "pied", "pier", "pies", "pigs",
      "pika", "pike", "piki", "pile", "pili", "pill", "pily", "pima", "pimp", "pina",
      "pine", "ping", "pink", "pins", "pint", "piny", "pion", "pipe", "pips", "pipy",
      "pirn", "pish", "piso", "piss", "pita", "pith", "pits", "pity", "pixy", "plan",
      "plat", "play", "plea", "pleb", "pled", "plew", "plod", "plop", "plot", "plow",
      "ploy", "plug", "plum", "plus", "pock", "poco", "pods", "poem", "poet", "pogy",
      "pois", "poke", "poky", "pole", "poll", "polo", "pols", "poly", "pome", "pomp",
      "poms", "pond", "pone", "pong", "pons", "pony", "pood", "poof", "pooh", "pool",
      "poon", "poop", "poor", "pope", "pops", "pore", "pork", "porn", "port", "pose",
      "posh", "post", "posy", "pots", "pouf", "pour", "pout", "pows", "pram", "prao",
      "prat", "prau", "pray", "pree", "prep", "prex", "prey", "prez", "prig", "prim",
      "proa", "prod", "prof", "prog", "prom", "prop", "pros", "prow", "psis", "psst",
      "pubs", "puce", "puck", "puds", "puff", "pugh", "pugs", "puja", "puke", "pula",
      "pule", "puli", "pull", "pulp", "puls", "puma", "pump", "puna", "pung", "punk",
      "puns", "punt", "puny", "pupa", "pups", "pure", "puri", "purl", "purr", "purs",
      "push", "puss", "puts", "putt", "putz", "pyas", "pyes", "pyic", "pyin", "pyre",
      "qaid", "qats", "qoph", "quad", "quag", "quai", "quay", "quey", "quid", "quin",
      "quip", "quit", "quiz", "quod", "race", "rack", "racy", "rads", "raff", "raft",
      "raga", "rage", "ragi", "rags", "raia", "raid", "rail", "rain", "raja", "rake",
      "raki", "rale", "rami", "ramp", "rams", "rand", "rang", "rani", "rank", "rant",
      "rape", "raps", "rapt", "rare", "rase", "rash", "rasp", "rate", "rath", "rato",
      "rats", "rave", "raws", "raya", "rays", "raze", "razz", "read", "real", "ream",
      "reap", "rear", "rebs", "reck", "recs", "redd", "rede", "redo", "reds", "reed",
      "reef", "reek", "reel", "rees", "refs", "reft", "regs", "reif", "rein", "reis",
      "rely", "rems", "rend", "rent", "repo", "repp", "reps", "resh", "rest", "rete",
      "rets", "revs", "rhea", "rhos", "rhus", "rial", "rias", "ribs", "rice", "rich",
      "rick", "ride", "rids", "riel", "rife", "riff", "rifs", "rift", "rigs", "rile",
      "rill", "rime", "rims", "rimy", "rind", "ring", "rink", "rins", "riot", "ripe",
      "rips", "rise", "risk", "rite", "ritz", "rive", "road", "roam", "roan", "roar",
      "robe", "robs", "rock", "rocs", "rode", "rods", "roes", "roil", "role", "rolf",
      "roll", "romp", "roms", "rood", "roof", "rook", "room", "root", "rope", "ropy",
      "rose", "rosy", "rota", "rote", "roti", "rotl", "roto", "rots", "roue", "roup",
      "rout", "roux", "rove", "rows", "rube", "rubs", "ruby", "ruck", "rudd", "rude",
      "rued", "ruer", "rues", "ruff", "ruga", "rugs", "ruin", "rule", "ruly", "rump",
      "rums", "rune", "rung", "runs", "runt", "ruse", "rush", "rusk", "rust", "ruth",
      "ruts", "ryas", "ryes", "ryke", "rynd", "ryot", "sabe", "sabs", "sack", "sacs",
      "sade", "sadi", "safe", "saga", "sage", "sago", "sags", "sagy", "said", "sail",
      "sain", "sake", "saki", "sale", "sall", "salp", "sals", "salt", "same", "samp",
      "sand", "sane", "sang", "sank", "sans", "saps", "sard", "sari", "sark", "sash",
      "sass", "sate", "sati", "saul", "save", "sawn", "saws", "says", "scab", "scad",
      "scag", "scam", "scan", "scar", "scat", "scop", "scot", "scow", "scry", "scud",
      "scum", "scup", "scut", "seal", "seam", "sear", "seas", "seat", "secs", "sect",
      "seed", "seek", "seel", "seem", "seen", "seep", "seer", "sees", "sego", "segs",
      "seif", "seis", "self", "sell", "sels", "seme", "semi", "send", "sene", "sent",
      "sept", "sera", "sere", "serf", "sers", "seta", "sets", "sett", "sewn", "sews",
      "sext", "sexy", "shad", "shag", "shah", "sham", "shat", "shaw", "shay", "shea",
      "shed", "shes", "shew", "shim", "shin", "ship", "shit", "shiv", "shmo", "shod",
      "shoe", "shog", "shoo", "shop", "shot", "show", "shri", "shul", "shun", "shut",
      "sial", "sibb", "sibs", "sice", "sick", "sics", "side", "sift", "sigh", "sign",
      "sike", "sild", "silk", "sill", "silo", "silt", "sima", "simp", "sims", "sine",
      "sing", "sinh", "sink", "sins", "sipe", "sips", "sire", "sirs", "site", "sith",
      "sits", "size", "sizy", "skag", "skas", "skat", "skee", "skeg", "skep", "skew",
      "skid", "skim", "skin", "skip", "skis", "skit", "slab", "slag", "slam", "slap",
      "slat", "slaw", "slay", "sled", "slew", "slid", "slim", "slip", "slit", "slob",
      "sloe", "slog", "slop", "slot", "slow", "slub", "slue", "slug", "slum", "slur",
      "slut", "smew", "smit", "smog", "smug", "smut", "snag", "snap", "snaw", "sned",
      "snib", "snip", "snit", "snob", "snog", "snot", "snow", "snub", "snug", "soak",
      "soap", "soar", "sobs", "sock", "soda", "sods", "sofa", "soft", "soil", "soja",
      "soke", "sola", "sold", "sole", "soli", "solo", "sols", "soma", "some", "sone",
      "song", "sons", "sook", "soon", "soot", "soph", "sops", "sora", "sorb", "sord",
      "sore", "sori", "sorn", "sort", "soth", "sots", "souk", "soul", "soup", "sour",
      "sous", "sown", "sows", "soya", "soys", "spae", "span", "spar", "spas", "spat",
      "spay", "spaz", "spec", "sped", "spew", "spic", "spik", "spin", "spit", "spiv",
      "spot", "spry", "spud", "spue", "spun", "spur", "sris", "stab", "stag", "star",
      "stat", "staw", "stay", "stem", "step", "stet", "stew", "stey", "stir", "stoa",
      "stob", "stop", "stow", "stub", "stud", "stum", "stun", "suba", "subs", "such",
      "suck", "sudd", "suds", "sued", "suer", "sues", "suet", "sugh", "suit", "sulk",
      "sulu", "sumo", "sump", "sums", "sung", "sunk", "sunn", "suns", "supe", "sups",
      "suqs", "sura", "surd", "sure", "surf", "suss", "swab", "swag", "swam", "swan",
      "swap", "swat", "sway", "swig", "swim", "swob", "swop", "swot", "swum", "syce",
      "syke", "syli", "sync", "syne", "syph", "tabs", "tabu", "tace", "tach", "tack",
      "taco", "tact", "tads", "tael", "tags", "tail", "tain", "taka", "take", "tala",
      "talc", "tale", "tali", "talk", "tall", "tame", "tamp", "tams", "tang", "tank",
      "tans", "taos", "tapa", "tape", "taps", "tare", "tarn", "taro", "tarp", "tars",
      "tart", "task", "tass", "tate", "tats", "taus", "taut", "tavs", "taws", "taxa",
      "taxi", "teak", "teal", "team", "tear", "teas", "teat", "teds", "teed", "teel",
      "teem", "teen", "tees", "teff", "tegs", "tela", "tele", "tell", "tels", "temp",
      "tend", "tens", "tent", "tepa", "term", "tern", "test", "teth", "tets", "tews",
      "text", "thae", "than", "that", "thaw", "thee", "them", "then", "thew", "they",
      "thin", "thio", "thir", "this", "thou", "thro", "thru", "thud", "thug", "thus",
      "tick", "tics", "tide", "tidy", "tied", "tier", "ties", "tiff", "tike", "tiki",
      "tile", "till", "tils", "tilt", "time", "tine", "ting", "tins", "tint", "tiny",
      "tipi", "tips", "tire", "tirl", "tiro", "titi", "tits", "tivy", "toad", "toby",
      "tods", "tody", "toea", "toed", "toes", "toff", "toft", "tofu", "toga", "togs",
      "toil", "toit", "toke", "tola", "told", "tole", "toll", "tolu", "tomb", "tome",
      "toms", "tone", "tong", "tons", "tony", "took", "tool", "toom", "toon", "toot",
      "tope", "toph", "topi", "tops", "tora", "torc", "tore", "tori", "torn", "toro",
      "torr", "tors", "tort", "tory", "tosh", "toss", "tost", "tote", "tots", "tour",
      "tout", "town", "tows", "towy", "toyo", "toys", "trad", "tram", "trap", "tray",
      "tree", "tref", "trek", "tret", "trey", "trig", "trim", "trio", "trip", "trod",
      "trop", "trot", "trow", "troy", "true", "trug", "tsar", "tsks", "tuba", "tube",
      "tubs", "tuck", "tufa", "tuff", "tuft", "tugs", "tuis", "tule", "tump", "tuna",
      "tune", "tung", "tuns", "tups", "turd", "turf", "turk", "turn", "tush", "tusk",
      "tuts", "tutu", "twae", "twas", "twat", "twee", "twig", "twin", "twit", "twos",
      "tyee", "tyer", "tyes", "tyke", "tyne", "type", "typo", "typp", "typy", "tyre",
      "tyro", "tzar", "udos", "ugly", "ukes", "ulan", "ulus", "umps", "unai", "unau",
      "unbe", "unci", "unco", "unde", "undo", "undy", "unit", "unto", "upas", "updo",
      "urbs", "urds", "urea", "urns", "ursa", "urus", "used", "user", "uses", "utas",
      "uvea", "vacs", "vagi", "vail", "vain", "vair", "vale", "vamp", "vane", "vang",
      "vans", "vara", "vars", "vary", "vasa", "vase", "vast", "vats", "vatu", "vaus",
      "vavs", "vaws", "veal", "veep", "veer", "vees", "veil", "vein", "vela", "veld",
      "vena", "vend", "vent", "vera", "verb", "vert", "very", "vest", "veto", "vets",
      "vext", "vial", "vibe", "vice", "vide", "vied", "vier", "vies", "view", "viga",
      "vigs", "vile", "vill", "vims", "vina", "vine", "vino", "viny", "viol", "virl",
      "visa", "vise", "vita", "viva", "vive", "voes", "vole", "volt", "vote", "vows",
      "vrow", "vugg", "vugh", "vugs", "wabs", "wack", "wade", "wadi", "wads", "wady",
      "waes", "waff", "waft", "wage", "wags", "waif", "wail", "wain", "wair", "wait",
      "wake", "wale", "walk", "wall", "waly", "wame", "wand", "wane", "wans", "want",
      "wany", "waps", "ward", "ware", "wark", "warm", "warn", "warp", "wars", "wart",
      "wary", "wash", "wasp", "wast", "wats", "watt", "wauk", "waul", "waur", "wave",
      "wavy", "wawl", "waws", "waxy", "ways", "weak", "weal", "wean", "wear", "webs",
      "weds", "weed", "week", "weel", "ween", "weep", "weer", "wees", "weet", "weft",
      "weir", "weld", "well", "welt", "wend", "wens", "went", "wept", "were", "wert",
      "west", "wets", "wham", "whap", "what", "whee", "when", "whet", "whew", "whey",
      "whid", "whig", "whim", "whin", "whip", "whir", "whit", "whiz", "whoa", "whom",
      "whop", "whys", "wich", "wick", "wide", "wife", "wigs", "wild", "wile", "will",
      "wilt", "wily", "wimp", "wind", "wine", "wing", "wink", "wino", "wins", "winy",
      "wipe", "wire", "wiry", "wise", "wish", "wisp", "wiss", "wist", "wite", "with",
      "wits", "wive", "woad", "woes", "wogs", "woke", "woks", "wold", "wolf", "womb",
      "wonk", "wons", "wont", "wood", "woof", "wool", "woos", "wops", "word", "wore",
      "work", "worm", "worn", "wort", "wost", "wots", "wove", "wows", "wrap", "wren",
      "writ", "wuss", "wych", "wyes", "wyle", "wynd", "wynn", "wyns", "wyte", "xyst",
      "yack", "yaff", "yagi", "yaks", "yald", "yams", "yang", "yank", "yaps", "yard",
      "yare", "yarn", "yaud", "yaup", "yawl", "yawn", "yawp", "yaws", "yays", "yeah",
      "yean", "year", "yeas", "yech", "yeld", "yelk", "yell", "yelp", "yens", "yerk",
      "yeti", "yett", "yeuk", "yews", "yids", "yill", "yins", "yipe", "yips", "yird",
      "yirr", "yobs", "yock", "yodh", "yods", "yoga", "yogh", "yogi", "yoke", "yoks",
      "yolk", "yond", "yoni", "yore", "your", "yowe", "yowl", "yows", "yuan", "yuca",
      "yuch", "yuck", "yuga", "yuks", "yule", "yups", "yurt", "ywis", "zags", "zany",
      "zaps", "zarf", "zeal", "zeds", "zees", "zein", "zeks", "zerk", "zero", "zest",
      "zeta", "zigs", "zill", "zinc", "zing", "zins", "zips", "ziti", "zits", "zoea",
      "zone", "zonk", "zoom", "zoon", "zoos", "zori", "zyme" ]

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.