86b1d9c018b43e25eb53d6ac5c75406d9134772c
[ou-summer-of-code-2017.git] / 04-word-search / wordsearch-solving.ipynb
1 {
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Wordsearch\n",
8 "Given a text file, consisting of three parts (a grid size, a grid, and a list of words), find:\n",
9 "* the words present in the grid, \n",
10 "* the longest word present in the grid, \n",
11 "* the number of words not present in the grid, \n",
12 "* the longest word not present that can be formed from the leftover letters\n",
13 "\n",
14 "The only words that need be considered are the ones given in the list in the puzzle input.\n",
15 "\n",
16 "The puzzle consists of:\n",
17 "1. A line consisting of _w_`x`_h_, where _w_ and _h_ are integers giving the width and height of the grid.\n",
18 "2. The grid itself, consisting of _h_ lines each of _w_ letters.\n",
19 "3. A list of words, one word per line, of arbitrary length. "
20 ]
21 },
22 {
23 "cell_type": "markdown",
24 "metadata": {},
25 "source": [
26 "## Example\n",
27 "\n",
28 "\n",
29 "`...p.mown.\n",
30 ".sdse..ee.\n",
31 ".e.elad.cr\n",
32 "pi.dtir.ah\n",
33 "rzsiwovspu\n",
34 "oawh.kieab\n",
35 "brow.c.rda\n",
36 "ecnotops.r\n",
37 "d.kc.d...b\n",
38 ".staple...`\n",
39 "\n",
40 "```\n",
41 "fhjpamownq\n",
42 "wsdseuqeev\n",
43 "ieaeladhcr\n",
44 "piedtiriah\n",
45 "rzsiwovspu\n",
46 "oawhakieab\n",
47 "browpcfrda\n",
48 "ecnotopssr\n",
49 "dikchdnpnb\n",
50 "bstapleokr\n",
51 "```\n",
52 "\n",
53 "14 words added; 6 directions\n",
54 "\n",
55 "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
56 "\n",
57 "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",
58 "\n",
59 "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>)`')]"
60 ]
61 },
62 {
63 "cell_type": "code",
64 "execution_count": 6,
65 "metadata": {},
66 "outputs": [],
67 "source": [
68 "import string\n",
69 "import re\n",
70 "import collections\n",
71 "import copy\n",
72 "import os\n",
73 "\n",
74 "from enum import Enum\n",
75 "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
76 " \n",
77 "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
78 " Direction.up: (-1, 0), Direction.down: (1, 0), \n",
79 " Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
80 " Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
81 "\n",
82 "cat = ''.join\n",
83 "wcat = ' '.join\n",
84 "lcat = '\\n'.join"
85 ]
86 },
87 {
88 "cell_type": "code",
89 "execution_count": 7,
90 "metadata": {
91 "collapsed": true
92 },
93 "outputs": [],
94 "source": [
95 "def empty_grid(w, h):\n",
96 " return [['.' for c in range(w)] for r in range(h)]"
97 ]
98 },
99 {
100 "cell_type": "code",
101 "execution_count": 8,
102 "metadata": {
103 "collapsed": true
104 },
105 "outputs": [],
106 "source": [
107 "def show_grid(grid):\n",
108 " return lcat(cat(r) for r in grid)"
109 ]
110 },
111 {
112 "cell_type": "code",
113 "execution_count": 9,
114 "metadata": {
115 "collapsed": true
116 },
117 "outputs": [],
118 "source": [
119 "def indices(grid, r, c, l, d):\n",
120 " dr, dc = delta[d]\n",
121 " w = len(grid[0])\n",
122 " h = len(grid)\n",
123 " inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
124 " return [(i, j) for i, j in inds\n",
125 " if i >= 0\n",
126 " if j >= 0\n",
127 " if i < h\n",
128 " if j < w]"
129 ]
130 },
131 {
132 "cell_type": "code",
133 "execution_count": 10,
134 "metadata": {
135 "collapsed": true
136 },
137 "outputs": [],
138 "source": [
139 "def gslice(grid, r, c, l, d):\n",
140 " return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
141 ]
142 },
143 {
144 "cell_type": "code",
145 "execution_count": 11,
146 "metadata": {
147 "collapsed": true
148 },
149 "outputs": [],
150 "source": [
151 "def set_grid(grid, r, c, d, word):\n",
152 " for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
153 " grid[i][j] = l\n",
154 " return grid"
155 ]
156 },
157 {
158 "cell_type": "code",
159 "execution_count": 12,
160 "metadata": {
161 "collapsed": true
162 },
163 "outputs": [],
164 "source": [
165 "def present(grid, word):\n",
166 " w = len(grid[0])\n",
167 " h = len(grid)\n",
168 " for r in range(h):\n",
169 " for c in range(w):\n",
170 " for d in Direction:\n",
171 " if cat(gslice(grid, r, c, len(word), d)) == word:\n",
172 " return True, r, c, d\n",
173 " return False, 0, 0, list(Direction)[0]"
174 ]
175 },
176 {
177 "cell_type": "code",
178 "execution_count": 13,
179 "metadata": {},
180 "outputs": [],
181 "source": [
182 "def read_wordsearch(fn):\n",
183 " lines = [l.strip() for l in open(fn).readlines()]\n",
184 " w, h = [int(s) for s in lines[0].split('x')]\n",
185 " grid = lines[1:h+1]\n",
186 " words = lines[h+1:]\n",
187 " return w, h, grid, words"
188 ]
189 },
190 {
191 "cell_type": "code",
192 "execution_count": 14,
193 "metadata": {
194 "scrolled": true
195 },
196 "outputs": [
197 {
198 "data": {
199 "text/plain": [
200 "(['pistrohxegniydutslxt',\n",
201 " 'wmregunarbpiledsyuoo',\n",
202 " 'hojminbmutartslrlmgo',\n",
203 " 'isrsdniiekildabolpll',\n",
204 " 'tstsnyekentypkalases',\n",
205 " 'ssnetengcrfetedirgdt',\n",
206 " 'religstasuslatxauner',\n",
207 " 'elgcpgatsklglzistilo',\n",
208 " 'tndlimitationilkasan',\n",
209 " 'aousropedlygiifeniog',\n",
210 " 'kilrprepszffsyzqsrhs',\n",
211 " 'itlaadorableorpccese',\n",
212 " 'noaeewoodedpngmqicnl',\n",
213 " 'gmrtoitailingchelrok',\n",
214 " 'jadsngninetsahtooeic',\n",
215 " 'xeernighestsailarmtu',\n",
216 " 'aeabsolvednscumdfnon',\n",
217 " 'gydammingawlcandornk',\n",
218 " 'hurlerslvkaccxcinosw',\n",
219 " 'iqnanoitacifitrofqqi'],\n",
220 " ['absolved',\n",
221 " 'adorable',\n",
222 " 'aeon',\n",
223 " 'alias',\n",
224 " 'ancestor',\n",
225 " 'baritone',\n",
226 " 'bemusing',\n",
227 " 'blonds',\n",
228 " 'bran',\n",
229 " 'calcite',\n",
230 " 'candor',\n",
231 " 'conciseness',\n",
232 " 'consequent',\n",
233 " 'cuddle',\n",
234 " 'damming',\n",
235 " 'dashboards',\n",
236 " 'despairing',\n",
237 " 'dint',\n",
238 " 'dullard',\n",
239 " 'dynasty',\n",
240 " 'employer',\n",
241 " 'exhorts',\n",
242 " 'feted',\n",
243 " 'fill',\n",
244 " 'flattens',\n",
245 " 'foghorn',\n",
246 " 'fortification',\n",
247 " 'freakish',\n",
248 " 'frolics',\n",
249 " 'gall',\n",
250 " 'gees',\n",
251 " 'genies',\n",
252 " 'gets',\n",
253 " 'hastening',\n",
254 " 'hits',\n",
255 " 'hopelessness',\n",
256 " 'hurlers',\n",
257 " 'impales',\n",
258 " 'infix',\n",
259 " 'inflow',\n",
260 " 'innumerable',\n",
261 " 'intentional',\n",
262 " 'jerkin',\n",
263 " 'justification',\n",
264 " 'kitty',\n",
265 " 'knuckles',\n",
266 " 'leaving',\n",
267 " 'like',\n",
268 " 'limitation',\n",
269 " 'locoweeds',\n",
270 " 'loot',\n",
271 " 'lucking',\n",
272 " 'lumps',\n",
273 " 'mercerising',\n",
274 " 'monickers',\n",
275 " 'motionless',\n",
276 " 'naturally',\n",
277 " 'nighest',\n",
278 " 'notion',\n",
279 " 'ogled',\n",
280 " 'originality',\n",
281 " 'outings',\n",
282 " 'pendulous',\n",
283 " 'piled',\n",
284 " 'pins',\n",
285 " 'pithier',\n",
286 " 'prep',\n",
287 " 'randomness',\n",
288 " 'rectors',\n",
289 " 'redrew',\n",
290 " 'reformulated',\n",
291 " 'remoteness',\n",
292 " 'retaking',\n",
293 " 'rethink',\n",
294 " 'rope',\n",
295 " 'rubier',\n",
296 " 'sailors',\n",
297 " 'scowls',\n",
298 " 'scum',\n",
299 " 'sepals',\n",
300 " 'sequencers',\n",
301 " 'serf',\n",
302 " 'shoaled',\n",
303 " 'shook',\n",
304 " 'sonic',\n",
305 " 'spottiest',\n",
306 " 'stag',\n",
307 " 'stood',\n",
308 " 'stratum',\n",
309 " 'strong',\n",
310 " 'studying',\n",
311 " 'surtaxing',\n",
312 " 'tailing',\n",
313 " 'tears',\n",
314 " 'teazles',\n",
315 " 'vans',\n",
316 " 'wardrobes',\n",
317 " 'wooded',\n",
318 " 'worsts',\n",
319 " 'zings'])"
320 ]
321 },
322 "execution_count": 14,
323 "metadata": {},
324 "output_type": "execute_result"
325 }
326 ],
327 "source": [
328 "width, height, g, ws = read_wordsearch('wordsearch04.txt')\n",
329 "g, ws"
330 ]
331 },
332 {
333 "cell_type": "code",
334 "execution_count": 15,
335 "metadata": {
336 "scrolled": true
337 },
338 "outputs": [
339 {
340 "name": "stdout",
341 "output_type": "stream",
342 "text": [
343 "absolved (True, 16, 2, <Direction.right: 2>)\n",
344 "adorable (True, 11, 4, <Direction.right: 2>)\n",
345 "aeon (True, 11, 4, <Direction.down: 4>)\n",
346 "alias (True, 15, 15, <Direction.left: 1>)\n",
347 "ancestor (False, 0, 0, <Direction.left: 1>)\n",
348 "baritone (False, 0, 0, <Direction.left: 1>)\n",
349 "bemusing (False, 0, 0, <Direction.left: 1>)\n",
350 "blonds (False, 0, 0, <Direction.left: 1>)\n",
351 "bran (True, 1, 9, <Direction.left: 1>)\n",
352 "calcite (True, 19, 9, <Direction.upright: 6>)\n",
353 "candor (True, 17, 12, <Direction.right: 2>)\n",
354 "conciseness (False, 0, 0, <Direction.left: 1>)\n",
355 "consequent (False, 0, 0, <Direction.left: 1>)\n",
356 "cuddle (False, 0, 0, <Direction.left: 1>)\n",
357 "damming (True, 17, 2, <Direction.right: 2>)\n",
358 "dashboards (False, 0, 0, <Direction.left: 1>)\n",
359 "despairing (False, 0, 0, <Direction.left: 1>)\n",
360 "dint (False, 0, 0, <Direction.left: 1>)\n",
361 "dullard (True, 8, 2, <Direction.down: 4>)\n",
362 "dynasty (True, 3, 4, <Direction.downright: 8>)\n",
363 "employer (False, 0, 0, <Direction.left: 1>)\n",
364 "exhorts (True, 0, 8, <Direction.left: 1>)\n",
365 "feted (True, 5, 10, <Direction.right: 2>)\n",
366 "fill (True, 9, 14, <Direction.upleft: 5>)\n",
367 "flattens (True, 10, 10, <Direction.upleft: 5>)\n",
368 "foghorn (True, 10, 11, <Direction.downright: 8>)\n",
369 "fortification (True, 19, 16, <Direction.left: 1>)\n",
370 "freakish (False, 0, 0, <Direction.left: 1>)\n",
371 "frolics (True, 16, 16, <Direction.up: 3>)\n",
372 "gall (False, 0, 0, <Direction.left: 1>)\n",
373 "gees (True, 17, 0, <Direction.upright: 6>)\n",
374 "genies (True, 5, 7, <Direction.upleft: 5>)\n",
375 "gets (True, 6, 4, <Direction.upleft: 5>)\n",
376 "hastening (True, 14, 13, <Direction.left: 1>)\n",
377 "hits (True, 2, 0, <Direction.down: 4>)\n",
378 "hopelessness (False, 0, 0, <Direction.left: 1>)\n",
379 "hurlers (True, 18, 0, <Direction.right: 2>)\n",
380 "impales (False, 0, 0, <Direction.left: 1>)\n",
381 "infix (False, 0, 0, <Direction.left: 1>)\n",
382 "inflow (False, 0, 0, <Direction.left: 1>)\n",
383 "innumerable (False, 0, 0, <Direction.left: 1>)\n",
384 "intentional (False, 0, 0, <Direction.left: 1>)\n",
385 "jerkin (False, 0, 0, <Direction.left: 1>)\n",
386 "justification (False, 0, 0, <Direction.left: 1>)\n",
387 "kitty (True, 8, 15, <Direction.upleft: 5>)\n",
388 "knuckles (True, 17, 19, <Direction.up: 3>)\n",
389 "leaving (False, 0, 0, <Direction.left: 1>)\n",
390 "like (True, 3, 11, <Direction.left: 1>)\n",
391 "limitation (True, 8, 3, <Direction.right: 2>)\n",
392 "locoweeds (False, 0, 0, <Direction.left: 1>)\n",
393 "loot (True, 3, 19, <Direction.up: 3>)\n",
394 "lucking (True, 7, 10, <Direction.upleft: 5>)\n",
395 "lumps (True, 0, 17, <Direction.down: 4>)\n",
396 "mercerising (True, 15, 17, <Direction.up: 3>)\n",
397 "monickers (False, 0, 0, <Direction.left: 1>)\n",
398 "motionless (True, 13, 1, <Direction.up: 3>)\n",
399 "naturally (True, 9, 16, <Direction.up: 3>)\n",
400 "nighest (True, 15, 4, <Direction.right: 2>)\n",
401 "notion (True, 17, 18, <Direction.up: 3>)\n",
402 "ogled (True, 1, 18, <Direction.down: 4>)\n",
403 "originality (False, 0, 0, <Direction.left: 1>)\n",
404 "outings (False, 0, 0, <Direction.left: 1>)\n",
405 "pendulous (False, 0, 0, <Direction.left: 1>)\n",
406 "piled (True, 1, 10, <Direction.right: 2>)\n",
407 "pins (True, 7, 4, <Direction.upleft: 5>)\n",
408 "pithier (False, 0, 0, <Direction.left: 1>)\n",
409 "prep (True, 10, 4, <Direction.right: 2>)\n",
410 "randomness (False, 0, 0, <Direction.left: 1>)\n",
411 "rectors (False, 0, 0, <Direction.left: 1>)\n",
412 "redrew (False, 0, 0, <Direction.left: 1>)\n",
413 "reformulated (False, 0, 0, <Direction.left: 1>)\n",
414 "remoteness (False, 0, 0, <Direction.left: 1>)\n",
415 "retaking (True, 6, 0, <Direction.down: 4>)\n",
416 "rethink (False, 0, 0, <Direction.left: 1>)\n",
417 "rope (True, 9, 4, <Direction.right: 2>)\n",
418 "rubier (True, 0, 4, <Direction.downright: 8>)\n",
419 "sailors (True, 7, 15, <Direction.up: 3>)\n",
420 "scowls (False, 0, 0, <Direction.left: 1>)\n",
421 "scum (True, 16, 11, <Direction.right: 2>)\n",
422 "sepals (True, 6, 10, <Direction.upright: 6>)\n",
423 "sequencers (False, 0, 0, <Direction.left: 1>)\n",
424 "serf (False, 0, 0, <Direction.left: 1>)\n",
425 "shoaled (True, 11, 18, <Direction.up: 3>)\n",
426 "shook (False, 0, 0, <Direction.left: 1>)\n",
427 "sonic (True, 18, 18, <Direction.left: 1>)\n",
428 "spottiest (False, 0, 0, <Direction.left: 1>)\n",
429 "stag (True, 7, 8, <Direction.left: 1>)\n",
430 "stood (False, 0, 0, <Direction.left: 1>)\n",
431 "stratum (True, 2, 13, <Direction.left: 1>)\n",
432 "strong (True, 4, 19, <Direction.down: 4>)\n",
433 "studying (True, 0, 16, <Direction.left: 1>)\n",
434 "surtaxing (False, 0, 0, <Direction.left: 1>)\n",
435 "tailing (True, 13, 6, <Direction.right: 2>)\n",
436 "tears (True, 13, 3, <Direction.up: 3>)\n",
437 "teazles (True, 4, 10, <Direction.downright: 8>)\n",
438 "vans (True, 18, 8, <Direction.upright: 6>)\n",
439 "wardrobes (False, 0, 0, <Direction.left: 1>)\n",
440 "wooded (True, 12, 5, <Direction.right: 2>)\n",
441 "worsts (True, 1, 0, <Direction.downright: 8>)\n",
442 "zings (True, 10, 14, <Direction.upleft: 5>)\n"
443 ]
444 }
445 ],
446 "source": [
447 "for w in ws:\n",
448 " print(w, present(g, w))"
449 ]
450 },
451 {
452 "cell_type": "markdown",
453 "metadata": {},
454 "source": [
455 "Which words are present?"
456 ]
457 },
458 {
459 "cell_type": "code",
460 "execution_count": 16,
461 "metadata": {
462 "scrolled": true
463 },
464 "outputs": [
465 {
466 "data": {
467 "text/plain": [
468 "['absolved',\n",
469 " 'adorable',\n",
470 " 'aeon',\n",
471 " 'alias',\n",
472 " 'bran',\n",
473 " 'calcite',\n",
474 " 'candor',\n",
475 " 'damming',\n",
476 " 'dullard',\n",
477 " 'dynasty',\n",
478 " 'exhorts',\n",
479 " 'feted',\n",
480 " 'fill',\n",
481 " 'flattens',\n",
482 " 'foghorn',\n",
483 " 'fortification',\n",
484 " 'frolics',\n",
485 " 'gees',\n",
486 " 'genies',\n",
487 " 'gets',\n",
488 " 'hastening',\n",
489 " 'hits',\n",
490 " 'hurlers',\n",
491 " 'kitty',\n",
492 " 'knuckles',\n",
493 " 'like',\n",
494 " 'limitation',\n",
495 " 'loot',\n",
496 " 'lucking',\n",
497 " 'lumps',\n",
498 " 'mercerising',\n",
499 " 'motionless',\n",
500 " 'naturally',\n",
501 " 'nighest',\n",
502 " 'notion',\n",
503 " 'ogled',\n",
504 " 'piled',\n",
505 " 'pins',\n",
506 " 'prep',\n",
507 " 'retaking',\n",
508 " 'rope',\n",
509 " 'rubier',\n",
510 " 'sailors',\n",
511 " 'scum',\n",
512 " 'sepals',\n",
513 " 'shoaled',\n",
514 " 'sonic',\n",
515 " 'stag',\n",
516 " 'stratum',\n",
517 " 'strong',\n",
518 " 'studying',\n",
519 " 'tailing',\n",
520 " 'tears',\n",
521 " 'teazles',\n",
522 " 'vans',\n",
523 " 'wooded',\n",
524 " 'worsts',\n",
525 " 'zings']"
526 ]
527 },
528 "execution_count": 16,
529 "metadata": {},
530 "output_type": "execute_result"
531 }
532 ],
533 "source": [
534 "[w for w in ws if present(g, w)[0]]"
535 ]
536 },
537 {
538 "cell_type": "markdown",
539 "metadata": {},
540 "source": [
541 "What is the longest word that is present?"
542 ]
543 },
544 {
545 "cell_type": "code",
546 "execution_count": 17,
547 "metadata": {},
548 "outputs": [
549 {
550 "data": {
551 "text/plain": [
552 "'fortification'"
553 ]
554 },
555 "execution_count": 17,
556 "metadata": {},
557 "output_type": "execute_result"
558 }
559 ],
560 "source": [
561 "sorted([w for w in ws if present(g, w)[0]], key=len)[-1]"
562 ]
563 },
564 {
565 "cell_type": "markdown",
566 "metadata": {},
567 "source": [
568 "What is the longest word that is absent?"
569 ]
570 },
571 {
572 "cell_type": "code",
573 "execution_count": 18,
574 "metadata": {},
575 "outputs": [
576 {
577 "data": {
578 "text/plain": [
579 "'justification'"
580 ]
581 },
582 "execution_count": 18,
583 "metadata": {},
584 "output_type": "execute_result"
585 }
586 ],
587 "source": [
588 "sorted([w for w in ws if not present(g, w)[0]], key=len)[-1]"
589 ]
590 },
591 {
592 "cell_type": "markdown",
593 "metadata": {},
594 "source": [
595 "How many letters are unused?"
596 ]
597 },
598 {
599 "cell_type": "code",
600 "execution_count": 19,
601 "metadata": {},
602 "outputs": [
603 {
604 "data": {
605 "text/plain": [
606 "57"
607 ]
608 },
609 "execution_count": 19,
610 "metadata": {},
611 "output_type": "execute_result"
612 }
613 ],
614 "source": [
615 "g0 = empty_grid(width, height)\n",
616 "for w in ws:\n",
617 " p, r, c, d = present(g, w)\n",
618 " if p:\n",
619 " set_grid(g0, r, c, d, w)\n",
620 "len([c for c in cat(cat(l) for l in g0) if c == '.'])"
621 ]
622 },
623 {
624 "cell_type": "markdown",
625 "metadata": {},
626 "source": [
627 "What is the longest word you can make form the leftover letters?"
628 ]
629 },
630 {
631 "cell_type": "code",
632 "execution_count": 20,
633 "metadata": {
634 "scrolled": true
635 },
636 "outputs": [
637 {
638 "data": {
639 "text/plain": [
640 "Counter({'a': 4,\n",
641 " 'b': 1,\n",
642 " 'c': 5,\n",
643 " 'd': 3,\n",
644 " 'e': 1,\n",
645 " 'g': 2,\n",
646 " 'i': 5,\n",
647 " 'j': 2,\n",
648 " 'k': 3,\n",
649 " 'l': 2,\n",
650 " 'm': 3,\n",
651 " 'n': 3,\n",
652 " 'p': 3,\n",
653 " 'q': 5,\n",
654 " 'r': 3,\n",
655 " 's': 3,\n",
656 " 'w': 2,\n",
657 " 'x': 4,\n",
658 " 'y': 2,\n",
659 " 'z': 1})"
660 ]
661 },
662 "execution_count": 20,
663 "metadata": {},
664 "output_type": "execute_result"
665 }
666 ],
667 "source": [
668 "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",
669 " if u == '.']\n",
670 "unused_letter_count = collections.Counter(unused_letters)\n",
671 "unused_letter_count"
672 ]
673 },
674 {
675 "cell_type": "code",
676 "execution_count": 21,
677 "metadata": {
678 "scrolled": true
679 },
680 "outputs": [
681 {
682 "data": {
683 "text/plain": [
684 "['ancestor',\n",
685 " 'baritone',\n",
686 " 'bemusing',\n",
687 " 'blonds',\n",
688 " 'conciseness',\n",
689 " 'consequent',\n",
690 " 'cuddle',\n",
691 " 'dashboards',\n",
692 " 'despairing',\n",
693 " 'dint',\n",
694 " 'employer',\n",
695 " 'freakish',\n",
696 " 'gall',\n",
697 " 'hopelessness',\n",
698 " 'impales',\n",
699 " 'infix',\n",
700 " 'inflow',\n",
701 " 'innumerable',\n",
702 " 'intentional',\n",
703 " 'jerkin',\n",
704 " 'justification',\n",
705 " 'leaving',\n",
706 " 'locoweeds',\n",
707 " 'monickers',\n",
708 " 'originality',\n",
709 " 'outings',\n",
710 " 'pendulous',\n",
711 " 'pithier',\n",
712 " 'randomness',\n",
713 " 'rectors',\n",
714 " 'redrew',\n",
715 " 'reformulated',\n",
716 " 'remoteness',\n",
717 " 'rethink',\n",
718 " 'scowls',\n",
719 " 'sequencers',\n",
720 " 'serf',\n",
721 " 'shook',\n",
722 " 'spottiest',\n",
723 " 'stood',\n",
724 " 'surtaxing',\n",
725 " 'wardrobes']"
726 ]
727 },
728 "execution_count": 21,
729 "metadata": {},
730 "output_type": "execute_result"
731 }
732 ],
733 "source": [
734 "unused_words = [w for w in ws if not present(g, w)[0]]\n",
735 "unused_words"
736 ]
737 },
738 {
739 "cell_type": "code",
740 "execution_count": 22,
741 "metadata": {
742 "scrolled": true
743 },
744 "outputs": [
745 {
746 "name": "stdout",
747 "output_type": "stream",
748 "text": [
749 "ancestor Counter({'c': 1, 'a': 1, 't': 1, 's': 1, 'r': 1, 'n': 1, 'e': 1, 'o': 1})\n",
750 "baritone Counter({'a': 1, 'r': 1, 'i': 1, 'b': 1, 't': 1, 'e': 1, 'o': 1, 'n': 1})\n",
751 "bemusing Counter({'g': 1, 'i': 1, 's': 1, 'u': 1, 'b': 1, 'm': 1, 'n': 1, 'e': 1})\n",
752 "blonds Counter({'d': 1, 's': 1, 'b': 1, 'n': 1, 'l': 1, 'o': 1})\n",
753 "conciseness Counter({'s': 3, 'c': 2, 'n': 2, 'e': 2, 'i': 1, 'o': 1})\n",
754 "consequent Counter({'n': 2, 'e': 2, 'c': 1, 't': 1, 's': 1, 'u': 1, 'q': 1, 'o': 1})\n",
755 "cuddle Counter({'d': 2, 'c': 1, 'e': 1, 'l': 1, 'u': 1})\n",
756 "dashboards Counter({'a': 2, 's': 2, 'd': 2, 'r': 1, 'h': 1, 'b': 1, 'o': 1})\n",
757 "*despairing Counter({'i': 2, 'g': 1, 'a': 1, 'r': 1, 's': 1, 'p': 1, 'd': 1, 'e': 1, 'n': 1})\n",
758 "dint Counter({'d': 1, 'i': 1, 't': 1, 'n': 1})\n",
759 "employer Counter({'e': 2, 'r': 1, 'm': 1, 'p': 1, 'l': 1, 'y': 1, 'o': 1})\n",
760 "freakish Counter({'s': 1, 'a': 1, 'i': 1, 'r': 1, 'k': 1, 'h': 1, 'f': 1, 'e': 1})\n",
761 "*gall Counter({'l': 2, 'g': 1, 'a': 1})\n",
762 "hopelessness Counter({'s': 4, 'e': 3, 'h': 1, 'p': 1, 'n': 1, 'l': 1, 'o': 1})\n",
763 "*impales Counter({'s': 1, 'a': 1, 'm': 1, 'p': 1, 'i': 1, 'l': 1, 'e': 1})\n",
764 "infix Counter({'i': 2, 'f': 1, 'n': 1, 'x': 1})\n",
765 "inflow Counter({'i': 1, 'w': 1, 'l': 1, 'n': 1, 'f': 1, 'o': 1})\n",
766 "innumerable Counter({'n': 2, 'e': 2, 'a': 1, 'l': 1, 'r': 1, 'm': 1, 'u': 1, 'b': 1, 'i': 1})\n",
767 "intentional Counter({'n': 3, 't': 2, 'i': 2, 'a': 1, 'l': 1, 'e': 1, 'o': 1})\n",
768 "*jerkin Counter({'r': 1, 'i': 1, 'j': 1, 'n': 1, 'e': 1, 'k': 1})\n",
769 "justification Counter({'i': 3, 't': 2, 'c': 1, 'a': 1, 'j': 1, 's': 1, 'u': 1, 'f': 1, 'o': 1, 'n': 1})\n",
770 "leaving Counter({'g': 1, 'a': 1, 'v': 1, 'i': 1, 'l': 1, 'n': 1, 'e': 1})\n",
771 "locoweeds Counter({'e': 2, 'o': 2, 'c': 1, 's': 1, 'w': 1, 'l': 1, 'd': 1})\n",
772 "monickers Counter({'c': 1, 'r': 1, 'i': 1, 's': 1, 'm': 1, 'n': 1, 'e': 1, 'o': 1, 'k': 1})\n",
773 "originality Counter({'i': 3, 'g': 1, 'a': 1, 'r': 1, 't': 1, 'n': 1, 'l': 1, 'y': 1, 'o': 1})\n",
774 "outings Counter({'g': 1, 'n': 1, 'i': 1, 'u': 1, 's': 1, 't': 1, 'o': 1})\n",
775 "pendulous Counter({'u': 2, 'd': 1, 's': 1, 'p': 1, 'l': 1, 'n': 1, 'e': 1, 'o': 1})\n",
776 "pithier Counter({'i': 2, 'r': 1, 'h': 1, 'p': 1, 't': 1, 'e': 1})\n",
777 "randomness Counter({'s': 2, 'n': 2, 'a': 1, 'r': 1, 'm': 1, 'd': 1, 'e': 1, 'o': 1})\n",
778 "rectors Counter({'r': 2, 'c': 1, 's': 1, 't': 1, 'e': 1, 'o': 1})\n",
779 "redrew Counter({'r': 2, 'e': 2, 'd': 1, 'w': 1})\n",
780 "reformulated Counter({'r': 2, 'e': 2, 'a': 1, 'l': 1, 'm': 1, 'u': 1, 't': 1, 'f': 1, 'd': 1, 'o': 1})\n",
781 "remoteness Counter({'e': 3, 's': 2, 'r': 1, 'm': 1, 't': 1, 'o': 1, 'n': 1})\n",
782 "rethink Counter({'r': 1, 'i': 1, 'h': 1, 'k': 1, 't': 1, 'e': 1, 'n': 1})\n",
783 "scowls Counter({'s': 2, 'c': 1, 'l': 1, 'o': 1, 'w': 1})\n",
784 "sequencers Counter({'e': 3, 's': 2, 'c': 1, 'r': 1, 'u': 1, 'q': 1, 'n': 1})\n",
785 "serf Counter({'e': 1, 'f': 1, 'r': 1, 's': 1})\n",
786 "shook Counter({'o': 2, 'k': 1, 's': 1, 'h': 1})\n",
787 "spottiest Counter({'t': 3, 's': 2, 'i': 1, 'p': 1, 'e': 1, 'o': 1})\n",
788 "stood Counter({'o': 2, 't': 1, 's': 1, 'd': 1})\n",
789 "surtaxing Counter({'g': 1, 'a': 1, 'i': 1, 'r': 1, 's': 1, 'u': 1, 'x': 1, 't': 1, 'n': 1})\n",
790 "wardrobes Counter({'r': 2, 'a': 1, 'b': 1, 's': 1, 'w': 1, 'd': 1, 'e': 1, 'o': 1})\n"
791 ]
792 }
793 ],
794 "source": [
795 "makeable_words = []\n",
796 "for w in unused_words:\n",
797 " unused_word_count = collections.Counter(w)\n",
798 " if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
799 " makeable_words += [w]\n",
800 " print('*', end='')\n",
801 " print(w, unused_word_count)"
802 ]
803 },
804 {
805 "cell_type": "code",
806 "execution_count": 23,
807 "metadata": {},
808 "outputs": [
809 {
810 "data": {
811 "text/plain": [
812 "10"
813 ]
814 },
815 "execution_count": 23,
816 "metadata": {},
817 "output_type": "execute_result"
818 }
819 ],
820 "source": [
821 "max(len(w) for w in makeable_words)"
822 ]
823 },
824 {
825 "cell_type": "code",
826 "execution_count": 24,
827 "metadata": {},
828 "outputs": [
829 {
830 "data": {
831 "text/plain": [
832 "'despairing'"
833 ]
834 },
835 "execution_count": 24,
836 "metadata": {},
837 "output_type": "execute_result"
838 }
839 ],
840 "source": [
841 "sorted(makeable_words, key=len)[-1]"
842 ]
843 },
844 {
845 "cell_type": "code",
846 "execution_count": 25,
847 "metadata": {},
848 "outputs": [],
849 "source": [
850 "def do_wordsearch_tasks(fn, show_anyway=False):\n",
851 " width, height, grid, words = read_wordsearch(fn)\n",
852 " used_words = [w for w in words if present(grid, w)[0]]\n",
853 " unused_words = [w for w in words if not present(grid, w)[0]]\n",
854 " lwp = sorted([w for w in words if present(grid, w)[0]], key=len)[-1]\n",
855 " lwps = [w for w in used_words if len(w) == len(lwp)]\n",
856 " lwa = sorted(unused_words, key=len)[-1]\n",
857 " lwas = [w for w in unused_words if len(w) == len(lwa)]\n",
858 " g0 = empty_grid(width, height)\n",
859 " for w in words:\n",
860 " p, r, c, d = present(grid, w)\n",
861 " if p:\n",
862 " set_grid(g0, r, c, d, w) \n",
863 " 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",
864 " if u == '.']\n",
865 " unused_letter_count = collections.Counter(unused_letters)\n",
866 " makeable_words = []\n",
867 " for w in unused_words:\n",
868 " unused_word_count = collections.Counter(w)\n",
869 " if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
870 " makeable_words += [w]\n",
871 " lwm = sorted(makeable_words, key=len)[-1]\n",
872 " lwms = [w for w in makeable_words if len(w) == len(lwm)]\n",
873 " if show_anyway or len(set((len(lwp),len(lwa),len(lwm)))) == 3:\n",
874 " print('\\n{}'.format(fn))\n",
875 " print('{} words present'.format(len(words) - len(unused_words)))\n",
876 " print('Longest word present: {}, {} letters ({})'.format(lwp, len(lwp), lwps))\n",
877 " print('Longest word absent: {}, {} letters ({})'.format(lwa, len(lwa), lwas))\n",
878 " print('{} unused letters'.format(len([c for c in cat(cat(l) for l in g0) if c == '.'])))\n",
879 " print('Longest makeable word: {}, {} ({})'.format(lwm, len(lwm), lwms))"
880 ]
881 },
882 {
883 "cell_type": "code",
884 "execution_count": 26,
885 "metadata": {},
886 "outputs": [
887 {
888 "name": "stdout",
889 "output_type": "stream",
890 "text": [
891 "\n",
892 "wordsearch04.txt\n",
893 "58 words present\n",
894 "Longest word present: fortification, 13 letters (['fortification'])\n",
895 "Longest word absent: justification, 13 letters (['justification'])\n",
896 "57 unused letters\n",
897 "Longest makeable word: despairing, 10 (['despairing'])\n"
898 ]
899 }
900 ],
901 "source": [
902 "do_wordsearch_tasks('wordsearch04.txt', show_anyway=True)"
903 ]
904 },
905 {
906 "cell_type": "code",
907 "execution_count": 27,
908 "metadata": {},
909 "outputs": [
910 {
911 "name": "stdout",
912 "output_type": "stream",
913 "text": [
914 "\n",
915 "wordsearch08.txt\n",
916 "62 words present\n",
917 "Longest word present: compassionately, 15 letters (['compassionately'])\n",
918 "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
919 "65 unused letters\n",
920 "Longest makeable word: vacationing, 11 (['vacationing'])\n"
921 ]
922 }
923 ],
924 "source": [
925 "do_wordsearch_tasks('wordsearch08.txt')"
926 ]
927 },
928 {
929 "cell_type": "code",
930 "execution_count": 28,
931 "metadata": {
932 "scrolled": true
933 },
934 "outputs": [
935 {
936 "name": "stdout",
937 "output_type": "stream",
938 "text": [
939 "\n",
940 "wordsearch08.txt\n",
941 "62 words present\n",
942 "Longest word present: compassionately, 15 letters (['compassionately'])\n",
943 "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
944 "65 unused letters\n",
945 "Longest makeable word: vacationing, 11 (['vacationing'])\n",
946 "\n",
947 "wordsearch17.txt\n",
948 "58 words present\n",
949 "Longest word present: complementing, 13 letters (['complementing'])\n",
950 "Longest word absent: upholstering, 12 letters (['domestically', 'upholstering'])\n",
951 "56 unused letters\n",
952 "Longest makeable word: plunderer, 9 (['plunderer'])\n",
953 "\n",
954 "wordsearch32.txt\n",
955 "60 words present\n",
956 "Longest word present: reciprocating, 13 letters (['reciprocating'])\n",
957 "Longest word absent: parenthesise, 12 letters (['collectibles', 'frontrunners', 'parenthesise'])\n",
958 "65 unused letters\n",
959 "Longest makeable word: sultanas, 8 (['sultanas'])\n",
960 "\n",
961 "wordsearch52.txt\n",
962 "51 words present\n",
963 "Longest word present: prefabricated, 13 letters (['prefabricated'])\n",
964 "Longest word absent: catastrophic, 12 letters (['capitalistic', 'catastrophic'])\n",
965 "86 unused letters\n",
966 "Longest makeable word: unimpressed, 11 (['bloodstream', 'brainstorms', 'reassembles', 'rhapsodises', 'synergistic', 'unimpressed'])\n",
967 "\n",
968 "wordsearch62.txt\n",
969 "58 words present\n",
970 "Longest word present: diametrically, 13 letters (['diametrically'])\n",
971 "Longest word absent: streetlights, 12 letters (['harmonically', 'skyrocketing', 'streetlights'])\n",
972 "59 unused letters\n",
973 "Longest makeable word: tabernacle, 10 (['falterings', 'tabernacle'])\n",
974 "\n",
975 "wordsearch76.txt\n",
976 "60 words present\n",
977 "Longest word present: bloodthirstier, 14 letters (['bloodthirstier'])\n",
978 "Longest word absent: incriminating, 13 letters (['incriminating'])\n",
979 "59 unused letters\n",
980 "Longest makeable word: stubbornly, 10 (['leafletted', 'stubbornly'])\n",
981 "\n",
982 "wordsearch94.txt\n",
983 "59 words present\n",
984 "Longest word present: unforgettable, 13 letters (['unforgettable'])\n",
985 "Longest word absent: accommodated, 12 letters (['accommodated'])\n",
986 "69 unused letters\n",
987 "Longest makeable word: respectably, 11 (['predictions', 'respectably'])\n"
988 ]
989 }
990 ],
991 "source": [
992 "for fn in sorted(os.listdir()):\n",
993 " if re.match('wordsearch\\d\\d\\.txt', fn):\n",
994 " do_wordsearch_tasks(fn)"
995 ]
996 },
997 {
998 "cell_type": "code",
999 "execution_count": 29,
1000 "metadata": {
1001 "scrolled": true
1002 },
1003 "outputs": [
1004 {
1005 "name": "stdout",
1006 "output_type": "stream",
1007 "text": [
1008 "absolved (True, 16, 2, <Direction.right: 2>)\n",
1009 "adorable (True, 11, 4, <Direction.right: 2>)\n",
1010 "aeon (True, 11, 4, <Direction.down: 4>)\n",
1011 "alias (True, 15, 15, <Direction.left: 1>)\n",
1012 "ancestor (False, 0, 0, <Direction.left: 1>)\n",
1013 "baritone (False, 0, 0, <Direction.left: 1>)\n",
1014 "bemusing (False, 0, 0, <Direction.left: 1>)\n",
1015 "blonds (False, 0, 0, <Direction.left: 1>)\n",
1016 "bran (True, 1, 9, <Direction.left: 1>)\n",
1017 "calcite (True, 19, 9, <Direction.upright: 6>)\n",
1018 "candor (True, 17, 12, <Direction.right: 2>)\n",
1019 "conciseness (False, 0, 0, <Direction.left: 1>)\n",
1020 "consequent (False, 0, 0, <Direction.left: 1>)\n",
1021 "cuddle (False, 0, 0, <Direction.left: 1>)\n",
1022 "damming (True, 17, 2, <Direction.right: 2>)\n",
1023 "dashboards (False, 0, 0, <Direction.left: 1>)\n",
1024 "despairing (False, 0, 0, <Direction.left: 1>)\n",
1025 "dint (False, 0, 0, <Direction.left: 1>)\n",
1026 "dullard (True, 8, 2, <Direction.down: 4>)\n",
1027 "dynasty (True, 3, 4, <Direction.downright: 8>)\n",
1028 "employer (False, 0, 0, <Direction.left: 1>)\n",
1029 "exhorts (True, 0, 8, <Direction.left: 1>)\n",
1030 "feted (True, 5, 10, <Direction.right: 2>)\n",
1031 "fill (True, 9, 14, <Direction.upleft: 5>)\n",
1032 "flattens (True, 10, 10, <Direction.upleft: 5>)\n",
1033 "foghorn (True, 10, 11, <Direction.downright: 8>)\n",
1034 "fortification (True, 19, 16, <Direction.left: 1>)\n",
1035 "freakish (False, 0, 0, <Direction.left: 1>)\n",
1036 "frolics (True, 16, 16, <Direction.up: 3>)\n",
1037 "gall (False, 0, 0, <Direction.left: 1>)\n",
1038 "gees (True, 17, 0, <Direction.upright: 6>)\n",
1039 "genies (True, 5, 7, <Direction.upleft: 5>)\n",
1040 "gets (True, 6, 4, <Direction.upleft: 5>)\n",
1041 "hastening (True, 14, 13, <Direction.left: 1>)\n",
1042 "hits (True, 2, 0, <Direction.down: 4>)\n",
1043 "hopelessness (False, 0, 0, <Direction.left: 1>)\n",
1044 "hurlers (True, 18, 0, <Direction.right: 2>)\n",
1045 "impales (False, 0, 0, <Direction.left: 1>)\n",
1046 "infix (False, 0, 0, <Direction.left: 1>)\n",
1047 "inflow (False, 0, 0, <Direction.left: 1>)\n",
1048 "innumerable (False, 0, 0, <Direction.left: 1>)\n",
1049 "intentional (False, 0, 0, <Direction.left: 1>)\n",
1050 "jerkin (False, 0, 0, <Direction.left: 1>)\n",
1051 "justification (False, 0, 0, <Direction.left: 1>)\n",
1052 "kitty (True, 8, 15, <Direction.upleft: 5>)\n",
1053 "knuckles (True, 17, 19, <Direction.up: 3>)\n",
1054 "leaving (False, 0, 0, <Direction.left: 1>)\n",
1055 "like (True, 3, 11, <Direction.left: 1>)\n",
1056 "limitation (True, 8, 3, <Direction.right: 2>)\n",
1057 "locoweeds (False, 0, 0, <Direction.left: 1>)\n",
1058 "loot (True, 3, 19, <Direction.up: 3>)\n",
1059 "lucking (True, 7, 10, <Direction.upleft: 5>)\n",
1060 "lumps (True, 0, 17, <Direction.down: 4>)\n",
1061 "mercerising (True, 15, 17, <Direction.up: 3>)\n",
1062 "monickers (False, 0, 0, <Direction.left: 1>)\n",
1063 "motionless (True, 13, 1, <Direction.up: 3>)\n",
1064 "naturally (True, 9, 16, <Direction.up: 3>)\n",
1065 "nighest (True, 15, 4, <Direction.right: 2>)\n",
1066 "notion (True, 17, 18, <Direction.up: 3>)\n",
1067 "ogled (True, 1, 18, <Direction.down: 4>)\n",
1068 "originality (False, 0, 0, <Direction.left: 1>)\n",
1069 "outings (False, 0, 0, <Direction.left: 1>)\n",
1070 "pendulous (False, 0, 0, <Direction.left: 1>)\n",
1071 "piled (True, 1, 10, <Direction.right: 2>)\n",
1072 "pins (True, 7, 4, <Direction.upleft: 5>)\n",
1073 "pithier (False, 0, 0, <Direction.left: 1>)\n",
1074 "prep (True, 10, 4, <Direction.right: 2>)\n",
1075 "randomness (False, 0, 0, <Direction.left: 1>)\n",
1076 "rectors (False, 0, 0, <Direction.left: 1>)\n",
1077 "redrew (False, 0, 0, <Direction.left: 1>)\n",
1078 "reformulated (False, 0, 0, <Direction.left: 1>)\n",
1079 "remoteness (False, 0, 0, <Direction.left: 1>)\n",
1080 "retaking (True, 6, 0, <Direction.down: 4>)\n",
1081 "rethink (False, 0, 0, <Direction.left: 1>)\n",
1082 "rope (True, 9, 4, <Direction.right: 2>)\n",
1083 "rubier (True, 0, 4, <Direction.downright: 8>)\n",
1084 "sailors (True, 7, 15, <Direction.up: 3>)\n",
1085 "scowls (False, 0, 0, <Direction.left: 1>)\n",
1086 "scum (True, 16, 11, <Direction.right: 2>)\n",
1087 "sepals (True, 6, 10, <Direction.upright: 6>)\n",
1088 "sequencers (False, 0, 0, <Direction.left: 1>)\n",
1089 "serf (False, 0, 0, <Direction.left: 1>)\n",
1090 "shoaled (True, 11, 18, <Direction.up: 3>)\n",
1091 "shook (False, 0, 0, <Direction.left: 1>)\n",
1092 "sonic (True, 18, 18, <Direction.left: 1>)\n",
1093 "spottiest (False, 0, 0, <Direction.left: 1>)\n",
1094 "stag (True, 7, 8, <Direction.left: 1>)\n",
1095 "stood (False, 0, 0, <Direction.left: 1>)\n",
1096 "stratum (True, 2, 13, <Direction.left: 1>)\n",
1097 "strong (True, 4, 19, <Direction.down: 4>)\n",
1098 "studying (True, 0, 16, <Direction.left: 1>)\n",
1099 "surtaxing (False, 0, 0, <Direction.left: 1>)\n",
1100 "tailing (True, 13, 6, <Direction.right: 2>)\n",
1101 "tears (True, 13, 3, <Direction.up: 3>)\n",
1102 "teazles (True, 4, 10, <Direction.downright: 8>)\n",
1103 "vans (True, 18, 8, <Direction.upright: 6>)\n",
1104 "wardrobes (False, 0, 0, <Direction.left: 1>)\n",
1105 "wooded (True, 12, 5, <Direction.right: 2>)\n",
1106 "worsts (True, 1, 0, <Direction.downright: 8>)\n",
1107 "zings (True, 10, 14, <Direction.upleft: 5>)\n"
1108 ]
1109 }
1110 ],
1111 "source": [
1112 "width, height, grid, words = read_wordsearch('wordsearch04.txt')\n",
1113 "for w in words:\n",
1114 " print(w, present(grid, w))"
1115 ]
1116 },
1117 {
1118 "cell_type": "markdown",
1119 "metadata": {},
1120 "source": [
1121 "## Example for question text"
1122 ]
1123 },
1124 {
1125 "cell_type": "code",
1126 "execution_count": 59,
1127 "metadata": {
1128 "collapsed": true
1129 },
1130 "outputs": [],
1131 "source": [
1132 "import copy\n",
1133 "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",
1134 "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",
1135 "present_words = ['probed', 'staple', 'rioted', 'cowhides', 'tops', 'knows', 'lived', 'rhubarb', 'crazies', 'dock', 'apace', 'mown', 'pears', 'wide']\n",
1136 "decoy_words = ['fickler', 'adapting', 'chump', 'foaming', 'molested', 'carnal', 'crumbled', 'guts', 'minuend', 'bombing', 'winced', 'coccyxes', 'solaria', 'shinier', 'cackles']"
1137 ]
1138 },
1139 {
1140 "cell_type": "code",
1141 "execution_count": 41,
1142 "metadata": {},
1143 "outputs": [
1144 {
1145 "name": "stdout",
1146 "output_type": "stream",
1147 "text": [
1148 "probed 3 0 6 Direction.down [(3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0)]\n",
1149 "staple 9 1 6 Direction.right [(9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)]\n",
1150 "rioted 6 7 6 Direction.upleft [(6, 7), (5, 6), (4, 5), (3, 4), (2, 3), (1, 2)]\n",
1151 "cowhides 8 3 8 Direction.up [(8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3)]\n",
1152 "tops 7 4 4 Direction.right [(7, 4), (7, 5), (7, 6), (7, 7)]\n",
1153 "knows 8 2 5 Direction.up [(8, 2), (7, 2), (6, 2), (5, 2), (4, 2)]\n",
1154 "lived 2 4 5 Direction.downright [(2, 4), (3, 5), (4, 6), (5, 7), (6, 8)]\n",
1155 "rhubarb 2 9 7 Direction.down [(2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9)]\n",
1156 "crazies 7 1 7 Direction.up [(7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)]\n",
1157 "dock 8 5 4 Direction.up [(8, 5), (7, 5), (6, 5), (5, 5)]\n",
1158 "apace 5 8 5 Direction.up [(5, 8), (4, 8), (3, 8), (2, 8), (1, 8)]\n",
1159 "mown 0 5 4 Direction.right [(0, 5), (0, 6), (0, 7), (0, 8)]\n",
1160 "pears 0 3 5 Direction.downright [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]\n",
1161 "wide 4 4 4 Direction.upright [(4, 4), (3, 5), (2, 6), (1, 7)]\n"
1162 ]
1163 },
1164 {
1165 "data": {
1166 "text/plain": [
1167 "[(7, 5), (2, 3), (3, 5)]"
1168 ]
1169 },
1170 "execution_count": 41,
1171 "metadata": {},
1172 "output_type": "execute_result"
1173 }
1174 ],
1175 "source": [
1176 "cts = collections.Counter()\n",
1177 "for w in present_words:\n",
1178 " _, r, c, d = present(grid, w)\n",
1179 " inds = indices(grid, r, c, len(w), d)\n",
1180 " for i in inds:\n",
1181 " cts[i] += 1\n",
1182 " print(w, r, c, len(w), d, inds)\n",
1183 "[i for i in cts if cts[i] > 1]"
1184 ]
1185 },
1186 {
1187 "cell_type": "code",
1188 "execution_count": 42,
1189 "metadata": {},
1190 "outputs": [
1191 {
1192 "name": "stdout",
1193 "output_type": "stream",
1194 "text": [
1195 "\n",
1196 "example-wordsearch.txt\n",
1197 "14 words present\n",
1198 "Longest word present: cowhides, 8 letters (['cowhides'])\n",
1199 "Longest word absent: molested, 8 letters (['adapting', 'coccyxes', 'crumbled', 'molested'])\n",
1200 "27 unused letters\n",
1201 "Longest makeable word: shinier, 7 (['shinier'])\n"
1202 ]
1203 }
1204 ],
1205 "source": [
1206 "do_wordsearch_tasks('example-wordsearch.txt', show_anyway=True)"
1207 ]
1208 },
1209 {
1210 "cell_type": "code",
1211 "execution_count": 45,
1212 "metadata": {},
1213 "outputs": [
1214 {
1215 "name": "stdout",
1216 "output_type": "stream",
1217 "text": [
1218 "..........\n",
1219 "..........\n",
1220 "....l.....\n",
1221 ".....i....\n",
1222 "......v...\n",
1223 ".......e..\n",
1224 "........d.\n",
1225 "..........\n",
1226 "..........\n",
1227 "..........\n"
1228 ]
1229 }
1230 ],
1231 "source": [
1232 "g = empty_grid(10, 10)\n",
1233 "set_grid(g, 2, 4, Direction.downright, 'lived')\n",
1234 "print(show_grid(g))"
1235 ]
1236 },
1237 {
1238 "cell_type": "code",
1239 "execution_count": 63,
1240 "metadata": {},
1241 "outputs": [
1242 {
1243 "name": "stdout",
1244 "output_type": "stream",
1245 "text": [
1246 "..........\n",
1247 ".......e..\n",
1248 "....l.d...\n",
1249 ".....i....\n",
1250 "....w.v...\n",
1251 ".......e..\n",
1252 "........d.\n",
1253 "..........\n",
1254 "..........\n",
1255 ".staple...\n"
1256 ]
1257 }
1258 ],
1259 "source": [
1260 "g = empty_grid(10, 10)\n",
1261 "set_grid(g, 2, 4, Direction.downright, 'lived')\n",
1262 "set_grid(g, 4, 4, Direction.upright, 'wide')\n",
1263 "set_grid(g, 9, 1, Direction.right, 'staple')\n",
1264 "print(show_grid(g))"
1265 ]
1266 },
1267 {
1268 "cell_type": "code",
1269 "execution_count": 54,
1270 "metadata": {},
1271 "outputs": [
1272 {
1273 "name": "stdout",
1274 "output_type": "stream",
1275 "text": [
1276 "..........\n",
1277 "...s......\n",
1278 "...e......\n",
1279 "...d......\n",
1280 "...i......\n",
1281 "...h......\n",
1282 "...w......\n",
1283 "...o......\n",
1284 "...c......\n",
1285 "..........\n"
1286 ]
1287 }
1288 ],
1289 "source": [
1290 "g = empty_grid(10, 10)\n",
1291 "set_grid(g, 8, 3, Direction.up, 'cowhides')\n",
1292 "print(show_grid(g))"
1293 ]
1294 },
1295 {
1296 "cell_type": "code",
1297 "execution_count": 64,
1298 "metadata": {},
1299 "outputs": [
1300 {
1301 "name": "stdout",
1302 "output_type": "stream",
1303 "text": [
1304 "..........\n",
1305 "..........\n",
1306 "..........\n",
1307 "..........\n",
1308 "..........\n",
1309 "..........\n",
1310 "brow......\n",
1311 "..........\n",
1312 "..........\n",
1313 "..........\n"
1314 ]
1315 }
1316 ],
1317 "source": [
1318 "# Example of word in grid that is English but isn't in the words listed in the puzzle.\n",
1319 "g = empty_grid(10, 10)\n",
1320 "set_grid(g, 6, 0, Direction.right, 'brow')\n",
1321 "print(show_grid(g))"
1322 ]
1323 },
1324 {
1325 "cell_type": "code",
1326 "execution_count": 65,
1327 "metadata": {},
1328 "outputs": [
1329 {
1330 "name": "stdout",
1331 "output_type": "stream",
1332 "text": [
1333 "fhj.a....q\n",
1334 "w....uq..v\n",
1335 "i.a....h..\n",
1336 "..e....i..\n",
1337 "..........\n",
1338 "....a.....\n",
1339 "....p.f...\n",
1340 "........s.\n",
1341 ".i..h.npn.\n",
1342 "b......okr\n"
1343 ]
1344 }
1345 ],
1346 "source": [
1347 "unused_grid = copy.deepcopy(padded_grid)\n",
1348 "for w in present_words:\n",
1349 " _, r, c, d = present(grid, w)\n",
1350 " set_grid(unused_grid, r, c, d, '.' * len(w))\n",
1351 "print(show_grid(unused_grid))"
1352 ]
1353 },
1354 {
1355 "cell_type": "code",
1356 "execution_count": null,
1357 "metadata": {
1358 "collapsed": true
1359 },
1360 "outputs": [],
1361 "source": []
1362 }
1363 ],
1364 "metadata": {
1365 "kernelspec": {
1366 "display_name": "Python 3",
1367 "language": "python",
1368 "name": "python3"
1369 },
1370 "language_info": {
1371 "codemirror_mode": {
1372 "name": "ipython",
1373 "version": 3
1374 },
1375 "file_extension": ".py",
1376 "mimetype": "text/x-python",
1377 "name": "python",
1378 "nbconvert_exporter": "python",
1379 "pygments_lexer": "ipython3",
1380 "version": "3.5.2+"
1381 }
1382 },
1383 "nbformat": 4,
1384 "nbformat_minor": 1
1385 }