From 0bcfa30e8f224ec593e9e1847fea7b6d2888b54c Mon Sep 17 00:00:00 2001 From: Peter Norvig Date: Sat, 4 Jan 2020 14:05:00 -0800 Subject: [PATCH] Add files via upload --- ipynb/SpellingBee.ipynb | 869 +++++++++++----------------------------- 1 file changed, 234 insertions(+), 635 deletions(-) diff --git a/ipynb/SpellingBee.ipynb b/ipynb/SpellingBee.ipynb index 9eac281..87693f9 100644 --- a/ipynb/SpellingBee.ipynb +++ b/ipynb/SpellingBee.ipynb @@ -8,7 +8,9 @@ "\n", "# Spelling Bee\n", "\n", - "The [Jan. 3 2020 Riddler](https://fivethirtyeight.com/features/can-you-solve-the-vexing-vexillology/) concerns the popular [NYTimes Spelling Bee](https://www.nytimes.com/puzzles/spelling-bee) puzzle. As they describe the problem, given a \"honeycomb\" of 7 letters like this:\n", + "The [Jan. 3 2020 Riddler](https://fivethirtyeight.com/features/can-you-solve-the-vexing-vexillology/) concerns the popular NYTimes [Spelling Bee](https://www.nytimes.com/puzzles/spelling-bee) puzzle:\n", + "\n", + "*In this game, seven letters are arranged in a honeycomb lattice, with one letter in the center. Here’s the lattice from December 24, 2019:*\n", "\n", "\n", "\n", @@ -20,19 +22,25 @@ "\n", "*Note that letters can be repeated. For example, the words GAME and AMALGAM are both acceptable words. Four-letter words are worth 1 point each, while five-letter words are worth 5 points, six-letter words are worth 6 points, seven-letter words are worth 7 points, etc. Words that use all of the seven letters in the honeycomb are known as “pangrams” and earn 7 bonus points (in addition to the points for the length of the word). So in the above example, MEGAPLEX is worth 15 points.*\n", "\n", - "*Which seven-letter honeycomb results in the highest possible game score? To be a valid choice of seven letters, no letter can be repeated, it must not contain the letter S (that would be too easy) and there must be at least one pangram.*\n", + "***Which seven-letter honeycomb results in the highest possible game score?*** *To be a valid choice of seven letters, no letter can be repeated, it must not contain the letter S (that would be too easy) and there must be at least one pangram.*\n", "\n", "*For consistency, please use [this word list](https://norvig.com/ngrams/enable1.txt) to check your game score.*\n", "\n", "# Approach to a Solution\n", "\n", - "Since the word list was on my web site (it is a standard Scrabble word list that I happen to host a copy of), I felt somewhat compelled to submit an answer. I had worked on word puzzles before, like Scrabble and Boggle. My first thought is that this puzzle is rather different because it deals with *unordered sets* of letters, not *ordered permutations* of letters. That makes things easier because, roughly speaking, ($26$ choose $7$) is 10,000 times smaller than $26^7$. So I'm optimistic that I can find an optimal solution, not just hillclimb to a pretty good solution (like I did in trying to find a high-scoring Boggle board). I'm developing a sketch of a strategy:\n", + "Since the word list was on my web site (it is a standard Scrabble word list that I happen to host a copy of), I felt somewhat compelled to submit an answer. I had worked on word puzzles before, like Scrabble and Boggle. My first thought is that this puzzle is rather different because it deals with *unordered sets* of letters, not *ordered permutations* of letters. That makes things much easier. When I tried to find the optimal 5×5 Boggle board, I couldn't exhaustively try all $26^{(5×5)} \\approx 10^{35}$ possibilites; I had to do hillclimbing to find a locally (but not necessarily globally) optimal solution. But for Spelling Bee, it is feasible to try every possibility. Here's a sketch of an approach:\n", " \n", "\n", - "- Represent a word as a set of letters, which I'll implement as a sorted string, as returned by `letterset(\"WORD\")`. So both GLAM and AMALGAM will be represented by the string `\"AGLM\"`. (Note: I could have used a `frozenset`, but strings have a more compact printed representation, making them easier to debug, and they take up less memory. I didn't need any `set` operations like union and intersection.) \n", - "- To represent a honeycomb, use a letterset, but also keep track of the center. So the honeycomb in the image above would be represented by `('AEGLMPX', 'G')`.\n", - "- Since every honeycomb must contain a pangram, I can find the best honeycomb by considering all possible pangrams and all possible centers and taking the one that scores highest.\n", - "- I'm hoping there aren't too many candidate pangrams. I can do some pre-computation to make the computation of scores faster." + "- Since every honeycomb must contain a pangram, I can find the best honeycomb by considering all possible pangrams and all possible centers for each pangram and taking the one that scores highest. Something like:\n", + "\n", + " max(game_score(pangram, center) \n", + " for pangram in pangrams for center in pangram)\n", + " \n", + "- So it comes down to having an efficient-enough computation of the words that a honeycomb can make.\n", + "- Represent a word as a set of letters, which I'll implement as a sorted string, e.g.: \n", + " letterset(\"GLAM\") == letterset(\"AMALGAM\") == \"AGLM\". \n", + "- Note: I could have used a `frozenset`, but strings have a more compact printed representation, making them easier to debug, and they take up less memory. I won't need any fancy `set` operations like union and intersection.\n", + "- Represent a honeycomb as a letterset of 7 letters, along with an indication of which one is the center. So the honeycomb in the image above would be represented by `('AEGLMPX', 'G')`." ] }, { @@ -60,12 +68,13 @@ "metadata": {}, "outputs": [], "source": [ - "def Words(text: str) -> set:\n", - " \"\"\"All the valid words from a str of text.\"\"\"\n", + "def Words(text) -> set:\n", + " \"\"\"The set of all the valid space-separated words in a str.\"\"\"\n", " return {w for w in text.upper().split() \n", " if len(w) >= 4 and 'S' not in w and len(set(w)) <= 7}\n", "\n", "def word_score(word) -> int: \n", + " \"\"\"The points for this word, including bonus for pangram.\"\"\"\n", " N = len(word)\n", " bonus = (7 if is_pangram(word) else 0)\n", " return (1 if N == 4 else N + bonus)\n", @@ -124,7 +133,7 @@ { "data": { "text/plain": [ - "{'GLAM': 1, 'MEGAPLEX': 15, 'GAME': 1, 'MAPLE': 5, 'PELAGIC': 14, 'AMALGAM': 7}" + "{'AMALGAM': 7, 'MEGAPLEX': 15, 'GLAM': 1, 'MAPLE': 5, 'GAME': 1, 'PELAGIC': 14}" ] }, "execution_count": 4, @@ -164,12 +173,12 @@ { "data": { "text/plain": [ - "{'GLAM': 'AGLM',\n", + "{'AMALGAM': 'AGLM',\n", " 'MEGAPLEX': 'AEGLMPX',\n", - " 'GAME': 'AEGM',\n", + " 'GLAM': 'AGLM',\n", " 'MAPLE': 'AELMP',\n", - " 'PELAGIC': 'ACEGILP',\n", - " 'AMALGAM': 'AGLM'}" + " 'GAME': 'AEGM',\n", + " 'PELAGIC': 'ACEGILP'}" ] }, "execution_count": 6, @@ -181,13 +190,6 @@ "{w: letterset(w) for w in words}" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that `AMALGAM` and `GLAM` have the same letterset, `AGLM`." - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -236,13 +238,6 @@ "len(enable1)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that only about 1/4 of the words are valid: the others are either shorter than 4 letters in length, or contain an 'S', or have more than 7 distinct letters." - ] - }, { "cell_type": "code", "execution_count": 9, @@ -251,16 +246,16 @@ { "data": { "text/plain": [ - "['TRIFLED',\n", - " 'FLYPAPER',\n", - " 'CANTONMENT',\n", - " 'COLLOGUING',\n", - " 'TRUNDLER',\n", - " 'UNPITIED',\n", - " 'KNUCKLING',\n", - " 'DEVALUATE',\n", - " 'UNAFRAID',\n", - " 'INJECTANT']" + "['CRACKLIER',\n", + " 'TURBINE',\n", + " 'METHIONINE',\n", + " 'UPGAZING',\n", + " 'CUMBERED',\n", + " 'BREEZEWAY',\n", + " 'JAMBING',\n", + " 'PAPERBACK',\n", + " 'TRIPINNATE',\n", + " 'TUNICAE']" ] }, "execution_count": 9, @@ -297,7 +292,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "So: 14,741 candidate pangrams. Feasible.\n", + "So: we start with 172,820 words in the word list, reduce that to 44,585 valid words (the others are either shorter than 4 letters in length, or contain an 'S', or have more than 7 distinct letters), and discover that 14,741 of those words are pangrams. \n", "\n", "I'm also curious: what's the highest-scoring individual word?" ] @@ -330,9 +325,10 @@ "# Efficiency: Caching a Scoring Table\n", "\n", "The goal is to find the honeycomb that maximizes the `game_score`: the total score of all words that can be made with the honeycomb. I've chosen to go down the path of considering all 14,741 pangrams, and all 7 centers for each pangram, for a total of 103,187 candidate honeycombs. \n", - "I'll make things more efficient by *caching* some important information so I don't need to recompute it 103,187 times.\n", + "I'll make things more efficient by *caching* some important information after computing it once, so I don't need to recompute it 103,187 times.\n", "- For each word, I'll precompute the `letterset` and the `word_score`.\n", - "- For each letterset, I'll precompute the total `word_score` points (over all the words with that letterset)." + "- For each letterset, I'll add up the total `word_score` points (over all the words with that letterset).\n", + "- The function `scoring_table(words)` will return a table (dict) with this information:" ] }, { @@ -345,8 +341,7 @@ " \"\"\"Return a dict of {letterset: sum_of_word_scores} over words.\"\"\"\n", " table = Counter()\n", " for w in words:\n", - " s = letterset(w)\n", - " table[s] += word_score(w)\n", + " table[letterset(w)] += word_score(w)\n", " return table" ] }, @@ -358,7 +353,7 @@ { "data": { "text/plain": [ - "Counter({'AGLM': 8, 'AEGLMPX': 15, 'AEGM': 1, 'AELMP': 5, 'ACEGILP': 14})" + "Counter({'AGLM': 8, 'AEGLMPX': 15, 'AELMP': 5, 'AEGM': 1, 'ACEGILP': 14})" ] }, "execution_count": 13, @@ -375,9 +370,8 @@ "metadata": {}, "source": [ "Note the letterset\n", - "`'AGLM'` scores 8 points as the sum over two words: 7 for `'AMALGAM'` and 1 for `'GLAM'`. \n", - "\n", - "The following says that there are about twice as many words as lettersets: on average about two words have the same letterset.\n", + "`'AGLM'` scores 8 points as the sum over two words: 7 for `'AMALGAM'` and 1 for `'GLAM'`. The other lettersets get their points from just one word.\n", + "The following calculation says that there are about twice as many words as lettersets: on average about two words have the same letterset.\n", "\n" ] }, @@ -407,10 +401,10 @@ "source": [ "# Computing the Game Score\n", "\n", - "Given a honeycomb we can efficiently compute the `game_score` as follows:\n", - "- For each of the 103,187 honeycombs, I could look at every posssible word to see if it can be made. But there are 44,585 words. Infeasible.\n", - "- Instead, generate every possible *subset* of the letters in the honeycomb. A subset must include the central letter, and it may or may not include each of the other 6 letters, so there are $2^6 = 64$ subsets. The function `letter_subsets` returns these.\n", - "- We already have letterset scores in the scoring table, so just fetch the 64 entries in the scoring table and add them up.\n", + "The brute force approach would be to take each of the 103,187 honeycombs, and for each honeycomb look at each of the 44,585 words and add up the word scores of the words that can be made by the honeycomb. That seems slow. I have an idea for a faster approach:\n", + "\n", + "- For each honeycomb, generate every possible *subset* of the letters in the honeycomb. A subset must include the central letter, and it may or may not include each of the other 6 letters, so there are $2^6 = 64$ subsets. The function `letter_subsets(letters)` returns these.\n", + "- We already have letterset scores in the scoring table, so we can compute the `game_score` of a honeycomb just by fetching 64 entries in the scoring table and adding them up.\n", "- 64 is less than 44,585, so that's a nice optimization!\n" ] }, @@ -421,7 +415,7 @@ "outputs": [], "source": [ "def game_score(letters, center, table) -> int:\n", - " \"The total score for this honeycomb, given a scoring table.\"\n", + " \"\"\"The total score for this honeycomb, given a scoring table.\"\"\"\n", " subsets = letter_subsets(letters, center)\n", " return sum(table[s] for s in subsets)\n", "\n", @@ -484,7 +478,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Trying `game_score`:" + "Trying out `game_score`:" ] }, { @@ -531,16 +525,43 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# The Solution: The Best Honeycomb\n", - "\n", - "\n", - "Finally, here's the function that will give us the solution: `best_honeycomb` searches through every possible pangram and center and finds the combination that gives the highest game score:" + "Let's choose some more common letters and see if we can score more:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2240" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "game_score('ETANHRD', 'E', scoring_table(enable1)) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The Solution: The Best Honeycomb\n", + "\n", + "\n", + "Finally, here's the function that will give us the solution: `best_honeycomb` searches through every possible pangram and center and finds the combination that gives the highest game score:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, "outputs": [], "source": [ "def best_honeycomb(words) -> tuple: \n", @@ -561,7 +582,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -570,7 +591,7 @@ "[29, 'AEGLMPX', 'M']" ] }, - "execution_count": 21, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -588,15 +609,15 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 4.15 s, sys: 4.46 ms, total: 4.16 s\n", - "Wall time: 4.16 s\n" + "CPU times: user 4.28 s, sys: 11.2 ms, total: 4.29 s\n", + "Wall time: 4.3 s\n" ] }, { @@ -605,7 +626,7 @@ "[3898, 'AEGINRT', 'R']" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -625,57 +646,37 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": { "scrolled": false }, "outputs": [], "source": [ + "def scoring_words(letters, center, words) -> set:\n", + " \"\"\"The set of words that this honeycomb can make.\"\"\"\n", + " subsets = letter_subsets(letters, center)\n", + " return {w for w in words if letterset(w) in subsets}\n", + "\n", "def report(words):\n", " \"\"\"Print stats and word scores for the best honeycomb on these words.\"\"\"\n", " (score, letters, center) = best_honeycomb(words)\n", " sw = scoring_words(letters, center, words)\n", " top = max(sw, key=word_score)\n", " np = sum(map(is_pangram, sw))\n", + " assert score == sum(map(word_score, sw))\n", " print(f'''\n", " The highest-scoring honeycomb for this list of {len(words)} words is:\n", " {letters} (center {center})\n", " It scores {score} points on {len(sw)} words with {np} pangrams*\n", " The top scoring word is {top} for {word_score(top)} points.\\n''')\n", - " for w in sorted(sw):\n", - " print(f'{w} ({word_score(w)}) {\"*\" if is_pangram(w) else \"\"}')\n", - " \n", - "def scoring_words(letters, center, words) -> set:\n", - " \"\"\"What words can this honeycomb make?\"\"\"\n", - " subsets = letter_subsets(letters, center)\n", - " return {w for w in words if letterset(w) in subsets}" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " The highest-scoring honeycomb for this list of 6 words is:\n", - " AEGLMPX (center M)\n", - " It scores 29 points on 5 words with 1 pangrams*\n", - " The top scoring word is MEGAPLEX for 15 points.\n", - "\n", - "AMALGAM (7) \n", - "GAME (1) \n", - "GLAM (1) \n", - "MAPLE (5) \n", - "MEGAPLEX (15) *\n" - ] - } - ], - "source": [ - "report(words)" + " printcolumns(4, 20, [f'{w} ({word_score(w)}){\"*\" if is_pangram(w) else \" \"}'\n", + " for w in sorted(sw)])\n", + "\n", + "def printcolumns(cols, width, items):\n", + " \"\"\"Print items in designated columns of designated width.\"\"\"\n", + " for i, item in enumerate(items, 1):\n", + " print(item.ljust(width), end='')\n", + " if i % cols == 0: print()" ] }, { @@ -695,543 +696,141 @@ " It scores 3898 points on 537 words with 50 pangrams*\n", " The top scoring word is REINTEGRATING for 20 points.\n", "\n", - "AERATE (6) \n", - "AERATING (15) *\n", - "AERIE (5) \n", - "AERIER (6) \n", - "AGAR (1) \n", - "AGER (1) \n", - "AGGER (5) \n", - "AGGREGATE (9) \n", - "AGGREGATING (18) *\n", - "AGINNER (7) \n", - "AGRARIAN (8) \n", - "AGREE (5) \n", - "AGREEING (8) \n", - "AGRIA (5) \n", - "AIGRET (6) \n", - "AIGRETTE (8) \n", - "AIRER (5) \n", - "AIRIER (6) \n", - "AIRING (6) \n", - "AIRN (1) \n", - "AIRT (1) \n", - "AIRTING (7) \n", - "ANEAR (5) \n", - "ANEARING (8) \n", - "ANERGIA (7) \n", - "ANGARIA (7) \n", - "ANGER (5) \n", - "ANGERING (8) \n", - "ANGRIER (7) \n", - "ANTEATER (8) \n", - "ANTIAIR (7) \n", - "ANTIAR (6) \n", - "ANTIARIN (8) \n", - "ANTRA (5) \n", - "ANTRE (5) \n", - "AREA (1) \n", - "AREAE (5) \n", - "ARENA (5) \n", - "ARENITE (7) \n", - "ARETE (5) \n", - "ARGENT (6) \n", - "ARGENTINE (16) *\n", - "ARGENTITE (16) *\n", - "ARGININE (8) \n", - "ARIA (1) \n", - "ARIETTA (7) \n", - "ARIETTE (7) \n", - "ARRAIGN (7) \n", - "ARRAIGNING (10) \n", - "ARRANGE (7) \n", - "ARRANGER (8) \n", - "ARRANGING (9) \n", - "ARRANT (6) \n", - "ARREAR (6) \n", - "ARREARAGE (9) \n", - "ARTIER (6) \n", - "ATRIA (5) \n", - "ATTAINER (8) \n", - "ATTAR (5) \n", - "ATTIRE (6) \n", - "ATTIRING (8) \n", - "ATTRITE (7) \n", - "EAGER (5) \n", - "EAGERER (7) \n", - "EAGRE (5) \n", - "EARING (6) \n", - "EARN (1) \n", - "EARNER (6) \n", - "EARNING (7) \n", - "EARRING (7) \n", - "EATER (5) \n", - "EERIE (5) \n", - "EERIER (6) \n", - "EGER (1) \n", - "EGGAR (5) \n", - "EGGER (5) \n", - "EGRET (5) \n", - "ENGAGER (7) \n", - "ENGINEER (8) \n", - "ENGINEERING (11) \n", - "ENGIRT (6) \n", - "ENGRAIN (7) \n", - "ENGRAINING (10) \n", - "ENRAGE (6) \n", - "ENRAGING (8) \n", - "ENTER (5) \n", - "ENTERA (6) \n", - "ENTERER (7) \n", - "ENTERING (8) \n", - "ENTERTAIN (9) \n", - "ENTERTAINER (11) \n", - "ENTERTAINING (19) *\n", - "ENTIRE (6) \n", - "ENTRAIN (7) \n", - "ENTRAINER (9) \n", - "ENTRAINING (17) *\n", - "ENTRANT (7) \n", - "ENTREAT (7) \n", - "ENTREATING (17) *\n", - "ENTREE (6) \n", - "ERGATE (6) \n", - "ERNE (1) \n", - "ERRANT (6) \n", - "ERRATA (6) \n", - "ERRING (6) \n", - "ETAGERE (7) \n", - "ETERNE (6) \n", - "GAGER (5) \n", - "GAGGER (6) \n", - "GAINER (6) \n", - "GAITER (6) \n", - "GANGER (6) \n", - "GANGRENE (8) \n", - "GANGRENING (10) \n", - "GARAGE (6) \n", - "GARAGING (8) \n", - "GARGET (6) \n", - "GARNER (6) \n", - "GARNERING (9) \n", - "GARNET (6) \n", - "GARNI (5) \n", - "GARNIERITE (17) *\n", - "GARRET (6) \n", - "GARRING (7) \n", - "GARTER (6) \n", - "GARTERING (16) *\n", - "GEAR (1) \n", - "GEARING (7) \n", - "GENERA (6) \n", - "GENERATE (8) \n", - "GENERATING (17) *\n", - "GENRE (5) \n", - "GERENT (6) \n", - "GETTER (6) \n", - "GETTERING (9) \n", - "GINGER (6) \n", - "GINGERING (9) \n", - "GINNER (6) \n", - "GINNIER (7) \n", - "GIRN (1) \n", - "GIRNING (7) \n", - "GIRT (1) \n", - "GIRTING (7) \n", - "GITTERN (7) \n", - "GNAR (1) \n", - "GNARR (5) \n", - "GNARRING (8) \n", - "GNATTIER (15) *\n", - "GRAIN (5) \n", - "GRAINER (7) \n", - "GRAINIER (8) \n", - "GRAINING (8) \n", - "GRAN (1) \n", - "GRANA (5) \n", - "GRANGE (6) \n", - "GRANGER (7) \n", - "GRANITA (7) \n", - "GRANITE (14) *\n", - "GRANNIE (7) \n", - "GRANT (5) \n", - "GRANTEE (7) \n", - "GRANTER (7) \n", - "GRANTING (8) \n", - "GRAT (1) \n", - "GRATE (5) \n", - "GRATER (6) \n", - "GRATIN (6) \n", - "GRATINE (14) *\n", - "GRATINEE (15) *\n", - "GRATINEEING (18) *\n", - "GRATING (7) \n", - "GREAT (5) \n", - "GREATEN (7) \n", - "GREATENING (17) *\n", - "GREATER (7) \n", - "GREE (1) \n", - "GREEGREE (8) \n", - "GREEING (7) \n", - "GREEN (5) \n", - "GREENER (7) \n", - "GREENGAGE (9) \n", - "GREENIE (7) \n", - "GREENIER (8) \n", - "GREENING (8) \n", - "GREET (5) \n", - "GREETER (7) \n", - "GREETING (8) \n", - "GREGARINE (9) \n", - "GREIGE (6) \n", - "GRIG (1) \n", - "GRIGRI (6) \n", - "GRIN (1) \n", - "GRINNER (7) \n", - "GRINNING (8) \n", - "GRIT (1) \n", - "GRITTIER (8) \n", - "GRITTING (8) \n", - "IGNITER (7) \n", - "INANER (6) \n", - "INERRANT (8) \n", - "INERT (5) \n", - "INERTIA (7) \n", - "INERTIAE (8) \n", - "INGRAIN (7) \n", - "INGRAINING (10) \n", - "INGRATE (14) *\n", - "INGRATIATE (17) *\n", - "INGRATIATING (12) \n", - "INNER (5) \n", - "INTEGER (7) \n", - "INTEGRATE (16) *\n", - "INTEGRATING (18) *\n", - "INTENERATE (10) \n", - "INTENERATING (19) *\n", - "INTER (5) \n", - "INTERAGE (15) *\n", - "INTERGANG (16) *\n", - "INTERN (6) \n", - "INTERNE (7) \n", - "INTERNEE (8) \n", - "INTERNING (9) \n", - "INTERREGNA (17) *\n", - "INTERRING (9) \n", - "INTERTIE (8) \n", - "INTRANT (7) \n", - "INTREAT (7) \n", - "INTREATING (17) *\n", - "INTRIGANT (9) \n", - "IRATE (5) \n", - "IRATER (6) \n", - "IRING (5) \n", - "IRRIGATE (8) \n", - "IRRIGATING (10) \n", - "IRRITANT (8) \n", - "IRRITATE (8) \n", - "IRRITATING (10) \n", - "ITERANT (7) \n", - "ITERATE (7) \n", - "ITERATING (16) *\n", - "ITINERANT (9) \n", - "ITINERATE (9) \n", - "ITINERATING (18) *\n", - "NAGGER (6) \n", - "NAGGIER (7) \n", - "NAIRA (5) \n", - "NARINE (6) \n", - "NARRATE (7) \n", - "NARRATER (8) \n", - "NARRATING (9) \n", - "NATTER (6) \n", - "NATTERING (16) *\n", - "NATTIER (7) \n", - "NEAR (1) \n", - "NEARER (6) \n", - "NEARING (7) \n", - "NEATER (6) \n", - "NEGATER (7) \n", - "NETTER (6) \n", - "NETTIER (7) \n", - "NIGGER (6) \n", - "NITER (5) \n", - "NITERIE (7) \n", - "NITRATE (7) \n", - "NITRATING (9) \n", - "NITRE (5) \n", - "NITRITE (7) \n", - "NITTIER (7) \n", - "RAGA (1) \n", - "RAGE (1) \n", - "RAGEE (5) \n", - "RAGGEE (6) \n", - "RAGGING (7) \n", - "RAGI (1) \n", - "RAGING (6) \n", - "RAGTAG (6) \n", - "RAIA (1) \n", - "RAIN (1) \n", - "RAINIER (7) \n", - "RAINING (7) \n", - "RANEE (5) \n", - "RANG (1) \n", - "RANGE (5) \n", - "RANGER (6) \n", - "RANGIER (7) \n", - "RANGING (7) \n", - "RANI (1) \n", - "RANT (1) \n", - "RANTER (6) \n", - "RANTING (7) \n", - "RARE (1) \n", - "RARER (5) \n", - "RARING (6) \n", - "RATAN (5) \n", - "RATATAT (7) \n", - "RATE (1) \n", - "RATER (5) \n", - "RATINE (6) \n", - "RATING (6) \n", - "RATITE (6) \n", - "RATTAN (6) \n", - "RATTEEN (7) \n", - "RATTEN (6) \n", - "RATTENER (8) \n", - "RATTENING (16) *\n", - "RATTER (6) \n", - "RATTIER (7) \n", - "RATTING (7) \n", - "REAGENT (7) \n", - "REAGGREGATE (11) \n", - "REAGGREGATING (20) *\n", - "REAGIN (6) \n", - "REAR (1) \n", - "REARER (6) \n", - "REARING (7) \n", - "REARRANGE (9) \n", - "REARRANGING (11) \n", - "REATA (5) \n", - "REATTAIN (8) \n", - "REATTAINING (18) *\n", - "REEARN (6) \n", - "REEARNING (9) \n", - "REENGAGE (8) \n", - "REENGAGING (10) \n", - "REENGINEER (10) \n", - "REENGINEERING (13) \n", - "REENTER (7) \n", - "REENTERING (10) \n", - "REENTRANT (9) \n", - "REGAIN (6) \n", - "REGAINER (8) \n", - "REGAINING (9) \n", - "REGATTA (7) \n", - "REGEAR (6) \n", - "REGEARING (9) \n", - "REGENERATE (10) \n", - "REGENERATING (19) *\n", - "REGENT (6) \n", - "REGGAE (6) \n", - "REGINA (6) \n", - "REGINAE (7) \n", - "REGNA (5) \n", - "REGNANT (7) \n", - "REGRANT (7) \n", - "REGRANTING (17) *\n", - "REGRATE (7) \n", - "REGRATING (16) *\n", - "REGREEN (7) \n", - "REGREENING (10) \n", - "REGREET (7) \n", - "REGREETING (10) \n", - "REGRET (6) \n", - "REGRETTER (9) \n", - "REGRETTING (10) \n", - "REIGN (5) \n", - "REIGNING (8) \n", - "REIGNITE (8) \n", - "REIGNITING (10) \n", - "REIN (1) \n", - "REINING (7) \n", - "REINITIATE (10) \n", - "REINITIATING (19) *\n", - "REINTEGRATE (18) *\n", - "REINTEGRATING (20) *\n", - "REINTER (7) \n", - "REINTERRING (11) \n", - "REITERATE (9) \n", - "REITERATING (18) *\n", - "RENEGE (6) \n", - "RENEGER (7) \n", - "RENEGING (8) \n", - "RENIG (5) \n", - "RENIGGING (9) \n", - "RENIN (5) \n", - "RENITENT (8) \n", - "RENNET (6) \n", - "RENNIN (6) \n", - "RENT (1) \n", - "RENTE (5) \n", - "RENTER (6) \n", - "RENTIER (7) \n", - "RENTING (7) \n", - "RERAN (5) \n", - "RERIG (5) \n", - "RERIGGING (9) \n", - "RETAG (5) \n", - "RETAGGING (16) *\n", - "RETAIN (6) \n", - "RETAINER (8) \n", - "RETAINING (16) *\n", - "RETARGET (8) \n", - "RETARGETING (18) *\n", - "RETE (1) \n", - "RETEAR (6) \n", - "RETEARING (16) *\n", - "RETENE (6) \n", - "RETIA (5) \n", - "RETIARII (8) \n", - "RETIE (5) \n", - "RETINA (6) \n", - "RETINAE (7) \n", - "RETINE (6) \n", - "RETINENE (8) \n", - "RETINITE (8) \n", - "RETINT (6) \n", - "RETINTING (9) \n", - "RETIRANT (8) \n", - "RETIRE (6) \n", - "RETIREE (7) \n", - "RETIRER (7) \n", - "RETIRING (8) \n", - "RETRAIN (7) \n", - "RETRAINING (17) *\n", - "RETREAT (7) \n", - "RETREATANT (10) \n", - "RETREATER (9) \n", - "RETREATING (17) *\n", - "RETTING (7) \n", - "RIANT (5) \n", - "RIATA (5) \n", - "RIGGER (6) \n", - "RIGGING (7) \n", - "RING (1) \n", - "RINGENT (7) \n", - "RINGER (6) \n", - "RINGGIT (7) \n", - "RINGING (7) \n", - "RINNING (7) \n", - "RITE (1) \n", - "RITTER (6) \n", - "TAGGER (6) \n", - "TAGRAG (6) \n", - "TANAGER (7) \n", - "TANGERINE (16) *\n", - "TANGIER (14) *\n", - "TANNER (6) \n", - "TANTARA (7) \n", - "TANTRA (6) \n", - "TARE (1) \n", - "TARGE (5) \n", - "TARGET (6) \n", - "TARGETING (16) *\n", - "TARING (6) \n", - "TARN (1) \n", - "TARRE (5) \n", - "TARRIER (7) \n", - "TARRING (7) \n", - "TART (1) \n", - "TARTAN (6) \n", - "TARTANA (7) \n", - "TARTAR (6) \n", - "TARTER (6) \n", - "TARTING (7) \n", - "TARTRATE (8) \n", - "TATAR (5) \n", - "TATER (5) \n", - "TATTER (6) \n", - "TATTERING (16) *\n", - "TATTIER (7) \n", - "TEAR (1) \n", - "TEARER (6) \n", - "TEARIER (7) \n", - "TEARING (14) *\n", - "TEENAGER (8) \n", - "TEENER (6) \n", - "TEENIER (7) \n", - "TEETER (6) \n", - "TEETERING (9) \n", - "TENNER (6) \n", - "TENTER (6) \n", - "TENTERING (9) \n", - "TENTIER (7) \n", - "TERAI (5) \n", - "TERETE (6) \n", - "TERGA (5) \n", - "TERGITE (7) \n", - "TERN (1) \n", - "TERNATE (7) \n", - "TERNE (5) \n", - "TERRA (5) \n", - "TERRAE (6) \n", - "TERRAIN (7) \n", - "TERRANE (7) \n", - "TERRARIA (8) \n", - "TERREEN (7) \n", - "TERRENE (7) \n", - "TERRET (6) \n", - "TERRIER (7) \n", - "TERRINE (7) \n", - "TERRIT (6) \n", - "TERTIAN (7) \n", - "TETRA (5) \n", - "TETTER (6) \n", - "TIARA (5) \n", - "TIER (1) \n", - "TIERING (7) \n", - "TIGER (5) \n", - "TINIER (6) \n", - "TINNER (6) \n", - "TINNIER (7) \n", - "TINTER (6) \n", - "TIRE (1) \n", - "TIRING (6) \n", - "TITER (5) \n", - "TITRANT (7) \n", - "TITRATE (7) \n", - "TITRATING (9) \n", - "TITRE (5) \n", - "TITTER (6) \n", - "TITTERER (8) \n", - "TITTERING (9) \n", - "TRAGI (5) \n", - "TRAIN (5) \n", - "TRAINEE (7) \n", - "TRAINER (7) \n", - "TRAINING (8) \n", - "TRAIT (5) \n", - "TREAT (5) \n", - "TREATER (7) \n", - "TREATING (15) *\n", - "TREE (1) \n", - "TREEING (7) \n", - "TREEN (5) \n", - "TRET (1) \n", - "TRIAGE (6) \n", - "TRIAGING (8) \n", - "TRIENE (6) \n", - "TRIENNIA (8) \n", - "TRIER (5) \n", - "TRIG (1) \n", - "TRIGGER (7) \n", - "TRIGGERING (10) \n", - "TRIGGING (8) \n", - "TRINE (5) \n", - "TRINING (7) \n", - "TRINITARIAN (11) \n", - "TRITE (5) \n", - "TRITER (6) \n" + "AERATE (6) AERATING (15)* AERIE (5) AERIER (6) \n", + "AGAR (1) AGER (1) AGGER (5) AGGREGATE (9) \n", + "AGGREGATING (18)* AGINNER (7) AGRARIAN (8) AGREE (5) \n", + "AGREEING (8) AGRIA (5) AIGRET (6) AIGRETTE (8) \n", + "AIRER (5) AIRIER (6) AIRING (6) AIRN (1) \n", + "AIRT (1) AIRTING (7) ANEAR (5) ANEARING (8) \n", + "ANERGIA (7) ANGARIA (7) ANGER (5) ANGERING (8) \n", + "ANGRIER (7) ANTEATER (8) ANTIAIR (7) ANTIAR (6) \n", + "ANTIARIN (8) ANTRA (5) ANTRE (5) AREA (1) \n", + "AREAE (5) ARENA (5) ARENITE (7) ARETE (5) \n", + "ARGENT (6) ARGENTINE (16)* ARGENTITE (16)* ARGININE (8) \n", + "ARIA (1) ARIETTA (7) ARIETTE (7) ARRAIGN (7) \n", + "ARRAIGNING (10) ARRANGE (7) ARRANGER (8) ARRANGING (9) \n", + "ARRANT (6) ARREAR (6) ARREARAGE (9) ARTIER (6) \n", + "ATRIA (5) ATTAINER (8) ATTAR (5) ATTIRE (6) \n", + "ATTIRING (8) ATTRITE (7) EAGER (5) EAGERER (7) \n", + "EAGRE (5) EARING (6) EARN (1) EARNER (6) \n", + "EARNING (7) EARRING (7) EATER (5) EERIE (5) \n", + "EERIER (6) EGER (1) EGGAR (5) EGGER (5) \n", + "EGRET (5) ENGAGER (7) ENGINEER (8) ENGINEERING (11) \n", + "ENGIRT (6) ENGRAIN (7) ENGRAINING (10) ENRAGE (6) \n", + "ENRAGING (8) ENTER (5) ENTERA (6) ENTERER (7) \n", + "ENTERING (8) ENTERTAIN (9) ENTERTAINER (11) ENTERTAINING (19)* \n", + "ENTIRE (6) ENTRAIN (7) ENTRAINER (9) ENTRAINING (17)* \n", + "ENTRANT (7) ENTREAT (7) ENTREATING (17)* ENTREE (6) \n", + "ERGATE (6) ERNE (1) ERRANT (6) ERRATA (6) \n", + "ERRING (6) ETAGERE (7) ETERNE (6) GAGER (5) \n", + "GAGGER (6) GAINER (6) GAITER (6) GANGER (6) \n", + "GANGRENE (8) GANGRENING (10) GARAGE (6) GARAGING (8) \n", + "GARGET (6) GARNER (6) GARNERING (9) GARNET (6) \n", + "GARNI (5) GARNIERITE (17)* GARRET (6) GARRING (7) \n", + "GARTER (6) GARTERING (16)* GEAR (1) GEARING (7) \n", + "GENERA (6) GENERATE (8) GENERATING (17)* GENRE (5) \n", + "GERENT (6) GETTER (6) GETTERING (9) GINGER (6) \n", + "GINGERING (9) GINNER (6) GINNIER (7) GIRN (1) \n", + "GIRNING (7) GIRT (1) GIRTING (7) GITTERN (7) \n", + "GNAR (1) GNARR (5) GNARRING (8) GNATTIER (15)* \n", + "GRAIN (5) GRAINER (7) GRAINIER (8) GRAINING (8) \n", + "GRAN (1) GRANA (5) GRANGE (6) GRANGER (7) \n", + "GRANITA (7) GRANITE (14)* GRANNIE (7) GRANT (5) \n", + "GRANTEE (7) GRANTER (7) GRANTING (8) GRAT (1) \n", + "GRATE (5) GRATER (6) GRATIN (6) GRATINE (14)* \n", + "GRATINEE (15)* GRATINEEING (18)* GRATING (7) GREAT (5) \n", + "GREATEN (7) GREATENING (17)* GREATER (7) GREE (1) \n", + "GREEGREE (8) GREEING (7) GREEN (5) GREENER (7) \n", + "GREENGAGE (9) GREENIE (7) GREENIER (8) GREENING (8) \n", + "GREET (5) GREETER (7) GREETING (8) GREGARINE (9) \n", + "GREIGE (6) GRIG (1) GRIGRI (6) GRIN (1) \n", + "GRINNER (7) GRINNING (8) GRIT (1) GRITTIER (8) \n", + "GRITTING (8) IGNITER (7) INANER (6) INERRANT (8) \n", + "INERT (5) INERTIA (7) INERTIAE (8) INGRAIN (7) \n", + "INGRAINING (10) INGRATE (14)* INGRATIATE (17)* INGRATIATING (12) \n", + "INNER (5) INTEGER (7) INTEGRATE (16)* INTEGRATING (18)* \n", + "INTENERATE (10) INTENERATING (19)* INTER (5) INTERAGE (15)* \n", + "INTERGANG (16)* INTERN (6) INTERNE (7) INTERNEE (8) \n", + "INTERNING (9) INTERREGNA (17)* INTERRING (9) INTERTIE (8) \n", + "INTRANT (7) INTREAT (7) INTREATING (17)* INTRIGANT (9) \n", + "IRATE (5) IRATER (6) IRING (5) IRRIGATE (8) \n", + "IRRIGATING (10) IRRITANT (8) IRRITATE (8) IRRITATING (10) \n", + "ITERANT (7) ITERATE (7) ITERATING (16)* ITINERANT (9) \n", + "ITINERATE (9) ITINERATING (18)* NAGGER (6) NAGGIER (7) \n", + "NAIRA (5) NARINE (6) NARRATE (7) NARRATER (8) \n", + "NARRATING (9) NATTER (6) NATTERING (16)* NATTIER (7) \n", + "NEAR (1) NEARER (6) NEARING (7) NEATER (6) \n", + "NEGATER (7) NETTER (6) NETTIER (7) NIGGER (6) \n", + "NITER (5) NITERIE (7) NITRATE (7) NITRATING (9) \n", + "NITRE (5) NITRITE (7) NITTIER (7) RAGA (1) \n", + "RAGE (1) RAGEE (5) RAGGEE (6) RAGGING (7) \n", + "RAGI (1) RAGING (6) RAGTAG (6) RAIA (1) \n", + "RAIN (1) RAINIER (7) RAINING (7) RANEE (5) \n", + "RANG (1) RANGE (5) RANGER (6) RANGIER (7) \n", + "RANGING (7) RANI (1) RANT (1) RANTER (6) \n", + "RANTING (7) RARE (1) RARER (5) RARING (6) \n", + "RATAN (5) RATATAT (7) RATE (1) RATER (5) \n", + "RATINE (6) RATING (6) RATITE (6) RATTAN (6) \n", + "RATTEEN (7) RATTEN (6) RATTENER (8) RATTENING (16)* \n", + "RATTER (6) RATTIER (7) RATTING (7) REAGENT (7) \n", + "REAGGREGATE (11) REAGGREGATING (20)* REAGIN (6) REAR (1) \n", + "REARER (6) REARING (7) REARRANGE (9) REARRANGING (11) \n", + "REATA (5) REATTAIN (8) REATTAINING (18)* REEARN (6) \n", + "REEARNING (9) REENGAGE (8) REENGAGING (10) REENGINEER (10) \n", + "REENGINEERING (13) REENTER (7) REENTERING (10) REENTRANT (9) \n", + "REGAIN (6) REGAINER (8) REGAINING (9) REGATTA (7) \n", + "REGEAR (6) REGEARING (9) REGENERATE (10) REGENERATING (19)* \n", + "REGENT (6) REGGAE (6) REGINA (6) REGINAE (7) \n", + "REGNA (5) REGNANT (7) REGRANT (7) REGRANTING (17)* \n", + "REGRATE (7) REGRATING (16)* REGREEN (7) REGREENING (10) \n", + "REGREET (7) REGREETING (10) REGRET (6) REGRETTER (9) \n", + "REGRETTING (10) REIGN (5) REIGNING (8) REIGNITE (8) \n", + "REIGNITING (10) REIN (1) REINING (7) REINITIATE (10) \n", + "REINITIATING (19)* REINTEGRATE (18)* REINTEGRATING (20)* REINTER (7) \n", + "REINTERRING (11) REITERATE (9) REITERATING (18)* RENEGE (6) \n", + "RENEGER (7) RENEGING (8) RENIG (5) RENIGGING (9) \n", + "RENIN (5) RENITENT (8) RENNET (6) RENNIN (6) \n", + "RENT (1) RENTE (5) RENTER (6) RENTIER (7) \n", + "RENTING (7) RERAN (5) RERIG (5) RERIGGING (9) \n", + "RETAG (5) RETAGGING (16)* RETAIN (6) RETAINER (8) \n", + "RETAINING (16)* RETARGET (8) RETARGETING (18)* RETE (1) \n", + "RETEAR (6) RETEARING (16)* RETENE (6) RETIA (5) \n", + "RETIARII (8) RETIE (5) RETINA (6) RETINAE (7) \n", + "RETINE (6) RETINENE (8) RETINITE (8) RETINT (6) \n", + "RETINTING (9) RETIRANT (8) RETIRE (6) RETIREE (7) \n", + "RETIRER (7) RETIRING (8) RETRAIN (7) RETRAINING (17)* \n", + "RETREAT (7) RETREATANT (10) RETREATER (9) RETREATING (17)* \n", + "RETTING (7) RIANT (5) RIATA (5) RIGGER (6) \n", + "RIGGING (7) RING (1) RINGENT (7) RINGER (6) \n", + "RINGGIT (7) RINGING (7) RINNING (7) RITE (1) \n", + "RITTER (6) TAGGER (6) TAGRAG (6) TANAGER (7) \n", + "TANGERINE (16)* TANGIER (14)* TANNER (6) TANTARA (7) \n", + "TANTRA (6) TARE (1) TARGE (5) TARGET (6) \n", + "TARGETING (16)* TARING (6) TARN (1) TARRE (5) \n", + "TARRIER (7) TARRING (7) TART (1) TARTAN (6) \n", + "TARTANA (7) TARTAR (6) TARTER (6) TARTING (7) \n", + "TARTRATE (8) TATAR (5) TATER (5) TATTER (6) \n", + "TATTERING (16)* TATTIER (7) TEAR (1) TEARER (6) \n", + "TEARIER (7) TEARING (14)* TEENAGER (8) TEENER (6) \n", + "TEENIER (7) TEETER (6) TEETERING (9) TENNER (6) \n", + "TENTER (6) TENTERING (9) TENTIER (7) TERAI (5) \n", + "TERETE (6) TERGA (5) TERGITE (7) TERN (1) \n", + "TERNATE (7) TERNE (5) TERRA (5) TERRAE (6) \n", + "TERRAIN (7) TERRANE (7) TERRARIA (8) TERREEN (7) \n", + "TERRENE (7) TERRET (6) TERRIER (7) TERRINE (7) \n", + "TERRIT (6) TERTIAN (7) TETRA (5) TETTER (6) \n", + "TIARA (5) TIER (1) TIERING (7) TIGER (5) \n", + "TINIER (6) TINNER (6) TINNIER (7) TINTER (6) \n", + "TIRE (1) TIRING (6) TITER (5) TITRANT (7) \n", + "TITRATE (7) TITRATING (9) TITRE (5) TITTER (6) \n", + "TITTERER (8) TITTERING (9) TRAGI (5) TRAIN (5) \n", + "TRAINEE (7) TRAINER (7) TRAINING (8) TRAIT (5) \n", + "TREAT (5) TREATER (7) TREATING (15)* TREE (1) \n", + "TREEING (7) TREEN (5) TRET (1) TRIAGE (6) \n", + "TRIAGING (8) TRIENE (6) TRIENNIA (8) TRIER (5) \n", + "TRIG (1) TRIGGER (7) TRIGGERING (10) TRIGGING (8) \n", + "TRINE (5) TRINING (7) TRINITARIAN (11) TRITE (5) \n", + "TRITER (6) " ] } ],