Creation doesn't create multiple copies of a word, created a large grid for the puzzle
[ou-summer-of-code-2017.git] / 04-word-search / wordsearch-creation.ipynb
index 5259725cf255bb5f24b620c8e193f345f7461dc4..52cbbdcd082588912156d2fc10432f92ed6e6f64 100644 (file)
@@ -2,8 +2,10 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
+   "execution_count": 206,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "import string\n",
@@ -11,6 +13,9 @@
     "import random\n",
     "import collections\n",
     "import copy\n",
+    "import os\n",
+    "\n",
+    "from IPython.display import clear_output\n",
     "\n",
     "from enum import Enum\n",
     "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {},
+   "execution_count": 180,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "# all_words = [w.strip() for w in open('/usr/share/dict/british-english').readlines()\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
+   "execution_count": 181,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "# ws_words = [w.strip() for w in open('wordsearch-words').readlines()\n",
@@ -51,7 +60,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 182,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 183,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "62183"
+      ]
+     },
+     "execution_count": 183,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len([w for w in ws_words if len(w) >= 4])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 184,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 185,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 186,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 187,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 188,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 189,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 190,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 191,
    "metadata": {},
    "outputs": [
     {
        "'..e.....'"
       ]
      },
-     "execution_count": 12,
+     "execution_count": 191,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 192,
    "metadata": {},
    "outputs": [
     {
        "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
       ]
      },
-     "execution_count": 13,
+     "execution_count": 192,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 193,
    "metadata": {},
    "outputs": [
     {
        "<_sre.SRE_Match object; span=(0, 3), match='kee'>"
       ]
      },
-     "execution_count": 14,
+     "execution_count": 193,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
-   "metadata": {},
+   "execution_count": 194,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "re.fullmatch(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 195,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 196,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 197,
    "metadata": {},
    "outputs": [
     {
        "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
       ]
      },
-     "execution_count": 18,
+     "execution_count": 197,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
-   "metadata": {},
+   "execution_count": 198,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "could_add(grid, 3, 2, Direction.right, 'kine')"
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 199,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "<Direction.right: 2>"
+       "<Direction.up: 3>"
       ]
      },
-     "execution_count": 20,
+     "execution_count": 199,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 58,
+   "execution_count": 207,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def fill_grid(grid, words, word_count, max_attempts=10000):\n",
+    "def fill_grid(grid, words, word_count, max_attempts=10000, min_word_len=4):\n",
     "    attempts = 0\n",
     "    added_words = []\n",
     "    w = len(grid[0])\n",
     "    h = len(grid)\n",
     "    while len(added_words) < word_count and attempts < max_attempts:\n",
+    "        clear_output(wait=True)\n",
+    "        print(\"Added\", len(added_words), '; attempt', attempts)\n",
     "        attempts += 1\n",
     "        r = random.randrange(w)\n",
     "        c = random.randrange(h)\n",
     "        word = random.choice(words)\n",
     "        d = random.choice(list(Direction))\n",
-    "        if len(word) >=4 and not any(word in w2 for w2 in added_words) and could_add(grid, r, c, d, word):\n",
-    "            set_grid(grid, r, c, d, word)\n",
-    "            added_words += [word]\n",
-    "            attempts = 0\n",
+    "#         print(word, r, c, d, \n",
+    "#               len(word) >= min_word_len, \n",
+    "#               not any(word in w2 for w2 in added_words), \n",
+    "#               could_add(grid, r, c, d, word), \n",
+    "#               not present(grid, word)[0]\n",
+    "#              )\n",
+    "        if (len(word) >= min_word_len\n",
+    "              and not any(word in w2 for w2 in added_words) \n",
+    "              and could_add(grid, r, c, d, word)\n",
+    "              and not present(grid, word)[0]):\n",
+    "            grid2 = copy.deepcopy(grid)\n",
+    "            set_grid(grid2, r, c, d, word)\n",
+    "#             print(present_many(grid2, [word]))\n",
+    "            if collections.Counter(p[0] for p in \n",
+    "                                   present_many(grid2, added_words + [word])).most_common(1)[0][1] == 1:\n",
+    "                set_grid(grid, r, c, d, word)\n",
+    "                added_words += [word]\n",
+    "                attempts = 0\n",
     "    return grid, added_words"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 201,
    "metadata": {},
    "outputs": [
     {
-     "data": {
-      "text/plain": [
-       "40"
-      ]
-     },
-     "execution_count": 22,
-     "metadata": {},
-     "output_type": "execute_result"
+     "ename": "KeyboardInterrupt",
+     "evalue": "",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-201-6ab66457c812>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mempty_grid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m20\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mws\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfill_grid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mws_words\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m40\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mws\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-200-42497f37ad7f>\u001b[0m in \u001b[0;36mfill_grid\u001b[0;34m(grid, words, word_count, max_attempts, min_word_len)\u001b[0m\n\u001b[1;32m     24\u001b[0m \u001b[0;31m#             print(present_many(grid2, [word]))\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     25\u001b[0m             if collections.Counter(p[0] for p in \n\u001b[0;32m---> 26\u001b[0;31m                                    present_many(grid2, added_words + [word])).most_common(1)[0][1] == 1:\n\u001b[0m\u001b[1;32m     27\u001b[0m                 \u001b[0mset_grid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mword\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     28\u001b[0m                 \u001b[0madded_words\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mword\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-123-ff8574b12cf0>\u001b[0m in \u001b[0;36mpresent_many\u001b[0;34m(grid, words)\u001b[0m\n\u001b[1;32m      8\u001b[0m             \u001b[0;32mfor\u001b[0m \u001b[0md\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mDirection\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m                 \u001b[0;32mfor\u001b[0m \u001b[0mwordlen\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mwordlens\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m                     \u001b[0mword\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgslice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwordlen\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     11\u001b[0m                     \u001b[0;32mif\u001b[0m \u001b[0mword\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mwords\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     12\u001b[0m                         \u001b[0mpresences\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mword\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-188-a5adda74be28>\u001b[0m in \u001b[0;36mgslice\u001b[0;34m(grid, r, c, l, d)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mgslice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mindices\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;32m<ipython-input-187-e0e67252b972>\u001b[0m in \u001b[0;36mindices\u001b[0;34m(grid, r, c, l, d)\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mindices\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m     \u001b[0mdr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdelta\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0mw\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m     \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0minds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mr\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mdr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mdc\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ml\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
+     ]
     }
    ],
    "source": [
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "..pouchexecrate.....\n",
-      ".hazardous....t.wive\n",
-      "...sniradnam.aselcnu\n",
-      "s.weeklies.rnb......\n",
-      "e..lamenessse.o.....\n",
-      "i.tsallab..s.a.i....\n",
-      "tslim.......f.c.l...\n",
-      "iwheelbase...f.tges.\n",
-      "ed....llabhgihinirr.\n",
-      "dw.limbs..nj.bitev.s\n",
-      "te.wiltediu.ructs.e.\n",
-      "elsombretv.oqes..a..\n",
-      "ll..e..te.iela....m.\n",
-      "ie.a..un.lheleiretoc\n",
-      "ord..bi.scsp...kiths\n",
-      "ts.malcentilitren...\n",
-      "..i.e.sexetrov.stolb\n",
-      ".r.s...ruof....htrof\n",
-      "bgnihsirevopmi.....c\n",
-      "....graciousness....\n",
-      "40 words added\n",
-      "lameness impoverishing plasters wilted toilet forth coterie hazardous abutting chequing weeklies sombre execrate mastiffs boilers uncles centilitre mandarins wheelbase graciousness vortexes dwellers ballast limbs four tans highball wive broils beads mils reactive select deities shtik juveniles blots pouch brim coon\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "print(show_grid(g))\n",
     "print(len(ws), 'words added')\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def present_many(grid, words):\n",
+    "    w = len(grid[0])\n",
+    "    h = len(grid)\n",
+    "    wordlens = set(len(w) for w in words)\n",
+    "    presences = []\n",
+    "    for r in range(h):\n",
+    "        for c in range(w):\n",
+    "            for d in Direction:\n",
+    "                for wordlen in wordlens:\n",
+    "                    word = cat(gslice(grid, r, c, wordlen, d))\n",
+    "                    if word in words:\n",
+    "                        presences += [(word, r, c, d)]\n",
+    "    return set(presences)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "lameness (True, 4, 3, <Direction.right: 2>)\n",
-      "impoverishing (True, 18, 13, <Direction.left: 1>)\n",
-      "plasters (True, 14, 11, <Direction.upright: 6>)\n",
-      "wilted (True, 10, 3, <Direction.right: 2>)\n",
-      "toilet (True, 15, 0, <Direction.up: 3>)\n",
-      "forth (True, 17, 19, <Direction.left: 1>)\n",
-      "coterie (True, 13, 19, <Direction.left: 1>)\n",
-      "hazardous (True, 1, 1, <Direction.right: 2>)\n",
-      "abutting (True, 15, 4, <Direction.upright: 6>)\n",
-      "chequing (True, 14, 9, <Direction.upright: 6>)\n",
-      "weeklies (True, 3, 2, <Direction.right: 2>)\n",
-      "sombre (True, 11, 2, <Direction.right: 2>)\n",
-      "execrate (True, 0, 7, <Direction.right: 2>)\n",
-      "mastiffs (True, 12, 18, <Direction.upleft: 5>)\n",
-      "boilers (True, 3, 13, <Direction.downright: 8>)\n",
-      "uncles (True, 2, 19, <Direction.left: 1>)\n",
-      "centilitre (True, 15, 6, <Direction.right: 2>)\n",
-      "mandarins (True, 2, 11, <Direction.left: 1>)\n",
-      "wheelbase (True, 7, 1, <Direction.right: 2>)\n",
-      "graciousness (True, 19, 4, <Direction.right: 2>)\n",
-      "vortexes (True, 16, 13, <Direction.left: 1>)\n",
-      "dwellers (True, 8, 1, <Direction.down: 4>)\n",
-      "ballast (True, 5, 8, <Direction.left: 1>)\n",
-      "limbs (True, 9, 3, <Direction.right: 2>)\n",
-      "four (True, 17, 10, <Direction.left: 1>)\n",
-      "tans (True, 1, 14, <Direction.downleft: 7>)\n",
-      "highball (True, 8, 13, <Direction.left: 1>)\n",
-      "wive (True, 1, 16, <Direction.right: 2>)\n",
-      "broils (True, 9, 13, <Direction.downleft: 7>)\n",
-      "beads (True, 11, 5, <Direction.downleft: 7>)\n",
-      "mils (True, 6, 4, <Direction.left: 1>)\n",
-      "reactive (True, 3, 11, <Direction.downright: 8>)\n",
-      "select (True, 14, 10, <Direction.upright: 6>)\n",
-      "deities (True, 9, 0, <Direction.up: 3>)\n",
-      "shtik (True, 14, 19, <Direction.left: 1>)\n",
-      "juveniles (True, 9, 11, <Direction.downleft: 7>)\n",
-      "blots (True, 16, 19, <Direction.left: 1>)\n",
-      "pouch (True, 0, 2, <Direction.right: 2>)\n",
-      "brim (True, 18, 0, <Direction.upright: 6>)\n",
-      "coon (True, 18, 19, <Direction.upleft: 5>)\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "for w in ws:\n",
     "    print(w, present(g, w))"
   },
   {
    "cell_type": "code",
-   "execution_count": 47,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 48,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "True"
-      ]
-     },
-     "execution_count": 48,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "interesting(g, ws)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 51,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def interesting_grid(width=20, height=20, words_limit=40, direction_slack=1):\n",
+    "def interesting_grid(width=20, height=20, words_limit=40, max_words=80, direction_slack=1):\n",
     "    boring = True\n",
     "    while boring:\n",
     "        grid = empty_grid(width, height)\n",
-    "        grid, words = fill_grid(grid, ws_words, 80)\n",
+    "        grid, words = fill_grid(grid, ws_words, max_words)\n",
     "        boring = not interesting(grid, words, words_limit=words_limit, direction_slack=direction_slack)\n",
     "    return grid, words"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 52,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "dexawwt....ybossm..t\n",
-      "snaprhlukulele..o.er\n",
-      "...erioteb.hrevordla\n",
-      "..sivc..pr.tdekcahkp\n",
-      "atve..h.oiselapcy.cd\n",
-      "nesrehpargohtill.pue\n",
-      "n.leaveyis.smuguhhrt\n",
-      "eyhsifnt.r...aeesetc\n",
-      "xverbseebasedlritl.a\n",
-      ".r..k.wie..mdonaiaeg\n",
-      "..ac.nsof.admeeulsoo\n",
-      "g.opo.cmanaotpqiinmp\n",
-      "nc.us.a.lpnteaerdkiu\n",
-      "ionjoys.leirinioicns\n",
-      "wnkcent.skeracllkase\n",
-      "oab..erusopxeao.antt\n",
-      "dureifidimuhed.nskea\n",
-      "aga...capitols..scrl\n",
-      "h.v.sandblaster..i.i\n",
-      "s.e..sdratoelhitsn.d\n",
-      "61 words added;  8 directions\n",
-      "newscast kittenish cocks lithographers truckle leotards they exposure dehumidifier sandblaster alien paddle shadowing gondola wrest joys minster pales chairs fishy capitols based gums pheromones saki moiety waxed guano thriven dilate moray icons adman ukulele hacked rope rise clue acted nicknack spar verbs boss annex neck repeater befalls drover leave pans brave brigs opus live noun tail riot care hits quilt part\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "g, ws = interesting_grid()\n",
     "print(show_grid(g))\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "english_counts = collections.Counter(dict(datafile('count_1l.txt')))\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "wordsearch_counts = collections.Counter(cat(ws_words))\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "normalised_wordsearch_counts = normalise(collections.Counter(normalised_wordsearch_counts) + collections.Counter({l: 0.05 for l in string.ascii_lowercase}))"
   },
   {
    "cell_type": "code",
-   "execution_count": 35,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'aaaaaabbccddeeeeeeeeeeeffggghhhhhhiiiiiiiiillllmmnnnnnnnooooooooooppppqrrrrrrrssstttttttttuuwyyyyyyz'"
-      ]
-     },
-     "execution_count": 36,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "cat(sorted(random_english_letter() for i in range(100)))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 37,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'aaaaaaaabbbccccddeeeeeeeeggghhhiiiiiiiijjkkllllnnnnoooooooooopppqqrrrrrssssssttttttuuuuvvwxxxxxyzzzz'"
-      ]
-     },
-     "execution_count": 37,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "cat(sorted(random_wordsearch_letter() for i in range(100)))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 38,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'x'"
-      ]
-     },
-     "execution_count": 38,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "random_wordsearch_letter()"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 39,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 53,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "dexawwtmxepybossmezt\n",
-      "snaprhlukulelefaoder\n",
-      "ijreriotebahrevordla\n",
-      "jrsivcciprstdekcahkp\n",
-      "atvecshkoiselapcydcd\n",
-      "nesrehpargohtilljpue\n",
-      "nuleaveyisasmuguhhrt\n",
-      "eyhsifntzrmnsaeesetc\n",
-      "xverbseebasedlritlla\n",
-      "prcckzwiefamdonaiaeg\n",
-      "osacqnsofgadmeeulsoo\n",
-      "gdoporcmanaotpqiinmp\n",
-      "ncmusbaslpnteaerdkiu\n",
-      "ionjoyswleirinioicns\n",
-      "wnkcentcskeracllkase\n",
-      "oabsuerusopxeaodantt\n",
-      "dureifidimuhedgnskea\n",
-      "agagvccapitolsgyscrl\n",
-      "hkvgsandblasterdhihi\n",
-      "syenesdratoelhitsnod\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "padded = pad_grid(g)\n",
     "print(show_grid(padded))"
   },
   {
    "cell_type": "code",
-   "execution_count": 54,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "dexawwt....ybossm..t\n",
-      "snaprhlukulele..o.er\n",
-      "...erioteb.hrevordla\n",
-      "..sivc..pr.tdekcahkp\n",
-      "atve..h.oiselapcy.cd\n",
-      "nesrehpargohtill.pue\n",
-      "n.leaveyis.smuguhhrt\n",
-      "eyhsifnt.r...aeesetc\n",
-      "xverbseebasedlritl.a\n",
-      ".r..k.wie..mdonaiaeg\n",
-      "..ac.nsof.admeeulsoo\n",
-      "g.opo.cmanaotpqiinmp\n",
-      "nc.us.a.lpnteaerdkiu\n",
-      "ionjoys.leirinioicns\n",
-      "wnkcent.skeracllkase\n",
-      "oab..erusopxeao.antt\n",
-      "dureifidimuhed.nskea\n",
-      "aga...capitols..scrl\n",
-      "h.v.sandblaster..i.i\n",
-      "s.e..sdratoelhitsn.d\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "print(show_grid(g))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 55,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "newscast (True, 7, 6, <Direction.down: 4>)\n",
-      "kittenish (True, 14, 9, <Direction.upright: 6>)\n",
-      "cocks (True, 12, 1, <Direction.upright: 6>)\n",
-      "lithographers (True, 5, 14, <Direction.left: 1>)\n",
-      "truckle (True, 7, 18, <Direction.up: 3>)\n",
-      "leotards (True, 19, 12, <Direction.left: 1>)\n",
-      "they (True, 3, 11, <Direction.up: 3>)\n",
-      "exposure (True, 15, 12, <Direction.left: 1>)\n",
-      "dehumidifier (True, 16, 13, <Direction.left: 1>)\n",
-      "sandblaster (True, 18, 4, <Direction.right: 2>)\n",
-      "alien (True, 9, 17, <Direction.downleft: 7>)\n",
-      "paddle (True, 12, 9, <Direction.upright: 6>)\n",
-      "shadowing (True, 19, 0, <Direction.up: 3>)\n",
-      "gondola (True, 9, 19, <Direction.downleft: 7>)\n",
-      "wrest (True, 0, 5, <Direction.downleft: 7>)\n",
-      "joys (True, 13, 3, <Direction.right: 2>)\n",
-      "minster (True, 11, 18, <Direction.down: 4>)\n",
-      "pales (True, 4, 14, <Direction.left: 1>)\n",
-      "chairs (True, 3, 5, <Direction.downright: 8>)\n",
-      "fishy (True, 7, 5, <Direction.left: 1>)\n",
-      "capitols (True, 17, 6, <Direction.right: 2>)\n",
-      "based (True, 8, 8, <Direction.right: 2>)\n",
-      "gums (True, 6, 14, <Direction.left: 1>)\n",
-      "pheromones (True, 5, 17, <Direction.downleft: 7>)\n",
-      "saki (True, 16, 16, <Direction.up: 3>)\n",
-      "moiety (True, 11, 7, <Direction.up: 3>)\n",
-      "waxed (True, 0, 4, <Direction.left: 1>)\n",
-      "guano (True, 17, 1, <Direction.up: 3>)\n",
-      "thriven (True, 0, 6, <Direction.downleft: 7>)\n",
-      "dilate (True, 19, 19, <Direction.up: 3>)\n",
-      "moray (True, 0, 16, <Direction.down: 4>)\n",
-      "icons (True, 13, 12, <Direction.downright: 8>)\n",
-      "adman (True, 7, 13, <Direction.downleft: 7>)\n",
-      "ukulele (True, 1, 7, <Direction.right: 2>)\n",
-      "hacked (True, 3, 17, <Direction.left: 1>)\n",
-      "rope (True, 5, 8, <Direction.up: 3>)\n",
-      "rise (True, 12, 15, <Direction.upright: 6>)\n",
-      "clue (True, 4, 15, <Direction.down: 4>)\n",
-      "acted (True, 8, 19, <Direction.up: 3>)\n",
-      "nicknack (True, 19, 17, <Direction.up: 3>)\n",
-      "spar (True, 12, 4, <Direction.upleft: 5>)\n",
-      "verbs (True, 8, 1, <Direction.right: 2>)\n",
-      "boss (True, 0, 12, <Direction.right: 2>)\n",
-      "annex (True, 4, 0, <Direction.down: 4>)\n",
-      "neck (True, 14, 5, <Direction.left: 1>)\n",
-      "repeater (True, 13, 11, <Direction.upright: 6>)\n",
-      "befalls (True, 8, 8, <Direction.down: 4>)\n",
-      "drover (True, 2, 17, <Direction.left: 1>)\n",
-      "leave (True, 6, 2, <Direction.right: 2>)\n",
-      "pans (True, 1, 3, <Direction.left: 1>)\n",
-      "brave (True, 15, 2, <Direction.down: 4>)\n",
-      "brigs (True, 2, 9, <Direction.down: 4>)\n",
-      "opus (True, 10, 19, <Direction.down: 4>)\n",
-      "live (True, 1, 6, <Direction.downleft: 7>)\n",
-      "noun (True, 10, 5, <Direction.downleft: 7>)\n",
-      "tail (True, 11, 12, <Direction.downright: 8>)\n",
-      "riot (True, 2, 4, <Direction.right: 2>)\n",
-      "care (True, 14, 13, <Direction.left: 1>)\n",
-      "hits (True, 19, 13, <Direction.right: 2>)\n",
-      "quilt (True, 11, 14, <Direction.upright: 6>)\n",
-      "part (True, 3, 19, <Direction.up: 3>)\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "for w in ws:\n",
     "    print(w, present(padded, w))"
   },
   {
    "cell_type": "code",
-   "execution_count": 43,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "def decoys(grid, words, all_words, limit=100):\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 44,
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def decoys(grid, words, all_words, limit=100, min_word_len=4):\n",
+    "    decoy_words = []\n",
+    "#     dlen_limit = max(len(w) for w in words)\n",
+    "    while len(words) + len(decoy_words) < limit:\n",
+    "        d = random.choice(all_words)\n",
+    "        if d not in words and len(d) >= min_word_len and not present(grid, d)[0]:\n",
+    "            decoy_words += [d]\n",
+    "    return decoy_words"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['friendship',\n",
-       " 'stepping',\n",
-       " 'featheriest',\n",
-       " 'thriftily',\n",
-       " 'mutilation',\n",
-       " 'nook',\n",
-       " 'clewing',\n",
-       " 'meditated',\n",
-       " 'gooier',\n",
-       " 'cripples',\n",
-       " 'ponderously',\n",
-       " 'roundelay',\n",
-       " 'curtailed',\n",
-       " 'redeemed',\n",
-       " 'perimeters',\n",
-       " 'harelips',\n",
-       " 'overcompensating',\n",
-       " 'rejoicings',\n",
-       " 'adobe',\n",
-       " 'decreasing',\n",
-       " 'interstices',\n",
-       " 'curd',\n",
-       " 'orientate',\n",
-       " 'blueberries',\n",
-       " 'juniors',\n",
-       " 'broadloom',\n",
-       " 'debarring',\n",
-       " 'chandeliers',\n",
-       " 'segues',\n",
-       " 'army',\n",
-       " 'snuck',\n",
-       " 'pugilistic',\n",
-       " 'snugs',\n",
-       " 'dexterity',\n",
-       " 'dallies',\n",
-       " 'curving',\n",
-       " 'newsletter',\n",
-       " 'torn',\n",
-       " 'beaching',\n",
-       " 'limit',\n",
-       " 'blackguards',\n",
-       " 'breezier',\n",
-       " 'reoccur',\n",
-       " 'cabins']"
-      ]
-     },
-     "execution_count": 44,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "ds = decoys(padded, ws, ws_words)\n",
     "ds"
   },
   {
    "cell_type": "code",
-   "execution_count": 45,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "opted (True, 5, 7, <Direction.downright: 8>)\n",
-      "haywire (True, 8, 9, <Direction.downleft: 7>)\n",
-      "busting (True, 4, 17, <Direction.left: 1>)\n",
-      "succinct (True, 7, 17, <Direction.down: 4>)\n",
-      "institute (True, 16, 18, <Direction.up: 3>)\n",
-      "illicit (True, 13, 14, <Direction.left: 1>)\n",
-      "hypersensitivity (True, 16, 15, <Direction.left: 1>)\n",
-      "placement (True, 3, 11, <Direction.left: 1>)\n",
-      "bathrobe (True, 0, 5, <Direction.right: 2>)\n",
-      "inured (True, 4, 0, <Direction.right: 2>)\n",
-      "caveats (True, 3, 8, <Direction.downleft: 7>)\n",
-      "revisiting (True, 2, 11, <Direction.left: 1>)\n",
-      "pulp (True, 15, 11, <Direction.right: 2>)\n",
-      "teacup (True, 7, 16, <Direction.downleft: 7>)\n",
-      "threading (True, 18, 6, <Direction.right: 2>)\n",
-      "queered (True, 5, 13, <Direction.right: 2>)\n",
-      "parking (True, 6, 9, <Direction.right: 2>)\n",
-      "advent (True, 1, 11, <Direction.left: 1>)\n",
-      "chasuble (True, 19, 19, <Direction.left: 1>)\n",
-      "mosey (True, 7, 5, <Direction.downleft: 7>)\n",
-      "highboys (True, 19, 4, <Direction.right: 2>)\n",
-      "recharging (True, 18, 19, <Direction.up: 3>)\n",
-      "flue (True, 12, 2, <Direction.upright: 6>)\n",
-      "plywood (True, 3, 18, <Direction.left: 1>)\n",
-      "gluing (True, 12, 12, <Direction.upleft: 5>)\n",
-      "worrier (True, 1, 12, <Direction.right: 2>)\n",
-      "karma (True, 17, 9, <Direction.left: 1>)\n",
-      "peepers (True, 8, 7, <Direction.downleft: 7>)\n",
-      "vulnerable (True, 17, 10, <Direction.right: 2>)\n",
-      "boycott (True, 15, 1, <Direction.right: 2>)\n",
-      "rummy (True, 5, 4, <Direction.left: 1>)\n",
-      "tonic (True, 8, 13, <Direction.downleft: 7>)\n",
-      "children (True, 15, 0, <Direction.up: 3>)\n",
-      "reales (True, 6, 1, <Direction.right: 2>)\n",
-      "rectal (True, 7, 15, <Direction.down: 4>)\n",
-      "sledded (True, 14, 16, <Direction.up: 3>)\n",
-      "collocates (True, 14, 5, <Direction.right: 2>)\n",
-      "edict (True, 17, 4, <Direction.left: 1>)\n",
-      "captor (True, 14, 5, <Direction.upright: 6>)\n",
-      "amulet (True, 9, 4, <Direction.upright: 6>)\n",
-      "slipper (True, 2, 13, <Direction.right: 2>)\n",
-      "foot (True, 0, 0, <Direction.right: 2>)\n",
-      "chef (True, 14, 4, <Direction.upright: 6>)\n",
-      "goods (True, 6, 15, <Direction.right: 2>)\n",
-      "salter (True, 1, 5, <Direction.left: 1>)\n",
-      "crows (True, 18, 0, <Direction.right: 2>)\n",
-      "paeans (True, 12, 14, <Direction.up: 3>)\n",
-      "fences (True, 0, 18, <Direction.left: 1>)\n",
-      "iron (True, 5, 9, <Direction.right: 2>)\n",
-      "liras (True, 0, 19, <Direction.down: 4>)\n",
-      "stages (True, 19, 16, <Direction.up: 3>)\n",
-      "defer (True, 14, 2, <Direction.upright: 6>)\n",
-      "racy (True, 5, 4, <Direction.downleft: 7>)\n",
-      "gaps (True, 7, 11, <Direction.right: 2>)\n",
-      "aspen (True, 12, 10, <Direction.upleft: 5>)\n",
-      "rams (True, 6, 0, <Direction.downright: 8>)\n",
-      "friendship (False, 0, 0, <Direction.left: 1>)\n",
-      "stepping (False, 0, 0, <Direction.left: 1>)\n",
-      "featheriest (False, 0, 0, <Direction.left: 1>)\n",
-      "thriftily (False, 0, 0, <Direction.left: 1>)\n",
-      "mutilation (False, 0, 0, <Direction.left: 1>)\n",
-      "nook (False, 0, 0, <Direction.left: 1>)\n",
-      "clewing (False, 0, 0, <Direction.left: 1>)\n",
-      "meditated (False, 0, 0, <Direction.left: 1>)\n",
-      "gooier (False, 0, 0, <Direction.left: 1>)\n",
-      "cripples (False, 0, 0, <Direction.left: 1>)\n",
-      "ponderously (False, 0, 0, <Direction.left: 1>)\n",
-      "roundelay (False, 0, 0, <Direction.left: 1>)\n",
-      "curtailed (False, 0, 0, <Direction.left: 1>)\n",
-      "redeemed (False, 0, 0, <Direction.left: 1>)\n",
-      "perimeters (False, 0, 0, <Direction.left: 1>)\n",
-      "harelips (False, 0, 0, <Direction.left: 1>)\n",
-      "overcompensating (False, 0, 0, <Direction.left: 1>)\n",
-      "rejoicings (False, 0, 0, <Direction.left: 1>)\n",
-      "adobe (False, 0, 0, <Direction.left: 1>)\n",
-      "decreasing (False, 0, 0, <Direction.left: 1>)\n",
-      "interstices (False, 0, 0, <Direction.left: 1>)\n",
-      "curd (False, 0, 0, <Direction.left: 1>)\n",
-      "orientate (False, 0, 0, <Direction.left: 1>)\n",
-      "blueberries (False, 0, 0, <Direction.left: 1>)\n",
-      "juniors (False, 0, 0, <Direction.left: 1>)\n",
-      "broadloom (False, 0, 0, <Direction.left: 1>)\n",
-      "debarring (False, 0, 0, <Direction.left: 1>)\n",
-      "chandeliers (False, 0, 0, <Direction.left: 1>)\n",
-      "segues (False, 0, 0, <Direction.left: 1>)\n",
-      "army (False, 0, 0, <Direction.left: 1>)\n",
-      "snuck (False, 0, 0, <Direction.left: 1>)\n",
-      "pugilistic (False, 0, 0, <Direction.left: 1>)\n",
-      "snugs (False, 0, 0, <Direction.left: 1>)\n",
-      "dexterity (False, 0, 0, <Direction.left: 1>)\n",
-      "dallies (False, 0, 0, <Direction.left: 1>)\n",
-      "curving (False, 0, 0, <Direction.left: 1>)\n",
-      "newsletter (False, 0, 0, <Direction.left: 1>)\n",
-      "torn (False, 0, 0, <Direction.left: 1>)\n",
-      "beaching (False, 0, 0, <Direction.left: 1>)\n",
-      "limit (False, 0, 0, <Direction.left: 1>)\n",
-      "blackguards (False, 0, 0, <Direction.left: 1>)\n",
-      "breezier (False, 0, 0, <Direction.left: 1>)\n",
-      "reoccur (False, 0, 0, <Direction.left: 1>)\n",
-      "cabins (False, 0, 0, <Direction.left: 1>)\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "for w in ws + ds:\n",
     "    print(w, present(padded, w))"
   },
   {
    "cell_type": "code",
-   "execution_count": 46,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "s.esevresed...dwhims\n",
-      "e.tbk..vapourse.bn.d\n",
-      "h.ificembracesnslo.e\n",
-      "ctr.egukiwic..ddui.r\n",
-      "inor.dwh.rips.rrftsa\n",
-      "reue.eeisrar.tiefiyl\n",
-      "mmli.mgrg.muarth.slc\n",
-      "ieft.un.a.bnbuemdole\n",
-      "nn.nesimrliertseepad\n",
-      "ei.imeloeccdeh.epob.\n",
-      "dfsaprlrio.saf.smri.\n",
-      "cnpdt.ofrn.usu..ap.h\n",
-      "oom.ispeccgntlpew.sa\n",
-      "tcu.e.l.lu.eda.vsgin\n",
-      "e.bdsb.oarrmneloplsg\n",
-      "r.olaetrleromrkr.isa\n",
-      "ibatnhd.nlpoaeic.bir\n",
-      "eesiee.i.luepno.o.e.\n",
-      "snt.d.o.y.pcte.p.mr.\n",
-      "u....jtoquesylduol..\n",
-      "sfesevresedpzcdwhims\n",
-      "eotbkvgvapoursehbnyd\n",
-      "hiificembracesnslone\n",
-      "ctrnegukiwicurdduivr\n",
-      "inorydwhrripscrrftsa\n",
-      "reueleeisrarvtiefiyl\n",
-      "mmlinmgrgzmuarthgslc\n",
-      "ieftuunyanbnbuemdole\n",
-      "nncnesimrliertseepad\n",
-      "eirimeloeccdehzepobm\n",
-      "dfsaprlrioisafesmriq\n",
-      "cnpdtsofrnausuodapxh\n",
-      "oomlispeccgntlpewasa\n",
-      "tcuaehlzluledakvsgin\n",
-      "eibdsbeoarrmneloplsg\n",
-      "rbolaetrleromrkrnisa\n",
-      "ibatnhdtnlpoaeicibir\n",
-      "eesieerimluepnoholey\n",
-      "sntadvoaycpctespsmro\n",
-      "uamapjtoquesylduoldp\n",
-      "56 words added;  8 directions\n",
-      "Present: abreast bigwig bluff bodes bumps clothe concur confinement coteries crier cull daintier declared dendrites denim deserves embraces empties federal fluorite from glib guarded hangar herds iambic joiner kiwi loudly menus mocked panoply pearl poem polling prints proposition pruned resume rices riches rips roped rove seal seem shucks sissier swamped syllabi tine toque truthful unstabler vapours whims\n",
-      "Decoys: abrasions adapters aimlessness alkali awakens blowing burnouses burped cattily coal commences confusion contrivance crudest curies depravity distribute diva emigrate emulsion giveaway hangman house lifeboats maze middy mines mystified obtain organic parsons postulate prefixes pretenders razors scone sloes spuds straight subtleties systematise turncoats unpacked waivers\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "g, ws = interesting_grid()\n",
     "p = pad_grid(g)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 63,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "...p.mown.\n",
-      ".sdse..ee.\n",
-      ".e.elad.cr\n",
-      "pi.dtir.ah\n",
-      "rzsiwovspu\n",
-      "oawh.kieab\n",
-      "brow.c.rda\n",
-      "ecnotops.r\n",
-      "d.kc.d...b\n",
-      ".staple...\n",
-      "\n",
-      "fhjpamownq\n",
-      "wsdseuqeev\n",
-      "ieaeladhcr\n",
-      "piedtiriah\n",
-      "rzsiwovspu\n",
-      "oawhakieab\n",
-      "browpcfrda\n",
-      "ecnotopssr\n",
-      "dikchdnpnb\n",
-      "bstapleokr\n",
-      "14 words added;  6 directions\n",
-      "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
-      "Decoys: adapting bombing boor brick cackles carnal casino chaplets chump coaster coccyxes coddle collies creels crumbled cunt curds curled curlier deepen demeanor dicier dowses ensuing faddish fest fickler foaming gambol garoting gliding gristle grunts guts ibex impugns instants kielbasy lanyard loamier lugs market meanly minuend misprint mitts molested moonshot mucking oaks olives orgasmic pastrami perfect proceed puckered quashed refined regards retraces revel ridges ringlet scoff shinier siren solaria sprain sunder sunup tamped tapes thirds throw tiller times trains tranquil transfix typesets uric wariness welts whimsy winced winced\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "g, ws = interesting_grid(width=10, height=10, words_limit=5, direction_slack=6)\n",
     "p = pad_grid(g)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 98,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['fickler',\n",
-       " 'adapting',\n",
-       " 'chump',\n",
-       " 'foaming',\n",
-       " 'molested',\n",
-       " 'carnal',\n",
-       " 'crumbled',\n",
-       " 'guts',\n",
-       " 'minuend',\n",
-       " 'bombing',\n",
-       " 'winced',\n",
-       " 'coccyxes',\n",
-       " 'solaria',\n",
-       " 'shinier',\n",
-       " 'cackles']"
-      ]
-     },
-     "execution_count": 98,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "ds_original = ['regards', 'perfect', 'instants', 'refined', 'coddle', 'fickler', 'gambol', 'misprint', 'tapes', 'impugns', 'moonshot', 'chump', 'brick', 'siren', 'faddish', 'winced', 'kielbasy', 'market', 'puckered', 'trains', 'welts', 'cackles', 'foaming', 'proceed', 'gliding', 'guts', 'uric', 'oaks', 'molested', 'curled', 'boor', 'solaria', 'gristle', 'bombing', 'loamier', 'ensuing', 'cunt', 'sunder', 'revel', 'coaster', 'grunts', 'mucking', 'typesets', 'carnal', 'whimsy', 'scoff', 'coccyxes', 'meanly', 'sprain', 'minuend', 'ringlet', 'fest', 'winced', 'shinier', 'dicier', 'thirds', 'olives', 'garoting', 'pastrami', 'tranquil', 'tamped', 'sunup', 'crumbled', 'throw', 'ridges', 'chaplets', 'curlier', 'lugs', 'collies', 'adapting', 'demeanor', 'deepen', 'lanyard', 'tiller', 'transfix', 'wariness', 'times', 'mitts', 'dowses', 'creels', 'curds', 'quashed', 'orgasmic', 'ibex', 'retraces', 'casino']\n",
     "ds = random.sample(ds_original, 15)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 89,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['regards',\n",
-       " 'perfect',\n",
-       " 'instants',\n",
-       " 'refined',\n",
-       " 'coddle',\n",
-       " 'fickler',\n",
-       " 'gambol',\n",
-       " 'misprint',\n",
-       " 'tapes',\n",
-       " 'impugns',\n",
-       " 'moonshot',\n",
-       " 'chump',\n",
-       " 'brick',\n",
-       " 'siren',\n",
-       " 'faddish',\n",
-       " 'winced',\n",
-       " 'kielbasy',\n",
-       " 'market',\n",
-       " 'puckered',\n",
-       " 'trains',\n",
-       " 'welts',\n",
-       " 'cackles',\n",
-       " 'foaming',\n",
-       " 'proceed',\n",
-       " 'gliding',\n",
-       " 'guts',\n",
-       " 'uric',\n",
-       " 'oaks',\n",
-       " 'molested',\n",
-       " 'curled',\n",
-       " 'boor',\n",
-       " 'solaria',\n",
-       " 'gristle',\n",
-       " 'bombing',\n",
-       " 'loamier',\n",
-       " 'ensuing',\n",
-       " 'cunt',\n",
-       " 'sunder',\n",
-       " 'revel',\n",
-       " 'coaster',\n",
-       " 'grunts',\n",
-       " 'mucking',\n",
-       " 'typesets',\n",
-       " 'carnal',\n",
-       " 'whimsy',\n",
-       " 'scoff',\n",
-       " 'coccyxes',\n",
-       " 'meanly',\n",
-       " 'sprain',\n",
-       " 'minuend',\n",
-       " 'ringlet',\n",
-       " 'fest',\n",
-       " 'winced',\n",
-       " 'shinier',\n",
-       " 'dicier',\n",
-       " 'thirds',\n",
-       " 'olives',\n",
-       " 'garoting',\n",
-       " 'pastrami',\n",
-       " 'tranquil',\n",
-       " 'tamped',\n",
-       " 'sunup',\n",
-       " 'crumbled',\n",
-       " 'throw',\n",
-       " 'ridges',\n",
-       " 'chaplets',\n",
-       " 'curlier',\n",
-       " 'lugs',\n",
-       " 'collies',\n",
-       " 'adapting',\n",
-       " 'demeanor',\n",
-       " 'deepen',\n",
-       " 'lanyard',\n",
-       " 'tiller',\n",
-       " 'transfix',\n",
-       " 'wariness',\n",
-       " 'times',\n",
-       " 'mitts',\n",
-       " 'dowses',\n",
-       " 'creels',\n",
-       " 'curds',\n",
-       " 'quashed',\n",
-       " 'orgasmic',\n",
-       " 'ibex',\n",
-       " 'retraces',\n",
-       " 'casino']"
-      ]
-     },
-     "execution_count": 89,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "ds_original"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 99,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "grid =  [['.', '.', '.', 'p', '.', 'm', 'o', 'w', 'n', '.'], ['.', 's', 'd', 's', 'e', '.', '.', 'e', 'e', '.'], ['.', 'e', '.', 'e', 'l', 'a', 'd', '.', 'c', 'r'], ['p', 'i', '.', 'd', 't', 'i', 'r', '.', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', '.', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', '.', 'c', '.', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', '.', 'r'], ['d', '.', 'k', 'c', '.', 'd', '.', '.', '.', 'b'], ['.', 's', 't', 'a', 'p', 'l', 'e', '.', '.', '.']]\n",
-      "padded_grid =  [['f', 'h', 'j', 'p', 'a', 'm', 'o', 'w', 'n', 'q'], ['w', 's', 'd', 's', 'e', 'u', 'q', 'e', 'e', 'v'], ['i', 'e', 'a', 'e', 'l', 'a', 'd', 'h', 'c', 'r'], ['p', 'i', 'e', 'd', 't', 'i', 'r', 'i', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', 'a', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', 'p', 'c', 'f', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', 's', 'r'], ['d', 'i', 'k', 'c', 'h', 'd', 'n', 'p', 'n', 'b'], ['b', 's', 't', 'a', 'p', 'l', 'e', 'o', 'k', 'r']]\n",
-      "present_words =  ['probed', 'staple', 'rioted', 'cowhides', 'tops', 'knows', 'lived', 'rhubarb', 'crazies', 'dock', 'apace', 'mown', 'pears', 'wide']\n",
-      "decoy_words =  ['fickler', 'adapting', 'chump', 'foaming', 'molested', 'carnal', 'crumbled', 'guts', 'minuend', 'bombing', 'winced', 'coccyxes', 'solaria', 'shinier', 'cackles']\n",
-      "Directions:  [('probed', '`(True, 3, 0, <Direction.down: 4>)`'), ('staple', '`(True, 9, 1, <Direction.right: 2>)`'), ('rioted', '`(True, 6, 7, <Direction.upleft: 5>)`'), ('cowhides', '`(True, 8, 3, <Direction.up: 3>)`'), ('tops', '`(True, 7, 4, <Direction.right: 2>)`'), ('knows', '`(True, 8, 2, <Direction.up: 3>)`'), ('lived', '`(True, 2, 4, <Direction.downright: 8>)`'), ('rhubarb', '`(True, 2, 9, <Direction.down: 4>)`'), ('crazies', '`(True, 7, 1, <Direction.up: 3>)`'), ('dock', '`(True, 8, 5, <Direction.up: 3>)`'), ('apace', '`(True, 5, 8, <Direction.up: 3>)`'), ('mown', '`(True, 0, 5, <Direction.right: 2>)`'), ('pears', '`(True, 0, 3, <Direction.downright: 8>)`'), ('wide', '`(True, 4, 4, <Direction.upright: 6>)`')]\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "print('grid = ', g)\n",
     "print('padded_grid = ', p)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 100,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 77,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "probed 3 0 6 Direction.down [(3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0)]\n",
-      "staple 9 1 6 Direction.right [(9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)]\n",
-      "rioted 6 7 6 Direction.upleft [(6, 7), (5, 6), (4, 5), (3, 4), (2, 3), (1, 2)]\n",
-      "cowhides 8 3 8 Direction.up [(8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3)]\n",
-      "tops 7 4 4 Direction.right [(7, 4), (7, 5), (7, 6), (7, 7)]\n",
-      "knows 8 2 5 Direction.up [(8, 2), (7, 2), (6, 2), (5, 2), (4, 2)]\n",
-      "lived 2 4 5 Direction.downright [(2, 4), (3, 5), (4, 6), (5, 7), (6, 8)]\n",
-      "rhubarb 2 9 7 Direction.down [(2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9)]\n",
-      "crazies 7 1 7 Direction.up [(7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)]\n",
-      "dock 8 5 4 Direction.up [(8, 5), (7, 5), (6, 5), (5, 5)]\n",
-      "apace 5 8 5 Direction.up [(5, 8), (4, 8), (3, 8), (2, 8), (1, 8)]\n",
-      "mown 0 5 4 Direction.right [(0, 5), (0, 6), (0, 7), (0, 8)]\n",
-      "pears 0 3 5 Direction.downright [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]\n",
-      "wide 4 4 4 Direction.upright [(4, 4), (3, 5), (2, 6), (1, 7)]\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "[(7, 5), (2, 3), (3, 5)]"
-      ]
-     },
-     "execution_count": 77,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "cts = collections.Counter()\n",
     "for w in ws:\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 143,
+   "execution_count": null,
    "metadata": {
+    "collapsed": true,
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "0\n",
-      "1\n",
-      "2\n",
-      "3\n",
-      "4\n",
-      "5\n",
-      "6\n",
-      "7\n",
-      "8\n",
-      "9\n",
-      "10\n",
-      "11\n",
-      "12\n",
-      "13\n",
-      "14\n",
-      "15\n",
-      "16\n",
-      "17\n",
-      "18\n",
-      "19\n",
-      "20\n",
-      "21\n",
-      "22\n",
-      "23\n",
-      "24\n",
-      "25\n",
-      "26\n",
-      "27\n",
-      "28\n",
-      "29\n",
-      "30\n",
-      "31\n",
-      "32\n",
-      "33\n",
-      "34\n",
-      "35\n",
-      "36\n",
-      "37\n",
-      "38\n",
-      "39\n",
-      "40\n",
-      "41\n",
-      "42\n",
-      "43\n",
-      "44\n",
-      "45\n",
-      "46\n",
-      "47\n",
-      "48\n",
-      "49\n",
-      "50\n",
-      "51\n",
-      "52\n",
-      "53\n",
-      "54\n",
-      "55\n",
-      "56\n",
-      "57\n",
-      "58\n",
-      "59\n",
-      "60\n",
-      "61\n",
-      "62\n",
-      "63\n",
-      "64\n",
-      "65\n",
-      "66\n",
-      "67\n",
-      "68\n",
-      "69\n",
-      "70\n",
-      "71\n",
-      "72\n",
-      "73\n",
-      "74\n",
-      "75\n",
-      "76\n",
-      "77\n",
-      "78\n",
-      "79\n",
-      "80\n",
-      "81\n",
-      "82\n",
-      "83\n",
-      "84\n",
-      "85\n",
-      "86\n",
-      "87\n",
-      "88\n",
-      "89\n",
-      "90\n",
-      "91\n",
-      "92\n",
-      "93\n",
-      "94\n",
-      "95\n",
-      "96\n",
-      "97\n",
-      "98\n",
-      "99\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# for i in range(100):\n",
     "#     print(i)\n",
     "#         f.write(lcat(sorted(ds)))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "g, ws = interesting_grid(width=100, height=100, words_limit=1, max_words=2000, direction_slack=1)\n",
+    "p = pad_grid(g)\n",
+    "ds = decoys(p, ws, ws_words, limit=2500)\n",
+    "# print(show_grid(g))\n",
+    "# print()\n",
+    "# print(show_grid(p))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
+    "# print('Present:', wcat(sorted(ws)))\n",
+    "# print('Decoys:', wcat(sorted(ds)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "with open('huge-wordsearch.txt', 'w') as f:\n",
+    "        f.write('{}x{}\\n'.format(len(g[0]), len(g)))\n",
+    "        f.write(show_grid(p))\n",
+    "        f.write('\\n')\n",
+    "        f.write(lcat(sorted(ws + ds)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def read_wordsearch(fn):\n",
+    "    lines = [l.strip() for l in open(fn).readlines()]\n",
+    "    w, h = [int(s) for s in lines[0].split('x')]\n",
+    "    grid = lines[1:h+1]\n",
+    "    words = lines[h+1:]\n",
+    "    return w, h, grid, words"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def do_wordsearch_tasks(fn, show_anyway=False):\n",
+    "    width, height, grid, words = read_wordsearch(fn)\n",
+    "    used_words = [w for w in words if present(grid, w)[0]]\n",
+    "    unused_words = [w for w in words if not present(grid, w)[0]]\n",
+    "    lwp = sorted([w for w in words if present(grid, w)[0]], key=len)[-1]\n",
+    "    lwps = [w for w in used_words if len(w) == len(lwp)]\n",
+    "    lwa = sorted(unused_words, key=len)[-1]\n",
+    "    lwas = [w for w in unused_words if len(w) == len(lwa)]\n",
+    "    g0 = empty_grid(width, height)\n",
+    "    for w in words:\n",
+    "        p, r, c, d = present(grid, w)\n",
+    "        if p:\n",
+    "            set_grid(g0, r, c, d, w) \n",
+    "    unused_letters = [l for l, u in zip((c for c in cat(cat(l) for l in grid)), (c for c in cat(cat(l) for l in g0)))\n",
+    "                  if u == '.']\n",
+    "    unused_letter_count = collections.Counter(unused_letters)\n",
+    "    makeable_words = []\n",
+    "    for w in unused_words:\n",
+    "        unused_word_count = collections.Counter(w)\n",
+    "        if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
+    "            makeable_words += [w]\n",
+    "    lwm = sorted(makeable_words, key=len)[-1]\n",
+    "    lwms = [w for w in makeable_words if len(w) == len(lwm)]\n",
+    "    if show_anyway or len(set((len(lwp),len(lwa),len(lwm)))) == 3:\n",
+    "        print('\\n{}'.format(fn))\n",
+    "        print('{} words present'.format(len(words) - len(unused_words)))\n",
+    "        print('Longest word present: {}, {} letters ({})'.format(lwp, len(lwp), lwps))\n",
+    "        print('Longest word absent: {}, {} letters ({})'.format(lwa, len(lwa), lwas))\n",
+    "        print('{} unused letters'.format(len([c for c in cat(cat(l) for l in g0) if c == '.'])))\n",
+    "        print('Longest makeable word: {}, {} ({})'.format(lwm, len(lwm), lwms))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "[w for w in ws_words if len(w) == 16]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# all_lines = []\n",
+    "# for fn in sorted(os.listdir()):\n",
+    "#     if re.match('wordsearch\\d\\d\\.txt', fn):\n",
+    "#         all_lines += open(fn).readlines()\n",
+    "#         all_lines += ['\\n'] * 2\n",
+    "\n",
+    "# open('all-wordsearches.txt', 'w').writelines(all_lines)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 209,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Added 6 ; attempt 19\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "6"
+      ]
+     },
+     "execution_count": 209,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "g = empty_grid(10, 10)\n",
+    "g, ws = fill_grid(g, ws_words, 200, min_word_len=4, max_attempts=20)\n",
+    "len(ws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 210,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Added 1149 ; attempt 9427\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "IOPub message rate exceeded.\n",
+      "The notebook server will temporarily stop sending output\n",
+      "to the client in order to avoid crashing it.\n",
+      "To change this limit, set the config variable\n",
+      "`--NotebookApp.iopub_msg_rate_limit`.\n"
+     ]
+    }
+   ],
+   "source": [
+    "g = empty_grid(100, 100)\n",
+    "g, ws = fill_grid(g, ws_words, 2000, min_word_len=5)\n",
+    "len(ws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 216,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(1149, 1149, [('scofflaw', 1)])"
+      ]
+     },
+     "execution_count": 216,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pm = present_many(g, ws)\n",
+    "pold = [w for w in ws if present(g, w)[0]]\n",
+    "len(pm), len(pold), collections.Counter(p[0] for p in pm).most_common(1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 219,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "\n",
+    "with open('huge-unpadded-wordsearch.txt', 'w') as f:\n",
+    "        f.write('{}x{}\\n'.format(len(g[0]), len(g)))\n",
+    "        f.write(show_grid(g))\n",
+    "        f.write('\\n')\n",
+    "        f.write(lcat(sorted(ws)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 218,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "smuiclacphysics.hcnebrevilingd..skcabllup.s...gnitnacs..blusted.....pilafeldrig..enquireddetnawnu...\n",
+      "e....nutmegs.t..telbanimret...e..tseikwagewoodpeckerstirwas.b.r...picksn...ylhsiroobsuspectingsexevd\n",
+      "cgnittacdliw..isuoniallivsegas.lrafts.y.vcs..demrofsnart.mla...e.c....e..fannysdiscrimination.oe..e.\n",
+      "nnytima.wharfrep.stswashbucklersw....m.eos...noprat....ao.rs....t.h..m.relabele..sss...b.sc.ts..vb.s\n",
+      "eid..desivedaia.shegdtg.gniyugys.o..a.rme.gpantedsobeysodgm.a....t.osabound...s.bttp...uje.orhd.boe.\n",
+      "tverediw...dtlw.eiar.ehacrierhsrmccosiant.nbestridi..sreepegarotedadr.slaropauses..e..rdis.oteia.lld\n",
+      "nardd.p...itli.i.pesu.srwe...ciuuhfsnti.sgingivitislubl.fotkcuhs..rmsensitisedeu...eleygbutsiyjcf.u.\n",
+      "eerne.u..aiin.r.i.nset.ioku..taeia.gods.e.n..dh.n.emld.r.lht.hobnobsi.s..l.c.trs...jnb.ieoizw.llka.f\n",
+      "shiense.nhae.s.n.aietun.owig.idtrp.srsayi.w..ogu.oecnie..yo.u...whmt.t..u.a.lcds...tb.ondran.oeersa.\n",
+      ".nhpnnktsts...g.d.cve.qe.pblohdoaseomtc.r.a.tgnrgdnaiae.spd.sc.sora...nt.r.en.no..ro...g.l..msbfdue.\n",
+      ".asxiiasehcnerdj.moido.edsoayvebr.w.ufh.rtr.sgiaxgdekm.rtfo.k.noir.....ag.se..ur.al..sreraehsu.xnoet\n",
+      "gr.erah.peeweeu.i.tdir..h.acc.mard..tie.u.pdeehbo.eyx.u.ralge.kucnoveltiesseirfdp..buttocksn..laodne\n",
+      "nr.sgls..d..sdwrg.iela...c.uikise.o.altwf.i.idcbtged...poeoatsqo...gratefully..sportingsweepersaa..s\n",
+      "iaw.bp...e.hgor.ulnnstullee.ntl.t.mttps.os..d.tienstc...nhggcst.gsugaringinsight..snifters.....cde.i\n",
+      "nta..m..ssteno..i.eckef..b...ar..y.ieu.lpls.n.endirswu..gsiehs..n.delbaf....interpose..dsurt..r.el.u\n",
+      "oeg..oae.usdr..kl..ecd.aiproveso..llsdsayeb.a.ra.iee.er.l.esih.ti.sllihygrellapractisedatcneea..gg.r\n",
+      "sdeb.cziofe.r.e.d..da..rgthrive.p.agearetr.hs.stsavr..riy.srec.ar.pocketbooktrotxe.....nw.unlk..gg.b\n",
+      "a.re.a.m.rs.espumoneb.t..o.semorhc.rnadau.istp.eehio..cpoga.sn.uuyratchetswisher.....n.se..fepc.aos.\n",
+      "e.saf...fsrrh.a.retpada...t.....e.iggiiv.llcaam.vgnt.o.t.sidtu.pj.r.retemarapecnarussau.a.l.frpante.\n",
+      "rretarcurne.c.g.pellagra...s...d.wni.dk.elgnaae.inusm..msgibehfedtsl..prowldenimn.shiedrka...l.il.ss\n",
+      "n..i..leatgbt.rc..s..sesitengamedinkafgnonn.tladta.m....uentbl.aa.oeegniyartrop.eseitoobsnoleme.tpuu\n",
+      "ub.f.lent.gri.afassevissimagingslgiryuoriit...nsahaseigodniiyelwb..upwthguorb.obmil....hfeedings..tr\n",
+      ".a.yydne..aew.ryrri.emackintoshw.trsbnasnh.u..trksr.gasketrpc.raar..ptereinterpretingie....deggiwtnp\n",
+      ".s..nyl...raslitloeett.splinesobtih.gnlgtkt.r.ealwasset....usu.bvgi..eej......rtss.dnrtonnaccords.oa\n",
+      ".ihikers..bkawa.rtssrao...gc.r.yek..ues..rhn.ennaob.gmovers.bid.riwcsketches.esar.etsi.gswollefdebcs\n",
+      ".leticilli.zaen..uftsrnv..log..dils.rrc..noau.nitrlbr.eidrib.iwa.irea..st...ieiadxe.n.lrolocsid....s\n",
+      "sr...m....edl.s...loyeage.ap...e.pc....h..ilk.am.roouevilamsidv.r.e.gt..ge.gfdeaer.s.ygnideerbnquoit\n",
+      "reprobatesdiyruovasbs.d.oddu..hks..h.s..e..kliee.uoae.lairetsigamt.r..e..nneedmsp.t.p.incisesuhctulc\n",
+      "s.vr.t.sdld..s.controllablel.s.aleavese..l..s..s.btrshalvesylsuougibma.s.sim.pgo.avhshortensr.zzazip\n",
+      ".ebae.oliedpmsuesilangisg..a..hc.zingsyy..oqueryingdoreopened..endless...l.bs.lrlsnikskcub.t..knifed\n",
+      "jiklruons.lefilbsnwodwohsn.ttupnit..tdretsenohl..cvsm...gnimirgnidaetsemoh..baamongst..y.wucustomers\n",
+      "doionfgh.a.lsotej.....e.h.iee...gniretnuas..s..o.oa.e.g.r...snoitulos.selppitue..w...io.trrbfruits..\n",
+      ".eydj.g.n..i.iutvosplithsejlhp.s.eieinveighing..mnl.rlbu..pineapple....a.f.e.nsrealiseadel.ar.eevell\n",
+      "r.ertu.e..gc..dleoi....htiiyi.m.avr..transducers.fe.aatempts.b.....d.n.f.ud.t.scales.r.tr.aopinion.l\n",
+      ".d.yoveterinaryoenrn..a.bapg.wjuin..psalmist.x...innlenvd...iebrashereat.ne...snaeco..aeiide.ps...ii\n",
+      "..pb.dtacosei.l.sr.gim.b.eb.ho.nrideraems....opa.dcdri.ie..n.lv.sc.k.kweent.outsmartedwl.oaef.ek..mb\n",
+      "feweste....p.v.a.p..enisreesbtg..t.h.e.k.tt..bem.eecas.lpggday.ipmrn.akrqeasedoberofmrr.l.nhp..de.pn\n",
+      "dy.sighting...o.spalfngsd..b.cellistott.nscc.hdesshlhe.leinde.aas.ea.ewnulcsekytmrg.oa..co..la...tao\n",
+      ".ddr..object...r.aehg.ee..ipr......degmreioascontrrits.an.oieinw.umlzwaoa.iss..i.netu.midictatorialo\n",
+      ".e.em..muiretcab.sn.rnh.gnoigimletslry.denreftmdie.trsygdm.rssvsealplyrobcll.gx.i.egusnm..b.c.ps..ap\n",
+      ".pstekcolsopyh..s...schngpsteppes.esoadwcaib.aesvsrhiiree.iprikvrc.l.ydniapisenb.banaoicar.yagr...ss\n",
+      "ep.sew......macinimin.islp..s....xrpaotoirdf.mto.eoomharntse.elti.a.a.eslrxarebiajdahvalaslprnoarbez\n",
+      "so.ykbongothistlektass.iidsreg..e.ia.lreogaiweevilgg..n.tagrw.ia.d.r..s.ioemsoinsa.pnnavtr.adidllucs\n",
+      "il.oloverwhelmednilni.neegee.cnd.as.mduvrch.n.r..lurd.oarnasenilesab..t.tul.stkxuie.ctesae.rigd.....\n",
+      "rp..y.......l..ivbal.nrigdn.l.ni.n.damava..t.g...seaeyi.ik..se...rtheoryysab.shnolreeril.edknniesohw\n",
+      "oproponents.etli.kacotr.in.o.t.en.innsidu...relruc.pgetge.d.lciportosi...ega.itgeplpyautge.egon.ar..\n",
+      "ecaudalyokelrst.ynoiif.l.piklstsrrtf.aenvoyeuristichnludta.b.se.i.ngnirabrer.entuleaugsno.gd.rgdlibd\n",
+      "h..configurationontnt.g...omr.toteo.fsg.g..stsefni.yora.psa.t.l.msa.....e.rbd.sseol.e.at.x.dwhesieee\n",
+      "tpalsy.r..c.e..ivcsrscinap.tma.irsfm.uliuqnartoday..racp.neo..u.plncaninev.eg.eduynr.rg.e.ieat.lgngp\n",
+      "..fleshyuk.s.dteeme.eruptingtah.lhir.gm.r.contrastedhbe.ugni..p.uei.yamsidad.nreal..r.ny.rrntc.antoy\n",
+      "....yogins..earnis..ripeness.edsmethe.na.bsromalgte.trr.ni..k.m.lemigfieryed..iwvtta.wia.hnis.ss.eth\n",
+      "nonhuman..knnsnte...e...cupolargiitapt.igreideew.s.re.pie....oaespo.nrcb.y.ke.wlfiee.hdws.p...mu.d..\n",
+      "bywords...osiohme..estnemegagnedlnstcon.ya...primessn.mshockerhleyd..sehe.t.ssealra.daua.s....ar....\n",
+      "outlastedt.ocsb.c.x....enilefileeavgotsi.lrfordssgt..ettautnessbdebbadieil.p.ur.po.w.lle......oe.k.g\n",
+      "ddetsyrte.n..l.gnp.esuccocddypl.ppdeisi..rlpimplyn..ecg..dsuitcases.a.ksnfl.mdtnekrahecs.etsawfpn.cn\n",
+      "iawaitss.s..e.a.e..lp....euhauwpi.udrv.ve..er.a..udt..as.se...ctlocn.c.ltifsretaehcc.rnempollenag.ii\n",
+      "essertsimdaehrsci.gdr...tstrcocrn.stesidi..ejs...o.e..erq..lt.i.akaco.ksussocondoretsaocno....tdnnls\n",
+      "s.rettab.es.rptgc.ide..itaeidodohb.cynen.sn.o....y..vrcua..uclb.earhgiyhla.hn..lebil..c..ak..senioli\n",
+      "retsim.tlu.eoo.rssfaa.xsendns.ehoqa.oeesgdtpmoppets.ueeu.moseyu.cygan.tlaib..detoormoisterpe.l.olial\n",
+      "......hbbdtpr..inmt.desrtaetjhpilu.rlrtdsso.derunettceirltesl.csneofis.aenssregnifrettub...od.asbtha\n",
+      "sfeergalebia.f.noui.iobattlae.ebei.bdwe..r..os...gpoz.orslsl.le.odefdr..tvdn...adjectivess.dr.geaapr\n",
+      "....isitultscrbdccn.n.lelipa.gnime..is.dp....we..ane.b..toi..bikc.sener..ii.eslays.rp..c.du..pagnr.t\n",
+      "f..limocleiasoaegsgignduear..udtut.l...gambol.nsrv.ib.o.re.ni..mupfdete..ysa.t....ea.oa..fetm.taeu.n\n",
+      "o.ideokoslb.ewnr.nrso.psnss.reeifelatrinems....ei..etb.s..rvg...ol..rtc.y.lin.u..t.lsne.cp.tceeyypte\n",
+      "owd.mel.ear.isir.eipeatsenye.snvfr..latticeworkndlrfesgnihsalpslagf.suunsprlv...u..otk.tardslassgpcc\n",
+      "t.yltd.dl.e.hysam.uhtl.so.tm.scelcascadinghl..c.asiyrse.vexed.tsng.fshpaslpua..c.oasislliiumtocsguie\n",
+      "wynifnpseydscetdso.acyyi.e..i.elihslanifbstsle.r.vevrycv.....rhi.ne.tsetoahdstaupset..eascae.rj.isvd\n",
+      "euamrae.sliuraeicccecnttmstner.yn.st....olansonsade.ieeoi...oeo..i.ga.rubqyaito..deposittdaat.a.wael\n",
+      "apmeitr.ussrarra..aaraiosgy...g.g.gie...tewor.wart.n.cbrfd.odds.hrpnb.ar.usddlltpoesyrr.js.l...wt.he\n",
+      "rpisasmtoutgid.l..ilctnl.nabiopsy.gnbi..cwsii.gepei.g..u.fn.ee.cseiimptaweiecoae..s.euyu...ynominees\n",
+      ".ictrsiarorerr..gdiipoi.fiwgnilratsnibu.hortcgn.saef.e.rtslrre.lcknlooelahcka.rvre.isdraeslather...r\n",
+      "yekopuspalirtu.eenf.re.m.nbslartueneiloqebeakoihstlhi.ru...ap.aaonilculirskrs..nnsntaarttdetcartsbao\n",
+      ".s.n.bsrclcyamnmei.h.pl..nu.deniapeptllns.kvslky.mymce.fs.mawussrane.nasdaiut.ylsasetmae.canoes.oe.m\n",
+      "...e.oio.at.ptmrt.c..r...estappinggp.odos.cahfnm..imi.dfl.c.gtudihgv.cieiunlerugpshietetniksgipdnt..\n",
+      "flierroo.cs.liac.gunfire.pwhimsd..aa..grr.ucasue...rmn.lis.hidu.n..i.etdnqgerfoceaodidsdewotwokrgals\n",
+      "latconnm.f.e..epaimedc...deducesddshs..aunfx..rn....kugie.tgdl..g..n..y.g.nawn.krnilse.snoopingisgil\n",
+      "obmibsss..asir..l..a.eeviecerggee.em....ecue..tstoadspynveael....resonantgtan.ugseiti.ruolev...freao\n",
+      "u..gdarnsspegniciee.sylbatonarpgfhrsodomychaiserelbmuh.grtnsstseebedliw.o.la.p..ncmpr.enrapturetertv\n",
+      "t...rd...oncc.t.srnclennut.cainoaap...od..bfrolics.k....o.rosseforp...brazzesb.laopa.eseifidoc.elgee\n",
+      "v...ee..o..ooe.eslsth.ke...drarnwan.l.es..a...sc.liatesrohc.sdellennekgi..s.u.af.albtkn...clawsrigrn\n",
+      "o..bdbyc....krsindekyasa..etredsdodi.l.re.l..tgo.nobscuredhh..securere..al.c.nsfn.iace.i.coupledoanl\n",
+      "t.mei.si..maximaltedynn.sdstss.doem.iebe.dm.n.nng.gnippohca....m....dt..eso.dnes.a.operpetuatingbo.i\n",
+      "eegggclassroomss...ral.t.pssp.ewbidtlelpd.yedoic.g.....s.dnm..otopaetn.t.lsmov..sfh.s.piling....i..e\n",
+      "dahh.n...h..pecnarpeeti.yeeredsrte.ere.e..mdepkrn.np....iucsun..ae...eotisaie..eis.ey.rknittings..br\n",
+      "rt.eenickinglfy...l.rdig..ie.neet.cev.ha.eo.naceo.wispsenme.eie.gr..lmncertrntdxs.bdpsao.tokenismda.\n",
+      "...dla.g..i.oar.cc.e.onchnn.ktihttfi.s.lgg.lwqitcp.en.rpttmt.ldnn.ti.i.bkii.hgeamyseprzk.r..mld.e.l.\n",
+      ".vwkibp.a.n.wlo.ifg..g.ugtw.afglrtr.i..nwpa.auleae.crorpoaaek.ueo.ssoai.ds.a.ryognhkaaec..euye.ce.ad\n",
+      "..ai.nmseph.msvsta..st.qh.ow.iiirden..iornp.pes.ec.eboigarxcrld.tslp.r.ahsw.sitsra.ortde..svt.a.ndne\n",
+      "b.rl.inacae.aeatel.yortuetl.l.fn.irr.rooe..e.s..dcv.vuytireypii.i.a.c.rlessdnoluvy.pcsggsidaim.aoect\n",
+      "u.loi.rerrr.nssacs.tuoaac.bp.y..iuakfdpr..egatsopasetznlapsni.nmf.zs.tynctrgrato..c.so.in.repnr.rbet\n",
+      "tgibps.idceott.nsi.ittnrntnalaesfsnnseysword.c..lrdedoygst.lrnggisi.xaoinoscvrcharsa.cngmesiamn.kkdu\n",
+      "tnkye.e.uusel..cat.lh.aaa.legabnaei.r...kinderou.y.pler.lksleeg.e.eevtteleaeezzaipddpis.nmntfgfo.csp\n",
+      "eietd..mpqankffh.yaie.gnt.....use.gallivants..ic.l.uydpuner.uyttdysinadlcrove....ee.tslu.geuijnrcipt\n",
+      "rbred..peri.usoe.srbayetimikespl.debrutrepnu.n.rkl.mb.npsera.fosm.dimieiscovsrd.vtyr.om...l..fioisiu\n",
+      "nbisl.e.or.a..rs.eoastrireitliugselttit.....g..e.u.pr..iadmsbnemil.gcrt..siepeclrrapteswovasidfvcgro\n",
+      "uupcer.o..y.d.gtstulte.ne...rtsicitnamoraincoatk.bfearedkhayyeutycacyc.hwlgrc.oeematr...vended.ei.i.\n",
+      "trxrm.msinimefe.tani.i.ih..i.....edutingamsnoynac..decay..ceagd.ara.a.celnie.vsndwo...pinup...l.dntd\n",
+      "sgeosdrenblurbscalda.o.nn.n..cimonoxatkinetic..e....narks.k.rl..pl.r.teaihe.eer.pwryly...tubes.e..g.\n",
+      "..saesuohdraug..ie.v.m.gig.ycnangiop.tawdrier..w....scallopedsesiwp.atstcl.ddo.astelfael..bumblers..\n",
+      ".t.krandomises..rr.a..gripestsivitcellocsbawsshapeliest..gnitontoofhylluftsaobwsocilac..located..s..\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_grid(g))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 221,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Attempt 249 ; most common is [('scofflaw', 1)]\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(True, [('scofflaw', 1)])"
+      ]
+     },
+     "execution_count": 221,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "padded = False\n",
+    "padding_attempts = 0\n",
+    "while not padded and padding_attempts < 10**6:\n",
+    "    clear_output(wait=True)\n",
+    "    padding_attempts += 1\n",
+    "    pg = pad_grid(g)\n",
+    "    pm = present_many(pg, ws)\n",
+    "    print('Attempt', padding_attempts, '; most common is', collections.Counter(p[0] for p in pm).most_common(1))\n",
+    "    if collections.Counter(p[0] for p in pm).most_common(1)[0][1] == 1:\n",
+    "        padded = True\n",
+    "        \n",
+    "padded, collections.Counter(p[0] for p in pm).most_common(1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 222,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "249"
+      ]
+     },
+     "execution_count": 222,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "padding_attempts"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 230,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "851"
+      ]
+     },
+     "execution_count": 230,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dws = decoys(pg, ws, ws_words, limit=2000, min_word_len=5)\n",
+    "len(dws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 231,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "smuiclacphysicsihcnebrevilingdroskcabllupcsowygnitnacsipblustedpesnipilafeldrigclenquireddetnawnufly\n",
+      "eqdbmnutmegsvtzdtelbanimretanmelptseikwagewoodpeckerstirwaszbdrrdypicksnzikylhsiroobsuspectingsexevd\n",
+      "cgnittacdliwffisuoniallivsegasplraftstyevcsgcdemrofsnartrmlaydzescpopxehsfannysdiscriminationdoeypen\n",
+      "nnytimavwharfrepjstswashbucklerswklqimkeosulxnopratpsitaoorsrtrjtthnsmxrelabelesrssstribiscutsddvbrs\n",
+      "eidgkdesivedaiajshegdtgrgniyugyshohaabrmedgpantedsobeysodgmraoozdteosaboundgfjsmbttpygjujedorhdvboeh\n",
+      "tverediwtczdtlwdeiaryehacrierhsrmccosiantnnbestridikysreepegarotedadrpslaropausesubepnrdissoteiailld\n",
+      "narddypasjitligihpesubsrwewfgciuuhfsntizsgingivitislublefotkcuhschrmsensitisedeugnveleygbutsiyjcflud\n",
+      "eernefunuaiindrsilnsethiokutttaeiapgodsteknerdhlngemldlrslhtrhobnobsizsvdlocdtrszbnjnbpieoizwillkarf\n",
+      "shiensetnhaepslnnaietundowigvidtrptsrsayiewreogudoecniebbyofugamwhmtntwsufaulcdsmlptbeondrancoeersak\n",
+      "onhpnnktstsdovgsdicvevqeypblohdoaseomtcdrbaatgnrgdnaiaejspdtscrsoratzdntmrgenqnomiroixqgslltmsbfduee\n",
+      "lasxiiasehcnerdjomoidodedsoayvebrawnufhcrtrtsgiaxgdekmkrtfodkinoirfekkaagvsermuroalabsreraehsuxxnoet\n",
+      "grderahepeeweeusiutdirnohmaccsmardrztienunpdeehbomeyxruyralgeskucnoveltiesseirfdpyebuttocksntqlaodne\n",
+      "nrrsglsmxdupsdwrgoielalgmccuikisexoaaltwfniaidcbtgednzcpoeoatsqoszdgratefullytisportingsweepersaapys\n",
+      "iawlbpsleeyhgorhulnnstulleemntlgtnmttpssostidstienstcbfnnhggcstegsugaringinsighthrsniftersmmfwicdeoi\n",
+      "ntabemghsstenongideckefombnlrarlxynieuplplsznnendirswunfgsiehsuensdelbafetkzinterposexldsurtimreelhu\n",
+      "oegleoaeiusdrixklisecdiaiprovesoatllsdsayebsawrasieeterrlaesihztixsllihygrellapractisedatcneeavgggpr\n",
+      "sdebzczioferrsexdiadatergthrivelpdagearetrfhststsavrbyriymsrecharupocketbooktrotxextuvznwkunlkaqggtb\n",
+      "ayrewatmerseespumonebatlnoisemorhcdrnadaubistpoeehiouxcpogaesnsuuyratchetswishereatjingsepnfepckaose\n",
+      "eosafgcffsrrhsawretpadaspitgewuheaiggiivrllcaamkvgntrodtbsidtutpjnrgretemarapecnarussaugaylcfrpantet\n",
+      "rretarcurneicwgnpellagraupmsixcdswniodknelgnaaetinusmlomsgibehfedtslabprowldenimnushiedrkaqndltillss\n",
+      "ntoimlleatgbtlrcsxsehsesitengamedinkafgnonnxtladtabmvkifuentblwaaroeegniyartropieseitoobsnolemedtpuu\n",
+      "ubqfilentigrigafassevissimagingslgiryuoriitoarnsahaseigodniiyelwblmupwthguorbkobmilkiaxhfeedingspptr\n",
+      "nanyydnerxaewaryrriaemackintoshwftrsbnasnhsukntrksragasketrpcsraarliptereinterpretingieycoudeggiwtnp\n",
+      "msrgnylmnkraslitloeettosplinesobtihfgnlgtktmrxealwassetpiykusurbvgijzeejgpkxclrtssfdnrtonnaccordshoa\n",
+      "aihikersaebkawarrtssraodcrgckrpyekbruesuorhnpennaobwgmoversabidgriwcsketchesuesartetsicgswollefdebcs\n",
+      "zleticilliozaenkfuftsrnvzylogeldilsrrrcrinoautnitrlbroeidribuiwaeireakrstmioieiadxesnnlrolocsidazdms\n",
+      "srsyamajsmedlkssrdloyeagevapwanespcemorhucilkxamhroouevilamsidvarcemgtqggezgfdeaerosyygnideerbnquoit\n",
+      "reprobatesdiyruovasbsidboddubehksoehnssseevklieepuoaetlairetsigamtorocevinneedmspwtnpfincisesuhctulc\n",
+      "smvrnttsdldfysbcontrollablelfsraleaveseuslvpsavsgbtrshalvesylsuougibmaesesimcpgopavhshortensrszzazip\n",
+      "vebaeioliedpmsuesilangisgynainhcazingsyymqoqueryingdoreopenedhsendlessasolbbsqlrlsnikskcubetbrknifed\n",
+      "jiklruonsflefilbsnwodwohsnittupnitfstdretsenohlcrcvsmphngnimirgnidaetsemohgbbaamongstljykwucustomers\n",
+      "doionfghfaalsotejhlrgmewhiieelbbgniretnuasuqsuiouoazeggqrhrisnoituloswselppitueaowymrioutrrbfruitspa\n",
+      "veydjogonywisiutvosplithsejlhpesseieinveighingqymnlerlbukfpineappleeunkagfieensrealiseadelaarjeevell\n",
+      "rkertuiegvgcbodleoievtwhtiiyiomravrsetransducersafelaatemptspbjhkrudenifiudktdscalesfratreaopinionql\n",
+      "tddyoveterinaryoenrnedaebapgowjuiniepsalmistyxadtinnlenvdnakiebrashereatmneirdsnaecomfaeiidedpskfzii\n",
+      "kfpbgdtacoseizlfsrfgimrblebehopnrideraemsnfhropatdcdriuieyjnilvmschkhkweentaoutsmartedwlooaefiekydmb\n",
+      "fewestegwhcpuviacpfrenisreesbtgcktshueckfttuzbemteecaswlpggdaypipmrniakrqeasedoberofmrrqltnhphqdefpn\n",
+      "dyesightingateonspalfngsdqfbxcellistottrnscchhdesshlhefleindegaasmeatewnulcsekytmrgyoaoecoiilanlatao\n",
+      "hddrafobjectkatrsaehgdeertiprrzyalndegmreioascontrritspanloieinwiumlzwaoaiissziicnetuimidictatorialo\n",
+      "renemidmuiretcabgsnwrnhegnoigimletslrywdenreftmdiectrsygdmgrssvsealplyrobcllugxxibegusnmqebycrpsguap\n",
+      "npstekcolsopyhbnsthtschngpsteppeseesoadwcaibraesvsrhiireediprikvrcrlpydniapisenbibanaoicarlyagrflsss\n",
+      "epksewpfsbkymacinimincislpsvsvyifxrpaotoirdfzmtoreoomharntseseltiuazaeeslrxarebiajdahvalaslprnoarbez\n",
+      "soeykbongothistlektasssiidsregsleaiarlreogaiweevilggwznttagrwniaiddroasiioemsoinsaepnnavtrnadidllucs\n",
+      "illoloverwhelmednilnicneegeetcndjasdmduvrchpnnrfzlurdloarnasenilesabemtdtulestkxuiepctesaerrigdekiup\n",
+      "rpriyewmjoqxltmivbalqnrigdnglcniinfdamavaoitsgrskseaeyipikliserpcrtheoryysabushnolreerilpedknniesohw\n",
+      "oproponentsmetliekacotroinaoltrenlinnsidutbgrelrucqpgetgemdklciportosipuaegamitgeplpyautgefegoniarcu\n",
+      "ecaudalyokelrsttynoiifilipiklstsrrtftaenvoyeuristichnludtaqbgsewinngnirabrergentuleaugsnofgdfrgdlibd\n",
+      "hahconfigurationontntzghhtomrbtoteorfsgyguostsefninyoranpsaqtllumsaqodnbecrbdysseoluetatzxpdwhesieee\n",
+      "tpalsygrarcdeobivcsrscinapbtmanirsfmeuliuqnartodayebracpnneowyuaplncaninevnegxeduynrargueuieatllgngp\n",
+      "ixfleshyukesedteemeueruptingtahmlhirugmvrccontrastedhbehugniblpsueiayamsidadinrealahrenyyrrntcwantoy\n",
+      "fefmyoginsnnearnisieripenessjedsmethelnaabsromalgtentrrxnilrkgmjlemigfieryedopiwvttanwiafhnisrsseeth\n",
+      "nonhumanvcknnsnteayuemsncupolargiitapthigreideewosireipieirnooaespoanrcbqygkemwlfieefhdwsppehwmubdkw\n",
+      "bywordswjtosiohmetlestnemegagnedlnstcontyanlaprimessnbmshockerhleydesseheotossealraodauaascpraardpga\n",
+      "outlastedtaocsbbcrxmgjeenilefileeavgotsiulrfordssgtrsettautnessbdebbadieilppfurvpopwylleemnsiuoelksg\n",
+      "ddetsyrtemntalngnpwesuccocddyplqppdeisifmrlpimplyntzecggndsuitcaseskarksnflomdtnekrahecsuetsawfpnpcn\n",
+      "iawaitssbskoedamenelphzijeuhauwpieudrvzvennerraytudtcpasbsencactlocnrcaltifsretaehccsrnempollenagtii\n",
+      "essertsimdaehrsciagdrphststrcocrnvstesidiayejswheosedmerqhhltviuakacooksussocondoretsaocnofktptdnnls\n",
+      "ssrettabiesarptgciideyhitaeidodohbvcynenmsncoesiqyvgvrcuaxauclbcearhgiyhladhniblebiluncraakussenioli\n",
+      "retsimdtluweoolrssfaajxsendnszehoqaxoeesgdtpmoppetsgueeuamoseyumcyganhtlaibeodetoormoisterpejltolial\n",
+      "sbtrsyhbbdtprleinmtddesrtaetjhpilusrlrtdssoqderunettceirlteslhcsneofisxaenssregnifrettubudnodgasbtha\n",
+      "sfeergalebiamfsnouieiobattlaebebeicbdweejrruostolgpozsorslslvleiodefdrietvdniqtadjectivesswdrfgeaapr\n",
+      "widrisitultscrbdccninelelipahgnimeqeisldpjierweqianeubcetoiwsbikcusenerqniiceslaysxrpbmcedunupagnrnt\n",
+      "fcclimocleiasoaegsgignduearteudtutolkjugambolbnsrvyibvoxrerniipmupfdetezmysaatrcmpeatoaarfetmftaeuqn\n",
+      "okideokoslbcewnrxnrsospsnsszreeifelatrinemsnxnaeieeetbcsiurvgiesolqsrtcjyrlinaujstelsneqcpatceeyypte\n",
+      "owdmmeldeargisiraeipeatsenyecsnvfriilatticeworkndlrfesgnihsalpslagfosuunsprlvarnucjotkptardslassgpcc\n",
+      "tryltdndlgeehysamtuhtlcsoitmpscelcascadinghlsiceasiyrseovexeditsnghfshpaslpuadicsoasislliiumtocsguie\n",
+      "wynifnpseydscetdsofacyyiledfiqelihslanifbstslewrevevrycvygetxrhipnestsetoahdstaupsetxneascaearjmisvd\n",
+      "euamraessliuraeicccecnttmstneroynlstodopolansonsadetieeoinoeoeouwiegarrubqyaitovtdeposittdaatnarwael\n",
+      "apmeitrrussrarrazqaaraiosgypgbgagsgieunuteworpwartrnmcbrfdcoddsihrpnbearlusddlltpoesyrrtjsyljalwtghe\n",
+      "rpisasmtoutgidqlsuilctnlgnabiopsyngnbilacwsiibgepeiogstutfnheescseiimptaweiecoaegesdeuyuyfeynominees\n",
+      "aictrsiarorerromgdiipoirfiwgnilratsnibuohortcgnisaefzedrtslrreylcknlooelahckasrvregisdraeslatheriwhr\n",
+      "yekopuspalirtuneenfmresmonbslartueneiloqebeakoihstlhirruqapaptaaonilculirskrsqtnnsntaarttdetcartsbao\n",
+      "bsenobsrclcyamnmeiphrpleenufdeniapeptllnsvkvslkyamymceufsrmawussraneonasdaiutdylsasetmaeacanoesroefm\n",
+      "ruoejoioeatwptmrtkcaarqtgestappinggprodosicahfnmolimiydflecugtudihgvocieiunlerugpshietetniksgipdntmn\n",
+      "flierrooicsrliacagunfirejpwhimsdphaatngrreucasueufnrmnilisihiduinnlibetdnqgerfoceaodidsdewotwokrgals\n",
+      "latconnmtfoessepaimedcsatdeducesddshsvvaunfxnsrnvgszkugiettgdldtgrqnhqykgdnawnekrnilseisnoopingisgil\n",
+      "obmibsssylasirralfpameeviecerggeesemrbegecuebvtstoadspynveaelmhdiresonantgtanaugseitiiruolevtizfreao\n",
+      "uppgdarnsspegnicieersylbatonarpgfhrsodomychaiserelbmuhvgrtnsstseebedliwmoqlarpobncmpryenrapturetertv\n",
+      "tvawrdzsponccwtfsrnclennutrcainoaapnbhodepbfrolicsaktziuogrosseforpqfdbrazzesbolaopaneseifidocselgee\n",
+      "vesjeegvojmooeoeslsthukexwudrarnwanxlkestjacvhscgliatesrohcqsdellennekgiqnslueafsalbtkncttclawsrigrn\n",
+      "ozpbdbycrenekrsindekyasascetredsdodislbrejlrstgocnobscuredhhabsecurerechaliconsfnciacesixcoupledoanl\n",
+      "tlmeicsihqmaximaltedynnwsdstssldoemtiebeedmdnbnngvgnippohcaeetsmespodtfmesosdnesjaloperpetuatingbosi\n",
+      "eegggclassroomssniiralitlpsspsewbidtlelpduyedoicsgumgwfswdnmgfotopaetnrtvlsmovrnsfhfsmpilingcppuiafe\n",
+      "dahhjnprnhwepecnarpeetixyeeredsrtezeredeldmdepkrnmnpqfgsiucsunneaegsueotisaiecreisueyirknittingsbdbr\n",
+      "rtyeenickinglfygenlxrdigwsievneetfcevthaeeolnaceoiwispsenmedeielgrwblmncertrntdxsibdpsaostokenismdad\n",
+      "aeedlafgiuigoarnccgezonchnnlktihttfiasllggalwqitcpcencrpttmteldnnutixisbkiilhgeamyseprzkmrhnmldneild\n",
+      "tvwkibpeatnhwlozifgiigdugtwoafglrtrwizsnwpaiauleaencrorpoaaekiueoissoaihdszanryognhkaaeccceuyegcehad\n",
+      "ifaitnmsephymsvstaxfstrqhlowziiirdendhiornplpesyecbeboigarxcrldhtslpgrnahswasitsraiortdemysvtjaindne\n",
+      "berlyinacaepaeateliyortuetlclofnsirrdrooerleystfdcvlvuytireypiiaidamcyrlessdnoluvyzpcsggsidaimraoect\n",
+      "unloijrerrrcnssacsetuoaaccbpdymciuakfdpreuegatsopasetznlapsnirnmfkzsztynctrgratoeectsoainarepnrmrbet\n",
+      "tgibpsridceottensigittnrntnalaesfsnnseysworddcgtlrdedoygstrlrnggisimxaoinoscvrcharsapcngmesiamnmkkdu\n",
+      "tnkyeuejuuselpscatelhdaaarlegabnaeimriohkinderouaydplerylksleegheueevtteleaeezzaipddpismnmntfgfowcsp\n",
+      "eietdrimpqankffhpyaietgntwtyrbusesgallivantsdyicelxuydpunerjuyttdysinadlcrovejtloeeitsludgeuijnrcipt\n",
+      "rbredgyperimusoejsrbayetimikesplkdebrutrepnumnbrklwmbanpserahfosmtdimieiscovsrdrvtyraomissluafioisiu\n",
+      "nbisluelornaaorsteoastrireitliugselttitndxadgsweiufpreiiadmsbnemilqgcrtrnsiepeclrrapteswovasidfvcgro\n",
+      "uupceraowdyedtgtstulteoneucertsicitnamoraincoatkubfearedkhayyeutycacyclhwlgrcjoeematrvilvendedaeisin\n",
+      "trxrmgmsinimefestaniridihueiokfkdedutingamsnoynacqndecayswceagdoarakagcelniesvsndwomagpinupjyrlfdntd\n",
+      "sgeosdrenblurbscaldahomnnoncncimonoxatkineticrseqorhnarksokurlsqplrreteaiheeeerepwrylykpdtubesuerogi\n",
+      "qmsaesuohdraugzuiecvemsgigtycnangiopatawdrieroawjsonscallopedsesiwpratstclfddoiastelfaelihbumblersru\n",
+      "itekrandomisessvrraayrgripestsivitcellocsbawsshapeliestmjgnitontoofhylluftsaobwsocilacidlocatedlrsee\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_grid(pg))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 232,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2000"
+      ]
+     },
+     "execution_count": 232,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(dws) + len(ws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 233,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "with open('huge-wordsearch.txt', 'w') as f:\n",
+    "        f.write('{}x{}\\n'.format(len(pg[0]), len(pg)))\n",
+    "        f.write(show_grid(pg))\n",
+    "        f.write('\\n')\n",
+    "        f.write(lcat(sorted(ws + dws)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 234,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(1149, 1149)"
+      ]
+     },
+     "execution_count": 234,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pm = present_many(g, ws)\n",
+    "pold = [w for w in ws if present(g, w)[0]]\n",
+    "len(pm), len(pold)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 235,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(1149, 1149)"
+      ]
+     },
+     "execution_count": 235,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ppm = present_many(pg, ws)\n",
+    "ppold = [w for w in ws if present(pg, w)[0]]\n",
+    "len(ppm), len(ppold)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 236,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "smuiclacphysics.hcnebrevilingd..skcabllup.s...gnitnacs..blusted.....pilafeldrig..enquireddetnawnu...\n",
+      "e....nutmegs.t..telbanimret...e..tseikwagewoodpeckerstirwas.b.r...picksn...ylhsiroobsuspectingsexevd\n",
+      "cgnittacdliw..isuoniallivsegas.lrafts.y.vcs..demrofsnart.mla...e.c....e..fannysdiscrimination.oe..e.\n",
+      "nnytima.wharfrep.stswashbucklersw....m.eos...noprat....ao.rs....t.h..m.relabele..sss...b.sc.ts..vb.s\n",
+      "eid..desivedaia.shegdtg.gniyugys.o..a.rme.gpantedsobeysodgm.a....t.osabound...s.bttp...uje.orhd.boe.\n",
+      "tverediw...dtlw.eiar.ehacrierhsrmccosiant.nbestridi..sreepegarotedadr.slaropauses..e..rdis.oteia.lld\n",
+      "nardd.p...itli.i.pesu.srwe...ciuuhfsnti.sgingivitislubl.fotkcuhs..rmsensitisedeu...eleygbutsiyjcf.u.\n",
+      "eerne.u..aiin.r.i.nset.ioku..taeia.gods.e.n..dh.n.emld.r.lht.hobnobsi.s..l.c.trs...jnb.ieoizw.llka.f\n",
+      "shiense.nhae.s.n.aietun.owig.idtrp.srsayi.w..ogu.oecnie..yo.u...whmt.t..u.a.lcds...tb.ondran.oeersa.\n",
+      ".nhpnnktsts...g.d.cve.qe.pblohdoaseomtc.r.a.tgnrgdnaiae.spd.sc.sora...nt.r.en.no..ro...g.l..msbfdue.\n",
+      ".asxiiasehcnerdj.moido.edsoayvebr.w.ufh.rtr.sgiaxgdekm.rtfo.k.noir.....ag.se..ur.al..sreraehsu.xnoet\n",
+      "gr.erah.peeweeu.i.tdir..h.acc.mard..tie.u.pdeehbo.eyx.u.ralge.kucnoveltiesseirfdp..buttocksn..laodne\n",
+      "nr.sgls..d..sdwrg.iela...c.uikise.o.altwf.i.idcbtged...poeoatsqo...gratefully..sportingsweepersaa..s\n",
+      "iaw.bp...e.hgor.ulnnstullee.ntl.t.mttps.os..d.tienstc...nhggcst.gsugaringinsight..snifters.....cde.i\n",
+      "nta..m..ssteno..i.eckef..b...ar..y.ieu.lpls.n.endirswu..gsiehs..n.delbaf....interpose..dsurt..r.el.u\n",
+      "oeg..oae.usdr..kl..ecd.aiproveso..llsdsayeb.a.ra.iee.er.l.esih.ti.sllihygrellapractisedatcneea..gg.r\n",
+      "sdeb.cziofe.r.e.d..da..rgthrive.p.agearetr.hs.stsavr..riy.srec.ar.pocketbooktrotxe.....nw.unlk..gg.b\n",
+      "a.re.a.m.rs.espumoneb.t..o.semorhc.rnadau.istp.eehio..cpoga.sn.uuyratchetswisher.....n.se..fepc.aos.\n",
+      "e.saf...fsrrh.a.retpada...t.....e.iggiiv.llcaam.vgnt.o.t.sidtu.pj.r.retemarapecnarussau.a.l.frpante.\n",
+      "rretarcurne.c.g.pellagra...s...d.wni.dk.elgnaae.inusm..msgibehfedtsl..prowldenimn.shiedrka...l.il.ss\n",
+      "n..i..leatgbt.rc..s..sesitengamedinkafgnonn.tladta.m....uentbl.aa.oeegniyartrop.eseitoobsnoleme.tpuu\n",
+      "ub.f.lent.gri.afassevissimagingslgiryuoriit...nsahaseigodniiyelwb..upwthguorb.obmil....hfeedings..tr\n",
+      ".a.yydne..aew.ryrri.emackintoshw.trsbnasnh.u..trksr.gasketrpc.raar..ptereinterpretingie....deggiwtnp\n",
+      ".s..nyl...raslitloeett.splinesobtih.gnlgtkt.r.ealwasset....usu.bvgi..eej......rtss.dnrtonnaccords.oa\n",
+      ".ihikers..bkawa.rtssrao...gc.r.yek..ues..rhn.ennaob.gmovers.bid.riwcsketches.esar.etsi.gswollefdebcs\n",
+      ".leticilli.zaen..uftsrnv..log..dils.rrc..noau.nitrlbr.eidrib.iwa.irea..st...ieiadxe.n.lrolocsid....s\n",
+      "sr...m....edl.s...loyeage.ap...e.pc....h..ilk.am.roouevilamsidv.r.e.gt..ge.gfdeaer.s.ygnideerbnquoit\n",
+      "reprobatesdiyruovasbs.d.oddu..hks..h.s..e..kliee.uoae.lairetsigamt.r..e..nneedmsp.t.p.incisesuhctulc\n",
+      "s.vr.t.sdld..s.controllablel.s.aleavese..l..s..s.btrshalvesylsuougibma.s.sim.pgo.avhshortensr.zzazip\n",
+      ".ebae.oliedpmsuesilangisg..a..hc.zingsyy..oqueryingdoreopened..endless...l.bs.lrlsnikskcub.t..knifed\n",
+      "jiklruons.lefilbsnwodwohsn.ttupnit..tdretsenohl..cvsm...gnimirgnidaetsemoh..baamongst..y.wucustomers\n",
+      "doionfgh.a.lsotej.....e.h.iee...gniretnuas..s..o.oa.e.g.r...snoitulos.selppitue..w...io.trrbfruits..\n",
+      ".eydj.g.n..i.iutvosplithsejlhp.s.eieinveighing..mnl.rlbu..pineapple....a.f.e.nsrealiseadel.ar.eevell\n",
+      "r.ertu.e..gc..dleoi....htiiyi.m.avr..transducers.fe.aatempts.b.....d.n.f.ud.t.scales.r.tr.aopinion.l\n",
+      ".d.yoveterinaryoenrn..a.bapg.wjuin..psalmist.x...innlenvd...iebrashereat.ne...snaeco..aeiide.ps...ii\n",
+      "..pb.dtacosei.l.sr.gim.b.eb.ho.nrideraems....opa.dcdri.ie..n.lv.sc.k.kweent.outsmartedwl.oaef.ek..mb\n",
+      "feweste....p.v.a.p..enisreesbtg..t.h.e.k.tt..bem.eecas.lpggday.ipmrn.akrqeasedoberofmrr.l.nhp..de.pn\n",
+      "dy.sighting...o.spalfngsd..b.cellistott.nscc.hdesshlhe.leinde.aas.ea.ewnulcsekytmrg.oa..co..la...tao\n",
+      ".ddr..object...r.aehg.ee..ipr......degmreioascontrrits.an.oieinw.umlzwaoa.iss..i.netu.midictatorialo\n",
+      ".e.em..muiretcab.sn.rnh.gnoigimletslry.denreftmdie.trsygdm.rssvsealplyrobcll.gx.i.egusnm..b.c.ps..ap\n",
+      ".pstekcolsopyh..s...schngpsteppes.esoadwcaib.aesvsrhiiree.iprikvrc.l.ydniapisenb.banaoicar.yagr...ss\n",
+      "ep.sew......macinimin.islp..s....xrpaotoirdf.mto.eoomharntse.elti.a.a.eslrxarebiajdahvalaslprnoarbez\n",
+      "so.ykbongothistlektass.iidsreg..e.ia.lreogaiweevilgg..n.tagrw.ia.d.r..s.ioemsoinsa.pnnavtr.adidllucs\n",
+      "il.oloverwhelmednilni.neegee.cnd.as.mduvrch.n.r..lurd.oarnasenilesab..t.tul.stkxuie.ctesae.rigd.....\n",
+      "rp..y.......l..ivbal.nrigdn.l.ni.n.damava..t.g...seaeyi.ik..se...rtheoryysab.shnolreeril.edknniesohw\n",
+      "oproponents.etli.kacotr.in.o.t.en.innsidu...relruc.pgetge.d.lciportosi...ega.itgeplpyautge.egon.ar..\n",
+      "ecaudalyokelrst.ynoiif.l.piklstsrrtf.aenvoyeuristichnludta.b.se.i.ngnirabrer.entuleaugsno.gd.rgdlibd\n",
+      "h..configurationontnt.g...omr.toteo.fsg.g..stsefni.yora.psa.t.l.msa.....e.rbd.sseol.e.at.x.dwhesieee\n",
+      "tpalsy.r..c.e..ivcsrscinap.tma.irsfm.uliuqnartoday..racp.neo..u.plncaninev.eg.eduynr.rg.e.ieat.lgngp\n",
+      "..fleshyuk.s.dteeme.eruptingtah.lhir.gm.r.contrastedhbe.ugni..p.uei.yamsidad.nreal..r.ny.rrntc.antoy\n",
+      "....yogins..earnis..ripeness.edsmethe.na.bsromalgte.trr.ni..k.m.lemigfieryed..iwvtta.wia.hnis.ss.eth\n",
+      "nonhuman..knnsnte...e...cupolargiitapt.igreideew.s.re.pie....oaespo.nrcb.y.ke.wlfiee.hdws.p...mu.d..\n",
+      "bywords...osiohme..estnemegagnedlnstcon.ya...primessn.mshockerhleyd..sehe.t.ssealra.daua.s....ar....\n",
+      "outlastedt.ocsb.c.x....enilefileeavgotsi.lrfordssgt..ettautnessbdebbadieil.p.ur.po.w.lle......oe.k.g\n",
+      "ddetsyrte.n..l.gnp.esuccocddypl.ppdeisi..rlpimplyn..ecg..dsuitcases.a.ksnfl.mdtnekrahecs.etsawfpn.cn\n",
+      "iawaitss.s..e.a.e..lp....euhauwpi.udrv.ve..er.a..udt..as.se...ctlocn.c.ltifsretaehcc.rnempollenag.ii\n",
+      "essertsimdaehrsci.gdr...tstrcocrn.stesidi..ejs...o.e..erq..lt.i.akaco.ksussocondoretsaocno....tdnnls\n",
+      "s.rettab.es.rptgc.ide..itaeidodohb.cynen.sn.o....y..vrcua..uclb.earhgiyhla.hn..lebil..c..ak..senioli\n",
+      "retsim.tlu.eoo.rssfaa.xsendns.ehoqa.oeesgdtpmoppets.ueeu.moseyu.cygan.tlaib..detoormoisterpe.l.olial\n",
+      "......hbbdtpr..inmt.desrtaetjhpilu.rlrtdsso.derunettceirltesl.csneofis.aenssregnifrettub...od.asbtha\n",
+      "sfeergalebia.f.noui.iobattlae.ebei.bdwe..r..os...gpoz.orslsl.le.odefdr..tvdn...adjectivess.dr.geaapr\n",
+      "....isitultscrbdccn.n.lelipa.gnime..is.dp....we..ane.b..toi..bikc.sener..ii.eslays.rp..c.du..pagnr.t\n",
+      "f..limocleiasoaegsgignduear..udtut.l...gambol.nsrv.ib.o.re.ni..mupfdete..ysa.t....ea.oa..fetm.taeu.n\n",
+      "o.ideokoslb.ewnr.nrso.psnss.reeifelatrinems....ei..etb.s..rvg...ol..rtc.y.lin.u..t.lsne.cp.tceeyypte\n",
+      "owd.mel.ear.isir.eipeatsenye.snvfr..latticeworkndlrfesgnihsalpslagf.suunsprlv...u..otk.tardslassgpcc\n",
+      "t.yltd.dl.e.hysam.uhtl.so.tm.scelcascadinghl..c.asiyrse.vexed.tsng.fshpaslpua..c.oasislliiumtocsguie\n",
+      "wynifnpseydscetdso.acyyi.e..i.elihslanifbstsle.r.vevrycv.....rhi.ne.tsetoahdstaupset..eascae.rj.isvd\n",
+      "euamrae.sliuraeicccecnttmstner.yn.st....olansonsade.ieeoi...oeo..i.ga.rubqyaito..deposittdaat.a.wael\n",
+      "apmeitr.ussrarra..aaraiosgy...g.g.gie...tewor.wart.n.cbrfd.odds.hrpnb.ar.usddlltpoesyrr.js.l...wt.he\n",
+      "rpisasmtoutgid.l..ilctnl.nabiopsy.gnbi..cwsii.gepei.g..u.fn.ee.cseiimptaweiecoae..s.euyu...ynominees\n",
+      ".ictrsiarorerr..gdiipoi.fiwgnilratsnibu.hortcgn.saef.e.rtslrre.lcknlooelahcka.rvre.isdraeslather...r\n",
+      "yekopuspalirtu.eenf.re.m.nbslartueneiloqebeakoihstlhi.ru...ap.aaonilculirskrs..nnsntaarttdetcartsbao\n",
+      ".s.n.bsrclcyamnmei.h.pl..nu.deniapeptllns.kvslky.mymce.fs.mawussrane.nasdaiut.ylsasetmae.canoes.oe.m\n",
+      "...e.oio.at.ptmrt.c..r...estappinggp.odos.cahfnm..imi.dfl.c.gtudihgv.cieiunlerugpshietetniksgipdnt..\n",
+      "flierroo.cs.liac.gunfire.pwhimsd..aa..grr.ucasue...rmn.lis.hidu.n..i.etdnqgerfoceaodidsdewotwokrgals\n",
+      "latconnm.f.e..epaimedc...deducesddshs..aunfx..rn....kugie.tgdl..g..n..y.g.nawn.krnilse.snoopingisgil\n",
+      "obmibsss..asir..l..a.eeviecerggee.em....ecue..tstoadspynveael....resonantgtan.ugseiti.ruolev...freao\n",
+      "u..gdarnsspegniciee.sylbatonarpgfhrsodomychaiserelbmuh.grtnsstseebedliw.o.la.p..ncmpr.enrapturetertv\n",
+      "t...rd...oncc.t.srnclennut.cainoaap...od..bfrolics.k....o.rosseforp...brazzesb.laopa.eseifidoc.elgee\n",
+      "v...ee..o..ooe.eslsth.ke...drarnwan.l.es..a...sc.liatesrohc.sdellennekgi..s.u.af.albtkn...clawsrigrn\n",
+      "o..bdbyc....krsindekyasa..etredsdodi.l.re.l..tgo.nobscuredhh..securere..al.c.nsfn.iace.i.coupledoanl\n",
+      "t.mei.si..maximaltedynn.sdstss.doem.iebe.dm.n.nng.gnippohca....m....dt..eso.dnes.a.operpetuatingbo.i\n",
+      "eegggclassroomss...ral.t.pssp.ewbidtlelpd.yedoic.g.....s.dnm..otopaetn.t.lsmov..sfh.s.piling....i..e\n",
+      "dahh.n...h..pecnarpeeti.yeeredsrte.ere.e..mdepkrn.np....iucsun..ae...eotisaie..eis.ey.rknittings..br\n",
+      "rt.eenickinglfy...l.rdig..ie.neet.cev.ha.eo.naceo.wispsenme.eie.gr..lmncertrntdxs.bdpsao.tokenismda.\n",
+      "...dla.g..i.oar.cc.e.onchnn.ktihttfi.s.lgg.lwqitcp.en.rpttmt.ldnn.ti.i.bkii.hgeamyseprzk.r..mld.e.l.\n",
+      ".vwkibp.a.n.wlo.ifg..g.ugtw.afglrtr.i..nwpa.auleae.crorpoaaek.ueo.ssoai.ds.a.ryognhkaaec..euye.ce.ad\n",
+      "..ai.nmseph.msvsta..st.qh.ow.iiirden..iornp.pes.ec.eboigarxcrld.tslp.r.ahsw.sitsra.ortde..svt.a.ndne\n",
+      "b.rl.inacae.aeatel.yortuetl.l.fn.irr.rooe..e.s..dcv.vuytireypii.i.a.c.rlessdnoluvy.pcsggsidaim.aoect\n",
+      "u.loi.rerrr.nssacs.tuoaac.bp.y..iuakfdpr..egatsopasetznlapsni.nmf.zs.tynctrgrato..c.so.in.repnr.rbet\n",
+      "tgibps.idceott.nsi.ittnrntnalaesfsnnseysword.c..lrdedoygst.lrnggisi.xaoinoscvrcharsa.cngmesiamn.kkdu\n",
+      "tnkye.e.uusel..cat.lh.aaa.legabnaei.r...kinderou.y.pler.lksleeg.e.eevtteleaeezzaipddpis.nmntfgfo.csp\n",
+      "eietd..mpqankffh.yaie.gnt.....use.gallivants..ic.l.uydpuner.uyttdysinadlcrove....ee.tslu.geuijnrcipt\n",
+      "rbred..peri.usoe.srbayetimikespl.debrutrepnu.n.rkl.mb.npsera.fosm.dimieiscovsrd.vtyr.om...l..fioisiu\n",
+      "nbisl.e.or.a..rs.eoastrireitliugselttit.....g..e.u.pr..iadmsbnemil.gcrt..siepeclrrapteswovasidfvcgro\n",
+      "uupcer.o..y.d.gtstulte.ne...rtsicitnamoraincoatk.bfearedkhayyeutycacyc.hwlgrc.oeematr...vended.ei.i.\n",
+      "trxrm.msinimefe.tani.i.ih..i.....edutingamsnoynac..decay..ceagd.ara.a.celnie.vsndwo...pinup...l.dntd\n",
+      "sgeosdrenblurbscalda.o.nn.n..cimonoxatkinetic..e....narks.k.rl..pl.r.teaihe.eer.pwryly...tubes.e..g.\n",
+      "..saesuohdraug..ie.v.m.gig.ycnangiop.tawdrier..w....scallopedsesiwp.atstcl.ddo.astelfael..bumblers..\n",
+      ".t.krandomises..rr.a..gripestsivitcellocsbawsshapeliest..gnitontoofhylluftsaobwsocilac..located..s..\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_grid(g))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,