{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import string\n",
    "import re\n",
    "import collections\n",
    "import copy\n",
    "import os\n",
    "\n",
    "from enum import Enum\n",
    "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
    "    \n",
    "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
    "         Direction.up: (-1, 0), Direction.down: (1, 0), \n",
    "         Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
    "         Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
    "\n",
    "cat = ''.join\n",
    "wcat = ' '.join\n",
    "lcat = '\\n'.join"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def empty_grid(w, h):\n",
    "    return [['.' for c in range(w)] for r in range(h)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def show_grid(grid):\n",
    "    return lcat(cat(r) for r in grid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def indices(grid, r, c, l, d):\n",
    "    dr, dc = delta[d]\n",
    "    w = len(grid[0])\n",
    "    h = len(grid)\n",
    "    inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
    "    return [(i, j) for i, j in inds\n",
    "           if i >= 0\n",
    "           if j >= 0\n",
    "           if i < h\n",
    "           if j < w]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def gslice(grid, r, c, l, d):\n",
    "    return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def set_grid(grid, r, c, d, word):\n",
    "    for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
    "        grid[i][j] = l\n",
    "    return grid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def could_add(grid, r, c, d, word):\n",
    "    s = gslice(grid, r, c, len(word), d)\n",
    "    return re.fullmatch(cat(s), word)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def present(grid, word):\n",
    "    w = len(grid[0])\n",
    "    h = len(grid)\n",
    "    for r in range(h):\n",
    "        for c in range(w):\n",
    "            for d in Direction:\n",
    "                if cat(gslice(grid, r, c, len(word), d)) == word:\n",
    "                    return True, r, c, d\n",
    "    return False, 0, 0, list(Direction)[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def pad_grid(g0):\n",
    "    grid = copy.deepcopy(g0)\n",
    "    w = len(grid[0])\n",
    "    h = len(grid)\n",
    "    for r in range(h):\n",
    "        for c in range(w):\n",
    "            if grid[r][c] == '.':\n",
    "                grid[r][c] = random_wordsearch_letter()\n",
    "    return grid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "collapsed": false
   },
   "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": 77,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(['iisnoitpircserpoacos',\n",
       "  'eohgiodnpgbeautypoar',\n",
       "  'arsllorcsnestdomofne',\n",
       "  'irfdeemseirrgarnlfrb',\n",
       "  'tclumpingkoeasevoedm',\n",
       "  'hetobsibecgftdcmgrvi',\n",
       "  'isesrepoeuelmsriyset',\n",
       "  'eknaodouusnoedetoxes',\n",
       "  'vldwiarsoiogsstiedue',\n",
       "  'ehealcegdsuidsesuifi',\n",
       "  'dirrsiidnesepmdaelnc',\n",
       "  'nierrrsdeibuwpegriga',\n",
       "  'sprirrsyebniednusirb',\n",
       "  'eeboraisahmieeaycnnw',\n",
       "  'irrrnbrnepcmanhriuug',\n",
       "  'tjasdypeykuanppetiot',\n",
       "  'nuvaaaicssndonrppmer',\n",
       "  'areeioassenyocoaooze',\n",
       "  'hellesoamalabruptest',\n",
       "  'csygsfyosinightclubs'],\n",
       " ['abruptest',\n",
       "  'apology',\n",
       "  'assumed',\n",
       "  'barricades',\n",
       "  'beauty',\n",
       "  'bravely',\n",
       "  'bravos',\n",
       "  'burlier',\n",
       "  'chanties',\n",
       "  'clumping',\n",
       "  'coached',\n",
       "  'coffers',\n",
       "  'coyness',\n",
       "  'decriminalisation',\n",
       "  'detoxes',\n",
       "  'differs',\n",
       "  'duelled',\n",
       "  'duplicating',\n",
       "  'elaborates',\n",
       "  'embroils',\n",
       "  'encirclement',\n",
       "  'erogenous',\n",
       "  'facsimiled',\n",
       "  'festers',\n",
       "  'flickering',\n",
       "  'fusible',\n",
       "  'gluiest',\n",
       "  'golfers',\n",
       "  'interpolations',\n",
       "  'involved',\n",
       "  'irony',\n",
       "  'lithographed',\n",
       "  'nabbed',\n",
       "  'nightclubs',\n",
       "  'oblongs',\n",
       "  'optics',\n",
       "  'orphaned',\n",
       "  'overstates',\n",
       "  'paining',\n",
       "  'papery',\n",
       "  'perjures',\n",
       "  'prescriptions',\n",
       "  'prissier',\n",
       "  'rallies',\n",
       "  'rebated',\n",
       "  'reneges',\n",
       "  'saleswomen',\n",
       "  'scrolls',\n",
       "  'searing',\n",
       "  'slobbering',\n",
       "  'soups',\n",
       "  'sucking',\n",
       "  'tenderer',\n",
       "  'thieved',\n",
       "  'timbers',\n",
       "  'toiletries',\n",
       "  'unabashed',\n",
       "  'warriors',\n",
       "  'wimpy',\n",
       "  'wriest'])"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "width, height, g, ws = read_wordsearch('wordsearch1.txt')\n",
    "g, ws"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "abruptest (True, 18, 11, <Direction.right: 2>)\n",
      "apology (True, 0, 16, <Direction.down: 4>)\n",
      "assumed (True, 18, 7, <Direction.upright: 6>)\n",
      "barricades (True, 14, 5, <Direction.up: 3>)\n",
      "beauty (True, 1, 10, <Direction.right: 2>)\n",
      "bravely (True, 13, 2, <Direction.down: 4>)\n",
      "bravos (False, 0, 0, <Direction.left: 1>)\n",
      "burlier (False, 0, 0, <Direction.left: 1>)\n",
      "chanties (True, 19, 0, <Direction.up: 3>)\n",
      "clumping (True, 4, 1, <Direction.right: 2>)\n",
      "coached (True, 17, 13, <Direction.upleft: 5>)\n",
      "coffers (True, 0, 17, <Direction.down: 4>)\n",
      "coyness (True, 17, 13, <Direction.left: 1>)\n",
      "decriminalisation (False, 0, 0, <Direction.left: 1>)\n",
      "detoxes (True, 7, 13, <Direction.right: 2>)\n",
      "differs (False, 0, 0, <Direction.left: 1>)\n",
      "duelled (False, 0, 0, <Direction.left: 1>)\n",
      "duplicating (False, 0, 0, <Direction.left: 1>)\n",
      "elaborates (False, 0, 0, <Direction.left: 1>)\n",
      "embroils (True, 3, 4, <Direction.down: 4>)\n",
      "encirclement (False, 0, 0, <Direction.left: 1>)\n",
      "erogenous (True, 2, 10, <Direction.down: 4>)\n",
      "facsimiled (False, 0, 0, <Direction.left: 1>)\n",
      "festers (False, 0, 0, <Direction.left: 1>)\n",
      "flickering (False, 0, 0, <Direction.left: 1>)\n",
      "fusible (False, 0, 0, <Direction.left: 1>)\n",
      "gluiest (True, 11, 18, <Direction.upleft: 5>)\n",
      "golfers (True, 8, 11, <Direction.up: 3>)\n",
      "interpolations (False, 0, 0, <Direction.left: 1>)\n",
      "involved (False, 0, 0, <Direction.left: 1>)\n",
      "irony (True, 11, 1, <Direction.downright: 8>)\n",
      "lithographed (False, 0, 0, <Direction.left: 1>)\n",
      "nabbed (True, 14, 7, <Direction.upright: 6>)\n",
      "nightclubs (True, 19, 10, <Direction.right: 2>)\n",
      "oblongs (False, 0, 0, <Direction.left: 1>)\n",
      "optics (True, 17, 16, <Direction.up: 3>)\n",
      "orphaned (True, 17, 14, <Direction.up: 3>)\n",
      "overstates (False, 0, 0, <Direction.left: 1>)\n",
      "paining (True, 15, 13, <Direction.upleft: 5>)\n",
      "papery (True, 18, 15, <Direction.up: 3>)\n",
      "perjures (True, 12, 1, <Direction.down: 4>)\n",
      "prescriptions (True, 0, 14, <Direction.left: 1>)\n",
      "prissier (True, 15, 6, <Direction.up: 3>)\n",
      "rallies (False, 0, 0, <Direction.left: 1>)\n",
      "rebated (False, 0, 0, <Direction.left: 1>)\n",
      "reneges (False, 0, 0, <Direction.left: 1>)\n",
      "saleswomen (False, 0, 0, <Direction.left: 1>)\n",
      "scrolls (True, 2, 8, <Direction.left: 1>)\n",
      "searing (True, 8, 13, <Direction.downright: 8>)\n",
      "slobbering (False, 0, 0, <Direction.left: 1>)\n",
      "soups (True, 9, 9, <Direction.upleft: 5>)\n",
      "sucking (True, 7, 9, <Direction.up: 3>)\n",
      "tenderer (True, 5, 2, <Direction.down: 4>)\n",
      "thieved (True, 4, 0, <Direction.down: 4>)\n",
      "timbers (True, 6, 19, <Direction.up: 3>)\n",
      "toiletries (False, 0, 0, <Direction.left: 1>)\n",
      "unabashed (False, 0, 0, <Direction.left: 1>)\n",
      "warriors (True, 8, 3, <Direction.down: 4>)\n",
      "wimpy (True, 11, 12, <Direction.downleft: 7>)\n",
      "wriest (True, 13, 19, <Direction.upleft: 5>)\n"
     ]
    }
   ],
   "source": [
    "for w in ws:\n",
    "    print(w, present(g, w))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Which words are present?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['abruptest',\n",
       " 'apology',\n",
       " 'assumed',\n",
       " 'barricades',\n",
       " 'beauty',\n",
       " 'bravely',\n",
       " 'chanties',\n",
       " 'clumping',\n",
       " 'coached',\n",
       " 'coffers',\n",
       " 'coyness',\n",
       " 'detoxes',\n",
       " 'embroils',\n",
       " 'erogenous',\n",
       " 'gluiest',\n",
       " 'golfers',\n",
       " 'irony',\n",
       " 'nabbed',\n",
       " 'nightclubs',\n",
       " 'optics',\n",
       " 'orphaned',\n",
       " 'paining',\n",
       " 'papery',\n",
       " 'perjures',\n",
       " 'prescriptions',\n",
       " 'prissier',\n",
       " 'scrolls',\n",
       " 'searing',\n",
       " 'soups',\n",
       " 'sucking',\n",
       " 'tenderer',\n",
       " 'thieved',\n",
       " 'timbers',\n",
       " 'warriors',\n",
       " 'wimpy',\n",
       " 'wriest']"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[w for w in ws if present(g, w)[0]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What is the longest word that is present?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'prescriptions'"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted([w for w in ws if present(g, w)[0]], key=len)[-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What is the longest word that is absent?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'decriminalisation'"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted([w for w in ws if not present(g, w)[0]], key=len)[-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "How many letters are unused?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "143"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g0 = empty_grid(width, height)\n",
    "for w in ws:\n",
    "    p, r, c, d = present(g, w)\n",
    "    if p:\n",
    "        set_grid(g0, r, c, d, w)\n",
    "len([c for c in cat(cat(l) for l in g0) if c == '.'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What is the longest word you can make form the leftover letters?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({'a': 11,\n",
       "         'b': 2,\n",
       "         'c': 3,\n",
       "         'd': 10,\n",
       "         'e': 21,\n",
       "         'f': 3,\n",
       "         'g': 4,\n",
       "         'h': 2,\n",
       "         'i': 15,\n",
       "         'k': 2,\n",
       "         'l': 3,\n",
       "         'm': 7,\n",
       "         'n': 10,\n",
       "         'o': 13,\n",
       "         'p': 3,\n",
       "         'r': 9,\n",
       "         's': 12,\n",
       "         't': 2,\n",
       "         'u': 6,\n",
       "         'v': 2,\n",
       "         'y': 2,\n",
       "         'z': 1})"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "unused_letters = [l for l, u in zip((c for c in cat(cat(l) for l in g)), (c for c in cat(cat(l) for l in g0)))\n",
    "                  if u == '.']\n",
    "unused_letter_count = collections.Counter(unused_letters)\n",
    "unused_letter_count"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['bravos',\n",
       " 'burlier',\n",
       " 'decriminalisation',\n",
       " 'differs',\n",
       " 'duelled',\n",
       " 'duplicating',\n",
       " 'elaborates',\n",
       " 'encirclement',\n",
       " 'facsimiled',\n",
       " 'festers',\n",
       " 'flickering',\n",
       " 'fusible',\n",
       " 'interpolations',\n",
       " 'involved',\n",
       " 'lithographed',\n",
       " 'oblongs',\n",
       " 'overstates',\n",
       " 'rallies',\n",
       " 'rebated',\n",
       " 'reneges',\n",
       " 'saleswomen',\n",
       " 'slobbering',\n",
       " 'toiletries',\n",
       " 'unabashed']"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "unused_words = [w for w in ws if not present(g, w)[0]]\n",
    "unused_words"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*bravos Counter({'v': 1, 'b': 1, 'a': 1, 's': 1, 'o': 1, 'r': 1})\n",
      "*burlier Counter({'r': 2, 'b': 1, 'u': 1, 'l': 1, 'i': 1, 'e': 1})\n",
      "*decriminalisation Counter({'i': 4, 'n': 2, 'a': 2, 's': 1, 'l': 1, 'd': 1, 'e': 1, 'r': 1, 't': 1, 'm': 1, 'o': 1, 'c': 1})\n",
      "*differs Counter({'f': 2, 's': 1, 'i': 1, 'd': 1, 'e': 1, 'r': 1})\n",
      "*duelled Counter({'d': 2, 'e': 2, 'l': 2, 'u': 1})\n",
      "*duplicating Counter({'i': 2, 'g': 1, 'n': 1, 'a': 1, 'l': 1, 'd': 1, 't': 1, 'p': 1, 'u': 1, 'c': 1})\n",
      "*elaborates Counter({'a': 2, 'e': 2, 'b': 1, 's': 1, 'l': 1, 'o': 1, 'r': 1, 't': 1})\n",
      "*encirclement Counter({'e': 3, 'n': 2, 'c': 2, 'm': 1, 't': 1, 'l': 1, 'i': 1, 'r': 1})\n",
      "*facsimiled Counter({'i': 2, 's': 1, 'm': 1, 'a': 1, 'f': 1, 'l': 1, 'd': 1, 'e': 1, 'c': 1})\n",
      "*festers Counter({'s': 2, 'e': 2, 'f': 1, 'r': 1, 't': 1})\n",
      "*flickering Counter({'i': 2, 'g': 1, 'n': 1, 'f': 1, 'l': 1, 'e': 1, 'k': 1, 'r': 1, 'c': 1})\n",
      "*fusible Counter({'s': 1, 'e': 1, 'f': 1, 'b': 1, 'i': 1, 'l': 1, 'u': 1})\n",
      "*interpolations Counter({'n': 2, 'i': 2, 'o': 2, 't': 2, 's': 1, 'a': 1, 'l': 1, 'e': 1, 'p': 1, 'r': 1})\n",
      "*involved Counter({'v': 2, 'n': 1, 'l': 1, 'i': 1, 'o': 1, 'e': 1, 'd': 1})\n",
      "*lithographed Counter({'h': 2, 'g': 1, 'a': 1, 'r': 1, 'l': 1, 'i': 1, 'o': 1, 'e': 1, 'p': 1, 'd': 1, 't': 1})\n",
      "*oblongs Counter({'o': 2, 'b': 1, 'g': 1, 'n': 1, 'l': 1, 's': 1})\n",
      "*overstates Counter({'s': 2, 'e': 2, 't': 2, 'v': 1, 'a': 1, 'o': 1, 'r': 1})\n",
      "*rallies Counter({'l': 2, 's': 1, 'a': 1, 'i': 1, 'e': 1, 'r': 1})\n",
      "*rebated Counter({'e': 2, 'b': 1, 'a': 1, 'd': 1, 'r': 1, 't': 1})\n",
      "*reneges Counter({'e': 3, 's': 1, 'g': 1, 'n': 1, 'r': 1})\n",
      "saleswomen Counter({'s': 2, 'e': 2, 'm': 1, 'n': 1, 'a': 1, 'l': 1, 'o': 1, 'w': 1})\n",
      "*slobbering Counter({'b': 2, 's': 1, 'g': 1, 'n': 1, 'i': 1, 'o': 1, 'e': 1, 'l': 1, 'r': 1})\n",
      "*toiletries Counter({'i': 2, 'e': 2, 't': 2, 's': 1, 'l': 1, 'o': 1, 'r': 1})\n",
      "*unabashed Counter({'a': 2, 'b': 1, 'n': 1, 'h': 1, 's': 1, 'd': 1, 'e': 1, 'u': 1})\n"
     ]
    }
   ],
   "source": [
    "makeable_words = []\n",
    "for w in unused_words:\n",
    "    unused_word_count = collections.Counter(w)\n",
    "    if all(l in unused_letter_count and unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
    "        makeable_words += [w]\n",
    "        print('*', end='')\n",
    "    print(w, unused_word_count)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "17"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "max(len(w) for w in makeable_words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'decriminalisation'"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted(makeable_words, key=len)[-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def do_wordsearch_tasks(fn):\n",
    "    width, height, grid, words = read_wordsearch(fn)\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",
    "    lwa = sorted(unused_words, key=len)[-1]\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(l in unused_letter_count and 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",
    "    print('\\n{}'.format(fn))\n",
    "    print('Longest word present: {}, {} letters'.format(lwp, len(lwp)))\n",
    "    print('Longest word absent: {}, {} letters'.format(lwa, len(lwa)))\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)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "wordsearch00.txt\n",
      "Longest word present: testamentary, 12 letters\n",
      "Longest word absent: decontamination, 15 letters\n",
      "133 unused letters\n",
      "Longest makeable word: decontamination, 15\n",
      "\n",
      "wordsearch01.txt\n",
      "Longest word present: corresponded, 12 letters\n",
      "Longest word absent: antihistamines, 14 letters\n",
      "115 unused letters\n",
      "Longest makeable word: universality, 12\n",
      "\n",
      "wordsearch02.txt\n",
      "Longest word present: presupposing, 12 letters\n",
      "Longest word absent: chloroformed, 12 letters\n",
      "114 unused letters\n",
      "Longest makeable word: chloroformed, 12\n",
      "\n",
      "wordsearch03.txt\n",
      "Longest word present: pasteurisation, 14 letters\n",
      "Longest word absent: spotlessness, 12 letters\n",
      "115 unused letters\n",
      "Longest makeable word: spotlessness, 12\n",
      "\n",
      "wordsearch04.txt\n",
      "Longest word present: domestication, 13 letters\n",
      "Longest word absent: discountenances, 15 letters\n",
      "123 unused letters\n",
      "Longest makeable word: discountenances, 15\n",
      "\n",
      "wordsearch05.txt\n",
      "Longest word present: refinancing, 11 letters\n",
      "Longest word absent: polytechnics, 12 letters\n",
      "124 unused letters\n",
      "Longest makeable word: polytechnics, 12\n",
      "\n",
      "wordsearch06.txt\n",
      "Longest word present: playwrights, 11 letters\n",
      "Longest word absent: conglomerations, 15 letters\n",
      "137 unused letters\n",
      "Longest makeable word: conglomerations, 15\n",
      "\n",
      "wordsearch07.txt\n",
      "Longest word present: negotiations, 12 letters\n",
      "Longest word absent: electroplating, 14 letters\n",
      "110 unused letters\n",
      "Longest makeable word: electroplating, 14\n",
      "\n",
      "wordsearch08.txt\n",
      "Longest word present: schoolhouses, 12 letters\n",
      "Longest word absent: tonsillectomies, 15 letters\n",
      "129 unused letters\n",
      "Longest makeable word: tonsillectomies, 15\n",
      "\n",
      "wordsearch09.txt\n",
      "Longest word present: ecumenically, 12 letters\n",
      "Longest word absent: vulgarisation, 13 letters\n",
      "136 unused letters\n",
      "Longest makeable word: vulgarisation, 13\n",
      "\n",
      "wordsearch10.txt\n",
      "Longest word present: cosmological, 12 letters\n",
      "Longest word absent: flabbergasting, 14 letters\n",
      "115 unused letters\n",
      "Longest makeable word: perversions, 11\n",
      "\n",
      "wordsearch11.txt\n",
      "Longest word present: penultimates, 12 letters\n",
      "Longest word absent: slaughterhouses, 15 letters\n",
      "122 unused letters\n",
      "Longest makeable word: unfriendliness, 14\n",
      "\n",
      "wordsearch12.txt\n",
      "Longest word present: unintelligibly, 14 letters\n",
      "Longest word absent: equestriennes, 13 letters\n",
      "124 unused letters\n",
      "Longest makeable word: unresponsive, 12\n",
      "\n",
      "wordsearch13.txt\n",
      "Longest word present: fearlessness, 12 letters\n",
      "Longest word absent: impoverishing, 13 letters\n",
      "130 unused letters\n",
      "Longest makeable word: impoverishing, 13\n",
      "\n",
      "wordsearch14.txt\n",
      "Longest word present: separations, 11 letters\n",
      "Longest word absent: perambulated, 12 letters\n",
      "159 unused letters\n",
      "Longest makeable word: perambulated, 12\n",
      "\n",
      "wordsearch15.txt\n",
      "Longest word present: undisciplined, 13 letters\n",
      "Longest word absent: noncontagious, 13 letters\n",
      "128 unused letters\n",
      "Longest makeable word: noncontagious, 13\n",
      "\n",
      "wordsearch16.txt\n",
      "Longest word present: intergalactic, 13 letters\n",
      "Longest word absent: beautification, 14 letters\n",
      "107 unused letters\n",
      "Longest makeable word: pharmacopeias, 13\n",
      "\n",
      "wordsearch17.txt\n",
      "Longest word present: undershirts, 11 letters\n",
      "Longest word absent: photographing, 13 letters\n",
      "138 unused letters\n",
      "Longest makeable word: photographing, 13\n",
      "\n",
      "wordsearch18.txt\n",
      "Longest word present: humanitarians, 13 letters\n",
      "Longest word absent: environmentalists, 17 letters\n",
      "120 unused letters\n",
      "Longest makeable word: proportionality, 15\n",
      "\n",
      "wordsearch19.txt\n",
      "Longest word present: regurgitates, 12 letters\n",
      "Longest word absent: unsatisfactory, 14 letters\n",
      "122 unused letters\n",
      "Longest makeable word: unsatisfactory, 14\n"
     ]
    }
   ],
   "source": [
    "for fn in sorted(os.listdir()):\n",
    "    if re.match('wordsearch\\d\\d\\.txt', fn):\n",
    "        do_wordsearch_tasks(fn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2+"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}