Updated question text
[ou-summer-of-code-2017.git] / 04-word-search / wordsearch-creation.ipynb
1 {
2 "cells": [
3 {
4 "cell_type": "code",
5 "execution_count": 1,
6 "metadata": {},
7 "outputs": [],
8 "source": [
9 "import string\n",
10 "import re\n",
11 "import random\n",
12 "import collections\n",
13 "import copy\n",
14 "\n",
15 "from enum import Enum\n",
16 "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
17 " \n",
18 "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
19 " Direction.up: (-1, 0), Direction.down: (1, 0), \n",
20 " Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
21 " Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
22 "\n",
23 "cat = ''.join\n",
24 "wcat = ' '.join\n",
25 "lcat = '\\n'.join"
26 ]
27 },
28 {
29 "cell_type": "code",
30 "execution_count": 2,
31 "metadata": {},
32 "outputs": [],
33 "source": [
34 "# all_words = [w.strip() for w in open('/usr/share/dict/british-english').readlines()\n",
35 "# if all(c in string.ascii_lowercase for c in w.strip())]\n",
36 "# words = [w for w in all_words\n",
37 "# if not any(w in w2 for w2 in all_words if w != w2)]\n",
38 "# open('wordsearch-words', 'w').write(lcat(words))"
39 ]
40 },
41 {
42 "cell_type": "code",
43 "execution_count": 3,
44 "metadata": {},
45 "outputs": [],
46 "source": [
47 "# ws_words = [w.strip() for w in open('wordsearch-words').readlines()\n",
48 "# if all(c in string.ascii_lowercase for c in w.strip())]\n",
49 "# ws_words[:10]"
50 ]
51 },
52 {
53 "cell_type": "code",
54 "execution_count": 4,
55 "metadata": {
56 "collapsed": true
57 },
58 "outputs": [],
59 "source": [
60 "ws_words = [w.strip() for w in open('/usr/share/dict/british-english').readlines()\n",
61 " if all(c in string.ascii_lowercase for c in w.strip())]"
62 ]
63 },
64 {
65 "cell_type": "code",
66 "execution_count": 5,
67 "metadata": {
68 "collapsed": true
69 },
70 "outputs": [],
71 "source": [
72 "def empty_grid(w, h):\n",
73 " return [['.' for c in range(w)] for r in range(h)]"
74 ]
75 },
76 {
77 "cell_type": "code",
78 "execution_count": 6,
79 "metadata": {
80 "collapsed": true
81 },
82 "outputs": [],
83 "source": [
84 "def show_grid(grid):\n",
85 " return lcat(cat(r) for r in grid)"
86 ]
87 },
88 {
89 "cell_type": "code",
90 "execution_count": 7,
91 "metadata": {},
92 "outputs": [
93 {
94 "name": "stdout",
95 "output_type": "stream",
96 "text": [
97 "..........\n",
98 "..........\n",
99 "..........\n",
100 "..........\n",
101 "..........\n",
102 "..........\n",
103 "..........\n",
104 "..........\n",
105 "..........\n",
106 "..........\n"
107 ]
108 }
109 ],
110 "source": [
111 "grid = empty_grid(10, 10)\n",
112 "print(show_grid(grid))"
113 ]
114 },
115 {
116 "cell_type": "code",
117 "execution_count": 8,
118 "metadata": {
119 "collapsed": true
120 },
121 "outputs": [],
122 "source": [
123 "def indices(grid, r, c, l, d):\n",
124 " dr, dc = delta[d]\n",
125 " w = len(grid[0])\n",
126 " h = len(grid)\n",
127 " inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
128 " return [(i, j) for i, j in inds\n",
129 " if i >= 0\n",
130 " if j >= 0\n",
131 " if i < h\n",
132 " if j < w]"
133 ]
134 },
135 {
136 "cell_type": "code",
137 "execution_count": 9,
138 "metadata": {
139 "collapsed": true
140 },
141 "outputs": [],
142 "source": [
143 "def gslice(grid, r, c, l, d):\n",
144 " return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
145 ]
146 },
147 {
148 "cell_type": "code",
149 "execution_count": 10,
150 "metadata": {
151 "collapsed": true
152 },
153 "outputs": [],
154 "source": [
155 "def set_grid(grid, r, c, d, word):\n",
156 " for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
157 " grid[i][j] = l\n",
158 " return grid"
159 ]
160 },
161 {
162 "cell_type": "code",
163 "execution_count": 11,
164 "metadata": {},
165 "outputs": [
166 {
167 "name": "stdout",
168 "output_type": "stream",
169 "text": [
170 "..........\n",
171 "..........\n",
172 "...t......\n",
173 "....e.....\n",
174 ".....s....\n",
175 "......t...\n",
176 ".......w..\n",
177 "........o.\n",
178 ".........r\n",
179 "..........\n"
180 ]
181 }
182 ],
183 "source": [
184 "set_grid(grid, 2, 3, Direction.downright, 'testword')\n",
185 "print(show_grid(grid))"
186 ]
187 },
188 {
189 "cell_type": "code",
190 "execution_count": 12,
191 "metadata": {},
192 "outputs": [
193 {
194 "data": {
195 "text/plain": [
196 "'..e.....'"
197 ]
198 },
199 "execution_count": 12,
200 "metadata": {},
201 "output_type": "execute_result"
202 }
203 ],
204 "source": [
205 "cat(gslice(grid, 3, 2, 15, Direction.right))"
206 ]
207 },
208 {
209 "cell_type": "code",
210 "execution_count": 13,
211 "metadata": {},
212 "outputs": [
213 {
214 "data": {
215 "text/plain": [
216 "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
217 ]
218 },
219 "execution_count": 13,
220 "metadata": {},
221 "output_type": "execute_result"
222 }
223 ],
224 "source": [
225 "re.match(cat(gslice(grid, 3, 2, 4, Direction.right)), 'keen')"
226 ]
227 },
228 {
229 "cell_type": "code",
230 "execution_count": 14,
231 "metadata": {},
232 "outputs": [
233 {
234 "data": {
235 "text/plain": [
236 "<_sre.SRE_Match object; span=(0, 3), match='kee'>"
237 ]
238 },
239 "execution_count": 14,
240 "metadata": {},
241 "output_type": "execute_result"
242 }
243 ],
244 "source": [
245 "re.match(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
246 ]
247 },
248 {
249 "cell_type": "code",
250 "execution_count": 15,
251 "metadata": {},
252 "outputs": [],
253 "source": [
254 "re.fullmatch(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
255 ]
256 },
257 {
258 "cell_type": "code",
259 "execution_count": 16,
260 "metadata": {
261 "collapsed": true
262 },
263 "outputs": [],
264 "source": [
265 "re.match(cat(gslice(grid, 3, 2, 4, Direction.right)), 'kine')"
266 ]
267 },
268 {
269 "cell_type": "code",
270 "execution_count": 17,
271 "metadata": {
272 "collapsed": true
273 },
274 "outputs": [],
275 "source": [
276 "def could_add(grid, r, c, d, word):\n",
277 " s = gslice(grid, r, c, len(word), d)\n",
278 " return re.fullmatch(cat(s), word)"
279 ]
280 },
281 {
282 "cell_type": "code",
283 "execution_count": 18,
284 "metadata": {},
285 "outputs": [
286 {
287 "data": {
288 "text/plain": [
289 "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
290 ]
291 },
292 "execution_count": 18,
293 "metadata": {},
294 "output_type": "execute_result"
295 }
296 ],
297 "source": [
298 "could_add(grid, 3, 2, Direction.right, 'keen')"
299 ]
300 },
301 {
302 "cell_type": "code",
303 "execution_count": 19,
304 "metadata": {},
305 "outputs": [],
306 "source": [
307 "could_add(grid, 3, 2, Direction.right, 'kine')"
308 ]
309 },
310 {
311 "cell_type": "code",
312 "execution_count": 20,
313 "metadata": {},
314 "outputs": [
315 {
316 "data": {
317 "text/plain": [
318 "<Direction.right: 2>"
319 ]
320 },
321 "execution_count": 20,
322 "metadata": {},
323 "output_type": "execute_result"
324 }
325 ],
326 "source": [
327 "random.choice(list(Direction))"
328 ]
329 },
330 {
331 "cell_type": "code",
332 "execution_count": 58,
333 "metadata": {
334 "collapsed": true
335 },
336 "outputs": [],
337 "source": [
338 "def fill_grid(grid, words, word_count, max_attempts=10000):\n",
339 " attempts = 0\n",
340 " added_words = []\n",
341 " w = len(grid[0])\n",
342 " h = len(grid)\n",
343 " while len(added_words) < word_count and attempts < max_attempts:\n",
344 " attempts += 1\n",
345 " r = random.randrange(w)\n",
346 " c = random.randrange(h)\n",
347 " word = random.choice(words)\n",
348 " d = random.choice(list(Direction))\n",
349 " if len(word) >=4 and not any(word in w2 for w2 in added_words) and could_add(grid, r, c, d, word):\n",
350 " set_grid(grid, r, c, d, word)\n",
351 " added_words += [word]\n",
352 " attempts = 0\n",
353 " return grid, added_words"
354 ]
355 },
356 {
357 "cell_type": "code",
358 "execution_count": 22,
359 "metadata": {},
360 "outputs": [
361 {
362 "data": {
363 "text/plain": [
364 "40"
365 ]
366 },
367 "execution_count": 22,
368 "metadata": {},
369 "output_type": "execute_result"
370 }
371 ],
372 "source": [
373 "g = empty_grid(20, 20)\n",
374 "g, ws = fill_grid(g, ws_words, 40)\n",
375 "len(ws)"
376 ]
377 },
378 {
379 "cell_type": "code",
380 "execution_count": 23,
381 "metadata": {},
382 "outputs": [
383 {
384 "name": "stdout",
385 "output_type": "stream",
386 "text": [
387 "..pouchexecrate.....\n",
388 ".hazardous....t.wive\n",
389 "...sniradnam.aselcnu\n",
390 "s.weeklies.rnb......\n",
391 "e..lamenessse.o.....\n",
392 "i.tsallab..s.a.i....\n",
393 "tslim.......f.c.l...\n",
394 "iwheelbase...f.tges.\n",
395 "ed....llabhgihinirr.\n",
396 "dw.limbs..nj.bitev.s\n",
397 "te.wiltediu.ructs.e.\n",
398 "elsombretv.oqes..a..\n",
399 "ll..e..te.iela....m.\n",
400 "ie.a..un.lheleiretoc\n",
401 "ord..bi.scsp...kiths\n",
402 "ts.malcentilitren...\n",
403 "..i.e.sexetrov.stolb\n",
404 ".r.s...ruof....htrof\n",
405 "bgnihsirevopmi.....c\n",
406 "....graciousness....\n",
407 "40 words added\n",
408 "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"
409 ]
410 }
411 ],
412 "source": [
413 "print(show_grid(g))\n",
414 "print(len(ws), 'words added')\n",
415 "print(wcat(ws))"
416 ]
417 },
418 {
419 "cell_type": "code",
420 "execution_count": 24,
421 "metadata": {
422 "collapsed": true
423 },
424 "outputs": [],
425 "source": [
426 "def present(grid, word):\n",
427 " w = len(grid[0])\n",
428 " h = len(grid)\n",
429 " for r in range(h):\n",
430 " for c in range(w):\n",
431 " for d in Direction:\n",
432 " if cat(gslice(grid, r, c, len(word), d)) == word:\n",
433 " return True, r, c, d\n",
434 " return False, 0, 0, list(Direction)[0]"
435 ]
436 },
437 {
438 "cell_type": "code",
439 "execution_count": 25,
440 "metadata": {
441 "scrolled": true
442 },
443 "outputs": [
444 {
445 "name": "stdout",
446 "output_type": "stream",
447 "text": [
448 "lameness (True, 4, 3, <Direction.right: 2>)\n",
449 "impoverishing (True, 18, 13, <Direction.left: 1>)\n",
450 "plasters (True, 14, 11, <Direction.upright: 6>)\n",
451 "wilted (True, 10, 3, <Direction.right: 2>)\n",
452 "toilet (True, 15, 0, <Direction.up: 3>)\n",
453 "forth (True, 17, 19, <Direction.left: 1>)\n",
454 "coterie (True, 13, 19, <Direction.left: 1>)\n",
455 "hazardous (True, 1, 1, <Direction.right: 2>)\n",
456 "abutting (True, 15, 4, <Direction.upright: 6>)\n",
457 "chequing (True, 14, 9, <Direction.upright: 6>)\n",
458 "weeklies (True, 3, 2, <Direction.right: 2>)\n",
459 "sombre (True, 11, 2, <Direction.right: 2>)\n",
460 "execrate (True, 0, 7, <Direction.right: 2>)\n",
461 "mastiffs (True, 12, 18, <Direction.upleft: 5>)\n",
462 "boilers (True, 3, 13, <Direction.downright: 8>)\n",
463 "uncles (True, 2, 19, <Direction.left: 1>)\n",
464 "centilitre (True, 15, 6, <Direction.right: 2>)\n",
465 "mandarins (True, 2, 11, <Direction.left: 1>)\n",
466 "wheelbase (True, 7, 1, <Direction.right: 2>)\n",
467 "graciousness (True, 19, 4, <Direction.right: 2>)\n",
468 "vortexes (True, 16, 13, <Direction.left: 1>)\n",
469 "dwellers (True, 8, 1, <Direction.down: 4>)\n",
470 "ballast (True, 5, 8, <Direction.left: 1>)\n",
471 "limbs (True, 9, 3, <Direction.right: 2>)\n",
472 "four (True, 17, 10, <Direction.left: 1>)\n",
473 "tans (True, 1, 14, <Direction.downleft: 7>)\n",
474 "highball (True, 8, 13, <Direction.left: 1>)\n",
475 "wive (True, 1, 16, <Direction.right: 2>)\n",
476 "broils (True, 9, 13, <Direction.downleft: 7>)\n",
477 "beads (True, 11, 5, <Direction.downleft: 7>)\n",
478 "mils (True, 6, 4, <Direction.left: 1>)\n",
479 "reactive (True, 3, 11, <Direction.downright: 8>)\n",
480 "select (True, 14, 10, <Direction.upright: 6>)\n",
481 "deities (True, 9, 0, <Direction.up: 3>)\n",
482 "shtik (True, 14, 19, <Direction.left: 1>)\n",
483 "juveniles (True, 9, 11, <Direction.downleft: 7>)\n",
484 "blots (True, 16, 19, <Direction.left: 1>)\n",
485 "pouch (True, 0, 2, <Direction.right: 2>)\n",
486 "brim (True, 18, 0, <Direction.upright: 6>)\n",
487 "coon (True, 18, 19, <Direction.upleft: 5>)\n"
488 ]
489 }
490 ],
491 "source": [
492 "for w in ws:\n",
493 " print(w, present(g, w))"
494 ]
495 },
496 {
497 "cell_type": "code",
498 "execution_count": 47,
499 "metadata": {
500 "collapsed": true
501 },
502 "outputs": [],
503 "source": [
504 "def interesting(grid, words, words_limit=40, direction_slack=1):\n",
505 " dirs = set(present(grid, w)[3] for w in words)\n",
506 " return len(words) > words_limit and len(dirs) + direction_slack >= len(delta)"
507 ]
508 },
509 {
510 "cell_type": "code",
511 "execution_count": 48,
512 "metadata": {},
513 "outputs": [
514 {
515 "data": {
516 "text/plain": [
517 "True"
518 ]
519 },
520 "execution_count": 48,
521 "metadata": {},
522 "output_type": "execute_result"
523 }
524 ],
525 "source": [
526 "interesting(g, ws)"
527 ]
528 },
529 {
530 "cell_type": "code",
531 "execution_count": 51,
532 "metadata": {
533 "collapsed": true
534 },
535 "outputs": [],
536 "source": [
537 "def interesting_grid(width=20, height=20, words_limit=40, direction_slack=1):\n",
538 " boring = True\n",
539 " while boring:\n",
540 " grid = empty_grid(width, height)\n",
541 " grid, words = fill_grid(grid, ws_words, 80)\n",
542 " boring = not interesting(grid, words, words_limit=words_limit, direction_slack=direction_slack)\n",
543 " return grid, words"
544 ]
545 },
546 {
547 "cell_type": "code",
548 "execution_count": 52,
549 "metadata": {},
550 "outputs": [
551 {
552 "name": "stdout",
553 "output_type": "stream",
554 "text": [
555 "dexawwt....ybossm..t\n",
556 "snaprhlukulele..o.er\n",
557 "...erioteb.hrevordla\n",
558 "..sivc..pr.tdekcahkp\n",
559 "atve..h.oiselapcy.cd\n",
560 "nesrehpargohtill.pue\n",
561 "n.leaveyis.smuguhhrt\n",
562 "eyhsifnt.r...aeesetc\n",
563 "xverbseebasedlritl.a\n",
564 ".r..k.wie..mdonaiaeg\n",
565 "..ac.nsof.admeeulsoo\n",
566 "g.opo.cmanaotpqiinmp\n",
567 "nc.us.a.lpnteaerdkiu\n",
568 "ionjoys.leirinioicns\n",
569 "wnkcent.skeracllkase\n",
570 "oab..erusopxeao.antt\n",
571 "dureifidimuhed.nskea\n",
572 "aga...capitols..scrl\n",
573 "h.v.sandblaster..i.i\n",
574 "s.e..sdratoelhitsn.d\n",
575 "61 words added; 8 directions\n",
576 "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"
577 ]
578 }
579 ],
580 "source": [
581 "g, ws = interesting_grid()\n",
582 "print(show_grid(g))\n",
583 "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
584 "print(wcat(ws))"
585 ]
586 },
587 {
588 "cell_type": "code",
589 "execution_count": 30,
590 "metadata": {
591 "collapsed": true
592 },
593 "outputs": [],
594 "source": [
595 "def datafile(name, sep='\\t'):\n",
596 " \"\"\"Read key,value pairs from file.\n",
597 " \"\"\"\n",
598 " with open(name) as f:\n",
599 " for line in f:\n",
600 " splits = line.split(sep)\n",
601 " yield [splits[0], int(splits[1])]"
602 ]
603 },
604 {
605 "cell_type": "code",
606 "execution_count": 31,
607 "metadata": {
608 "collapsed": true
609 },
610 "outputs": [],
611 "source": [
612 "def normalise(frequencies):\n",
613 " \"\"\"Scale a set of frequencies so they sum to one\n",
614 " \n",
615 " >>> sorted(normalise({1: 1, 2: 0}).items())\n",
616 " [(1, 1.0), (2, 0.0)]\n",
617 " >>> sorted(normalise({1: 1, 2: 1}).items())\n",
618 " [(1, 0.5), (2, 0.5)]\n",
619 " >>> sorted(normalise({1: 1, 2: 1, 3: 1}).items()) # doctest: +ELLIPSIS\n",
620 " [(1, 0.333...), (2, 0.333...), (3, 0.333...)]\n",
621 " >>> sorted(normalise({1: 1, 2: 2, 3: 1}).items())\n",
622 " [(1, 0.25), (2, 0.5), (3, 0.25)]\n",
623 " \"\"\"\n",
624 " length = sum(f for f in frequencies.values())\n",
625 " return collections.defaultdict(int, ((k, v / length) \n",
626 " for (k, v) in frequencies.items()))\n"
627 ]
628 },
629 {
630 "cell_type": "code",
631 "execution_count": 32,
632 "metadata": {},
633 "outputs": [],
634 "source": [
635 "english_counts = collections.Counter(dict(datafile('count_1l.txt')))\n",
636 "normalised_english_counts = normalise(english_counts)"
637 ]
638 },
639 {
640 "cell_type": "code",
641 "execution_count": 33,
642 "metadata": {},
643 "outputs": [],
644 "source": [
645 "wordsearch_counts = collections.Counter(cat(ws_words))\n",
646 "normalised_wordsearch_counts = normalise(wordsearch_counts)"
647 ]
648 },
649 {
650 "cell_type": "code",
651 "execution_count": 34,
652 "metadata": {},
653 "outputs": [],
654 "source": [
655 "normalised_wordsearch_counts = normalise(collections.Counter(normalised_wordsearch_counts) + collections.Counter({l: 0.05 for l in string.ascii_lowercase}))"
656 ]
657 },
658 {
659 "cell_type": "code",
660 "execution_count": 35,
661 "metadata": {
662 "collapsed": true
663 },
664 "outputs": [],
665 "source": [
666 "def weighted_choice(d):\n",
667 " \"\"\"Generate random item from a dictionary of item counts\n",
668 " \"\"\"\n",
669 " target = random.uniform(0, sum(d.values()))\n",
670 " cuml = 0.0\n",
671 " for (l, p) in d.items():\n",
672 " cuml += p\n",
673 " if cuml > target:\n",
674 " return l\n",
675 " return None\n",
676 "\n",
677 "def random_english_letter():\n",
678 " \"\"\"Generate a random letter based on English letter counts\n",
679 " \"\"\"\n",
680 " return weighted_choice(normalised_english_counts)\n",
681 "\n",
682 "def random_wordsearch_letter():\n",
683 " \"\"\"Generate a random letter based on wordsearch letter counts\n",
684 " \"\"\"\n",
685 " return weighted_choice(normalised_wordsearch_counts)"
686 ]
687 },
688 {
689 "cell_type": "code",
690 "execution_count": 36,
691 "metadata": {},
692 "outputs": [
693 {
694 "data": {
695 "text/plain": [
696 "'aaaaaabbccddeeeeeeeeeeeffggghhhhhhiiiiiiiiillllmmnnnnnnnooooooooooppppqrrrrrrrssstttttttttuuwyyyyyyz'"
697 ]
698 },
699 "execution_count": 36,
700 "metadata": {},
701 "output_type": "execute_result"
702 }
703 ],
704 "source": [
705 "cat(sorted(random_english_letter() for i in range(100)))"
706 ]
707 },
708 {
709 "cell_type": "code",
710 "execution_count": 37,
711 "metadata": {},
712 "outputs": [
713 {
714 "data": {
715 "text/plain": [
716 "'aaaaaaaabbbccccddeeeeeeeeggghhhiiiiiiiijjkkllllnnnnoooooooooopppqqrrrrrssssssttttttuuuuvvwxxxxxyzzzz'"
717 ]
718 },
719 "execution_count": 37,
720 "metadata": {},
721 "output_type": "execute_result"
722 }
723 ],
724 "source": [
725 "cat(sorted(random_wordsearch_letter() for i in range(100)))"
726 ]
727 },
728 {
729 "cell_type": "code",
730 "execution_count": 38,
731 "metadata": {},
732 "outputs": [
733 {
734 "data": {
735 "text/plain": [
736 "'x'"
737 ]
738 },
739 "execution_count": 38,
740 "metadata": {},
741 "output_type": "execute_result"
742 }
743 ],
744 "source": [
745 "random_wordsearch_letter()"
746 ]
747 },
748 {
749 "cell_type": "code",
750 "execution_count": 39,
751 "metadata": {
752 "collapsed": true
753 },
754 "outputs": [],
755 "source": [
756 "def pad_grid(g0):\n",
757 " grid = copy.deepcopy(g0)\n",
758 " w = len(grid[0])\n",
759 " h = len(grid)\n",
760 " for r in range(h):\n",
761 " for c in range(w):\n",
762 " if grid[r][c] == '.':\n",
763 " grid[r][c] = random_wordsearch_letter()\n",
764 " return grid"
765 ]
766 },
767 {
768 "cell_type": "code",
769 "execution_count": 53,
770 "metadata": {},
771 "outputs": [
772 {
773 "name": "stdout",
774 "output_type": "stream",
775 "text": [
776 "dexawwtmxepybossmezt\n",
777 "snaprhlukulelefaoder\n",
778 "ijreriotebahrevordla\n",
779 "jrsivcciprstdekcahkp\n",
780 "atvecshkoiselapcydcd\n",
781 "nesrehpargohtilljpue\n",
782 "nuleaveyisasmuguhhrt\n",
783 "eyhsifntzrmnsaeesetc\n",
784 "xverbseebasedlritlla\n",
785 "prcckzwiefamdonaiaeg\n",
786 "osacqnsofgadmeeulsoo\n",
787 "gdoporcmanaotpqiinmp\n",
788 "ncmusbaslpnteaerdkiu\n",
789 "ionjoyswleirinioicns\n",
790 "wnkcentcskeracllkase\n",
791 "oabsuerusopxeaodantt\n",
792 "dureifidimuhedgnskea\n",
793 "agagvccapitolsgyscrl\n",
794 "hkvgsandblasterdhihi\n",
795 "syenesdratoelhitsnod\n"
796 ]
797 }
798 ],
799 "source": [
800 "padded = pad_grid(g)\n",
801 "print(show_grid(padded))"
802 ]
803 },
804 {
805 "cell_type": "code",
806 "execution_count": 54,
807 "metadata": {},
808 "outputs": [
809 {
810 "name": "stdout",
811 "output_type": "stream",
812 "text": [
813 "dexawwt....ybossm..t\n",
814 "snaprhlukulele..o.er\n",
815 "...erioteb.hrevordla\n",
816 "..sivc..pr.tdekcahkp\n",
817 "atve..h.oiselapcy.cd\n",
818 "nesrehpargohtill.pue\n",
819 "n.leaveyis.smuguhhrt\n",
820 "eyhsifnt.r...aeesetc\n",
821 "xverbseebasedlritl.a\n",
822 ".r..k.wie..mdonaiaeg\n",
823 "..ac.nsof.admeeulsoo\n",
824 "g.opo.cmanaotpqiinmp\n",
825 "nc.us.a.lpnteaerdkiu\n",
826 "ionjoys.leirinioicns\n",
827 "wnkcent.skeracllkase\n",
828 "oab..erusopxeao.antt\n",
829 "dureifidimuhed.nskea\n",
830 "aga...capitols..scrl\n",
831 "h.v.sandblaster..i.i\n",
832 "s.e..sdratoelhitsn.d\n"
833 ]
834 }
835 ],
836 "source": [
837 "print(show_grid(g))"
838 ]
839 },
840 {
841 "cell_type": "code",
842 "execution_count": 55,
843 "metadata": {
844 "scrolled": true
845 },
846 "outputs": [
847 {
848 "name": "stdout",
849 "output_type": "stream",
850 "text": [
851 "newscast (True, 7, 6, <Direction.down: 4>)\n",
852 "kittenish (True, 14, 9, <Direction.upright: 6>)\n",
853 "cocks (True, 12, 1, <Direction.upright: 6>)\n",
854 "lithographers (True, 5, 14, <Direction.left: 1>)\n",
855 "truckle (True, 7, 18, <Direction.up: 3>)\n",
856 "leotards (True, 19, 12, <Direction.left: 1>)\n",
857 "they (True, 3, 11, <Direction.up: 3>)\n",
858 "exposure (True, 15, 12, <Direction.left: 1>)\n",
859 "dehumidifier (True, 16, 13, <Direction.left: 1>)\n",
860 "sandblaster (True, 18, 4, <Direction.right: 2>)\n",
861 "alien (True, 9, 17, <Direction.downleft: 7>)\n",
862 "paddle (True, 12, 9, <Direction.upright: 6>)\n",
863 "shadowing (True, 19, 0, <Direction.up: 3>)\n",
864 "gondola (True, 9, 19, <Direction.downleft: 7>)\n",
865 "wrest (True, 0, 5, <Direction.downleft: 7>)\n",
866 "joys (True, 13, 3, <Direction.right: 2>)\n",
867 "minster (True, 11, 18, <Direction.down: 4>)\n",
868 "pales (True, 4, 14, <Direction.left: 1>)\n",
869 "chairs (True, 3, 5, <Direction.downright: 8>)\n",
870 "fishy (True, 7, 5, <Direction.left: 1>)\n",
871 "capitols (True, 17, 6, <Direction.right: 2>)\n",
872 "based (True, 8, 8, <Direction.right: 2>)\n",
873 "gums (True, 6, 14, <Direction.left: 1>)\n",
874 "pheromones (True, 5, 17, <Direction.downleft: 7>)\n",
875 "saki (True, 16, 16, <Direction.up: 3>)\n",
876 "moiety (True, 11, 7, <Direction.up: 3>)\n",
877 "waxed (True, 0, 4, <Direction.left: 1>)\n",
878 "guano (True, 17, 1, <Direction.up: 3>)\n",
879 "thriven (True, 0, 6, <Direction.downleft: 7>)\n",
880 "dilate (True, 19, 19, <Direction.up: 3>)\n",
881 "moray (True, 0, 16, <Direction.down: 4>)\n",
882 "icons (True, 13, 12, <Direction.downright: 8>)\n",
883 "adman (True, 7, 13, <Direction.downleft: 7>)\n",
884 "ukulele (True, 1, 7, <Direction.right: 2>)\n",
885 "hacked (True, 3, 17, <Direction.left: 1>)\n",
886 "rope (True, 5, 8, <Direction.up: 3>)\n",
887 "rise (True, 12, 15, <Direction.upright: 6>)\n",
888 "clue (True, 4, 15, <Direction.down: 4>)\n",
889 "acted (True, 8, 19, <Direction.up: 3>)\n",
890 "nicknack (True, 19, 17, <Direction.up: 3>)\n",
891 "spar (True, 12, 4, <Direction.upleft: 5>)\n",
892 "verbs (True, 8, 1, <Direction.right: 2>)\n",
893 "boss (True, 0, 12, <Direction.right: 2>)\n",
894 "annex (True, 4, 0, <Direction.down: 4>)\n",
895 "neck (True, 14, 5, <Direction.left: 1>)\n",
896 "repeater (True, 13, 11, <Direction.upright: 6>)\n",
897 "befalls (True, 8, 8, <Direction.down: 4>)\n",
898 "drover (True, 2, 17, <Direction.left: 1>)\n",
899 "leave (True, 6, 2, <Direction.right: 2>)\n",
900 "pans (True, 1, 3, <Direction.left: 1>)\n",
901 "brave (True, 15, 2, <Direction.down: 4>)\n",
902 "brigs (True, 2, 9, <Direction.down: 4>)\n",
903 "opus (True, 10, 19, <Direction.down: 4>)\n",
904 "live (True, 1, 6, <Direction.downleft: 7>)\n",
905 "noun (True, 10, 5, <Direction.downleft: 7>)\n",
906 "tail (True, 11, 12, <Direction.downright: 8>)\n",
907 "riot (True, 2, 4, <Direction.right: 2>)\n",
908 "care (True, 14, 13, <Direction.left: 1>)\n",
909 "hits (True, 19, 13, <Direction.right: 2>)\n",
910 "quilt (True, 11, 14, <Direction.upright: 6>)\n",
911 "part (True, 3, 19, <Direction.up: 3>)\n"
912 ]
913 }
914 ],
915 "source": [
916 "for w in ws:\n",
917 " print(w, present(padded, w))"
918 ]
919 },
920 {
921 "cell_type": "code",
922 "execution_count": 43,
923 "metadata": {},
924 "outputs": [],
925 "source": [
926 "def decoys(grid, words, all_words, limit=100):\n",
927 " decoy_words = []\n",
928 " dlen_limit = max(len(w) for w in words)\n",
929 " while len(words) + len(decoy_words) < limit:\n",
930 " d = random.choice(all_words)\n",
931 " if d not in words and len(d) >= 4 and len(d) <= dlen_limit and not present(grid, d)[0]:\n",
932 " decoy_words += [d]\n",
933 " return decoy_words"
934 ]
935 },
936 {
937 "cell_type": "code",
938 "execution_count": 44,
939 "metadata": {},
940 "outputs": [
941 {
942 "data": {
943 "text/plain": [
944 "['friendship',\n",
945 " 'stepping',\n",
946 " 'featheriest',\n",
947 " 'thriftily',\n",
948 " 'mutilation',\n",
949 " 'nook',\n",
950 " 'clewing',\n",
951 " 'meditated',\n",
952 " 'gooier',\n",
953 " 'cripples',\n",
954 " 'ponderously',\n",
955 " 'roundelay',\n",
956 " 'curtailed',\n",
957 " 'redeemed',\n",
958 " 'perimeters',\n",
959 " 'harelips',\n",
960 " 'overcompensating',\n",
961 " 'rejoicings',\n",
962 " 'adobe',\n",
963 " 'decreasing',\n",
964 " 'interstices',\n",
965 " 'curd',\n",
966 " 'orientate',\n",
967 " 'blueberries',\n",
968 " 'juniors',\n",
969 " 'broadloom',\n",
970 " 'debarring',\n",
971 " 'chandeliers',\n",
972 " 'segues',\n",
973 " 'army',\n",
974 " 'snuck',\n",
975 " 'pugilistic',\n",
976 " 'snugs',\n",
977 " 'dexterity',\n",
978 " 'dallies',\n",
979 " 'curving',\n",
980 " 'newsletter',\n",
981 " 'torn',\n",
982 " 'beaching',\n",
983 " 'limit',\n",
984 " 'blackguards',\n",
985 " 'breezier',\n",
986 " 'reoccur',\n",
987 " 'cabins']"
988 ]
989 },
990 "execution_count": 44,
991 "metadata": {},
992 "output_type": "execute_result"
993 }
994 ],
995 "source": [
996 "ds = decoys(padded, ws, ws_words)\n",
997 "ds"
998 ]
999 },
1000 {
1001 "cell_type": "code",
1002 "execution_count": 45,
1003 "metadata": {
1004 "scrolled": true
1005 },
1006 "outputs": [
1007 {
1008 "name": "stdout",
1009 "output_type": "stream",
1010 "text": [
1011 "opted (True, 5, 7, <Direction.downright: 8>)\n",
1012 "haywire (True, 8, 9, <Direction.downleft: 7>)\n",
1013 "busting (True, 4, 17, <Direction.left: 1>)\n",
1014 "succinct (True, 7, 17, <Direction.down: 4>)\n",
1015 "institute (True, 16, 18, <Direction.up: 3>)\n",
1016 "illicit (True, 13, 14, <Direction.left: 1>)\n",
1017 "hypersensitivity (True, 16, 15, <Direction.left: 1>)\n",
1018 "placement (True, 3, 11, <Direction.left: 1>)\n",
1019 "bathrobe (True, 0, 5, <Direction.right: 2>)\n",
1020 "inured (True, 4, 0, <Direction.right: 2>)\n",
1021 "caveats (True, 3, 8, <Direction.downleft: 7>)\n",
1022 "revisiting (True, 2, 11, <Direction.left: 1>)\n",
1023 "pulp (True, 15, 11, <Direction.right: 2>)\n",
1024 "teacup (True, 7, 16, <Direction.downleft: 7>)\n",
1025 "threading (True, 18, 6, <Direction.right: 2>)\n",
1026 "queered (True, 5, 13, <Direction.right: 2>)\n",
1027 "parking (True, 6, 9, <Direction.right: 2>)\n",
1028 "advent (True, 1, 11, <Direction.left: 1>)\n",
1029 "chasuble (True, 19, 19, <Direction.left: 1>)\n",
1030 "mosey (True, 7, 5, <Direction.downleft: 7>)\n",
1031 "highboys (True, 19, 4, <Direction.right: 2>)\n",
1032 "recharging (True, 18, 19, <Direction.up: 3>)\n",
1033 "flue (True, 12, 2, <Direction.upright: 6>)\n",
1034 "plywood (True, 3, 18, <Direction.left: 1>)\n",
1035 "gluing (True, 12, 12, <Direction.upleft: 5>)\n",
1036 "worrier (True, 1, 12, <Direction.right: 2>)\n",
1037 "karma (True, 17, 9, <Direction.left: 1>)\n",
1038 "peepers (True, 8, 7, <Direction.downleft: 7>)\n",
1039 "vulnerable (True, 17, 10, <Direction.right: 2>)\n",
1040 "boycott (True, 15, 1, <Direction.right: 2>)\n",
1041 "rummy (True, 5, 4, <Direction.left: 1>)\n",
1042 "tonic (True, 8, 13, <Direction.downleft: 7>)\n",
1043 "children (True, 15, 0, <Direction.up: 3>)\n",
1044 "reales (True, 6, 1, <Direction.right: 2>)\n",
1045 "rectal (True, 7, 15, <Direction.down: 4>)\n",
1046 "sledded (True, 14, 16, <Direction.up: 3>)\n",
1047 "collocates (True, 14, 5, <Direction.right: 2>)\n",
1048 "edict (True, 17, 4, <Direction.left: 1>)\n",
1049 "captor (True, 14, 5, <Direction.upright: 6>)\n",
1050 "amulet (True, 9, 4, <Direction.upright: 6>)\n",
1051 "slipper (True, 2, 13, <Direction.right: 2>)\n",
1052 "foot (True, 0, 0, <Direction.right: 2>)\n",
1053 "chef (True, 14, 4, <Direction.upright: 6>)\n",
1054 "goods (True, 6, 15, <Direction.right: 2>)\n",
1055 "salter (True, 1, 5, <Direction.left: 1>)\n",
1056 "crows (True, 18, 0, <Direction.right: 2>)\n",
1057 "paeans (True, 12, 14, <Direction.up: 3>)\n",
1058 "fences (True, 0, 18, <Direction.left: 1>)\n",
1059 "iron (True, 5, 9, <Direction.right: 2>)\n",
1060 "liras (True, 0, 19, <Direction.down: 4>)\n",
1061 "stages (True, 19, 16, <Direction.up: 3>)\n",
1062 "defer (True, 14, 2, <Direction.upright: 6>)\n",
1063 "racy (True, 5, 4, <Direction.downleft: 7>)\n",
1064 "gaps (True, 7, 11, <Direction.right: 2>)\n",
1065 "aspen (True, 12, 10, <Direction.upleft: 5>)\n",
1066 "rams (True, 6, 0, <Direction.downright: 8>)\n",
1067 "friendship (False, 0, 0, <Direction.left: 1>)\n",
1068 "stepping (False, 0, 0, <Direction.left: 1>)\n",
1069 "featheriest (False, 0, 0, <Direction.left: 1>)\n",
1070 "thriftily (False, 0, 0, <Direction.left: 1>)\n",
1071 "mutilation (False, 0, 0, <Direction.left: 1>)\n",
1072 "nook (False, 0, 0, <Direction.left: 1>)\n",
1073 "clewing (False, 0, 0, <Direction.left: 1>)\n",
1074 "meditated (False, 0, 0, <Direction.left: 1>)\n",
1075 "gooier (False, 0, 0, <Direction.left: 1>)\n",
1076 "cripples (False, 0, 0, <Direction.left: 1>)\n",
1077 "ponderously (False, 0, 0, <Direction.left: 1>)\n",
1078 "roundelay (False, 0, 0, <Direction.left: 1>)\n",
1079 "curtailed (False, 0, 0, <Direction.left: 1>)\n",
1080 "redeemed (False, 0, 0, <Direction.left: 1>)\n",
1081 "perimeters (False, 0, 0, <Direction.left: 1>)\n",
1082 "harelips (False, 0, 0, <Direction.left: 1>)\n",
1083 "overcompensating (False, 0, 0, <Direction.left: 1>)\n",
1084 "rejoicings (False, 0, 0, <Direction.left: 1>)\n",
1085 "adobe (False, 0, 0, <Direction.left: 1>)\n",
1086 "decreasing (False, 0, 0, <Direction.left: 1>)\n",
1087 "interstices (False, 0, 0, <Direction.left: 1>)\n",
1088 "curd (False, 0, 0, <Direction.left: 1>)\n",
1089 "orientate (False, 0, 0, <Direction.left: 1>)\n",
1090 "blueberries (False, 0, 0, <Direction.left: 1>)\n",
1091 "juniors (False, 0, 0, <Direction.left: 1>)\n",
1092 "broadloom (False, 0, 0, <Direction.left: 1>)\n",
1093 "debarring (False, 0, 0, <Direction.left: 1>)\n",
1094 "chandeliers (False, 0, 0, <Direction.left: 1>)\n",
1095 "segues (False, 0, 0, <Direction.left: 1>)\n",
1096 "army (False, 0, 0, <Direction.left: 1>)\n",
1097 "snuck (False, 0, 0, <Direction.left: 1>)\n",
1098 "pugilistic (False, 0, 0, <Direction.left: 1>)\n",
1099 "snugs (False, 0, 0, <Direction.left: 1>)\n",
1100 "dexterity (False, 0, 0, <Direction.left: 1>)\n",
1101 "dallies (False, 0, 0, <Direction.left: 1>)\n",
1102 "curving (False, 0, 0, <Direction.left: 1>)\n",
1103 "newsletter (False, 0, 0, <Direction.left: 1>)\n",
1104 "torn (False, 0, 0, <Direction.left: 1>)\n",
1105 "beaching (False, 0, 0, <Direction.left: 1>)\n",
1106 "limit (False, 0, 0, <Direction.left: 1>)\n",
1107 "blackguards (False, 0, 0, <Direction.left: 1>)\n",
1108 "breezier (False, 0, 0, <Direction.left: 1>)\n",
1109 "reoccur (False, 0, 0, <Direction.left: 1>)\n",
1110 "cabins (False, 0, 0, <Direction.left: 1>)\n"
1111 ]
1112 }
1113 ],
1114 "source": [
1115 "for w in ws + ds:\n",
1116 " print(w, present(padded, w))"
1117 ]
1118 },
1119 {
1120 "cell_type": "code",
1121 "execution_count": 46,
1122 "metadata": {
1123 "scrolled": true
1124 },
1125 "outputs": [
1126 {
1127 "name": "stdout",
1128 "output_type": "stream",
1129 "text": [
1130 "s.esevresed...dwhims\n",
1131 "e.tbk..vapourse.bn.d\n",
1132 "h.ificembracesnslo.e\n",
1133 "ctr.egukiwic..ddui.r\n",
1134 "inor.dwh.rips.rrftsa\n",
1135 "reue.eeisrar.tiefiyl\n",
1136 "mmli.mgrg.muarth.slc\n",
1137 "ieft.un.a.bnbuemdole\n",
1138 "nn.nesimrliertseepad\n",
1139 "ei.imeloeccdeh.epob.\n",
1140 "dfsaprlrio.saf.smri.\n",
1141 "cnpdt.ofrn.usu..ap.h\n",
1142 "oom.ispeccgntlpew.sa\n",
1143 "tcu.e.l.lu.eda.vsgin\n",
1144 "e.bdsb.oarrmneloplsg\n",
1145 "r.olaetrleromrkr.isa\n",
1146 "ibatnhd.nlpoaeic.bir\n",
1147 "eesiee.i.luepno.o.e.\n",
1148 "snt.d.o.y.pcte.p.mr.\n",
1149 "u....jtoquesylduol..\n",
1150 "sfesevresedpzcdwhims\n",
1151 "eotbkvgvapoursehbnyd\n",
1152 "hiificembracesnslone\n",
1153 "ctrnegukiwicurdduivr\n",
1154 "inorydwhrripscrrftsa\n",
1155 "reueleeisrarvtiefiyl\n",
1156 "mmlinmgrgzmuarthgslc\n",
1157 "ieftuunyanbnbuemdole\n",
1158 "nncnesimrliertseepad\n",
1159 "eirimeloeccdehzepobm\n",
1160 "dfsaprlrioisafesmriq\n",
1161 "cnpdtsofrnausuodapxh\n",
1162 "oomlispeccgntlpewasa\n",
1163 "tcuaehlzluledakvsgin\n",
1164 "eibdsbeoarrmneloplsg\n",
1165 "rbolaetrleromrkrnisa\n",
1166 "ibatnhdtnlpoaeicibir\n",
1167 "eesieerimluepnoholey\n",
1168 "sntadvoaycpctespsmro\n",
1169 "uamapjtoquesylduoldp\n",
1170 "56 words added; 8 directions\n",
1171 "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",
1172 "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"
1173 ]
1174 }
1175 ],
1176 "source": [
1177 "g, ws = interesting_grid()\n",
1178 "p = pad_grid(g)\n",
1179 "ds = decoys(p, ws, ws_words)\n",
1180 "print(show_grid(g))\n",
1181 "print(show_grid(p))\n",
1182 "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
1183 "print('Present:', wcat(sorted(ws)))\n",
1184 "print('Decoys:', wcat(sorted(ds)))"
1185 ]
1186 },
1187 {
1188 "cell_type": "code",
1189 "execution_count": 63,
1190 "metadata": {
1191 "scrolled": true
1192 },
1193 "outputs": [
1194 {
1195 "name": "stdout",
1196 "output_type": "stream",
1197 "text": [
1198 "...p.mown.\n",
1199 ".sdse..ee.\n",
1200 ".e.elad.cr\n",
1201 "pi.dtir.ah\n",
1202 "rzsiwovspu\n",
1203 "oawh.kieab\n",
1204 "brow.c.rda\n",
1205 "ecnotops.r\n",
1206 "d.kc.d...b\n",
1207 ".staple...\n",
1208 "\n",
1209 "fhjpamownq\n",
1210 "wsdseuqeev\n",
1211 "ieaeladhcr\n",
1212 "piedtiriah\n",
1213 "rzsiwovspu\n",
1214 "oawhakieab\n",
1215 "browpcfrda\n",
1216 "ecnotopssr\n",
1217 "dikchdnpnb\n",
1218 "bstapleokr\n",
1219 "14 words added; 6 directions\n",
1220 "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
1221 "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"
1222 ]
1223 }
1224 ],
1225 "source": [
1226 "g, ws = interesting_grid(width=10, height=10, words_limit=5, direction_slack=6)\n",
1227 "p = pad_grid(g)\n",
1228 "ds = decoys(p, ws, ws_words)\n",
1229 "print(show_grid(g))\n",
1230 "print()\n",
1231 "print(show_grid(p))\n",
1232 "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
1233 "print('Present:', wcat(sorted(ws)))\n",
1234 "print('Decoys:', wcat(sorted(ds)))"
1235 ]
1236 },
1237 {
1238 "cell_type": "code",
1239 "execution_count": 98,
1240 "metadata": {},
1241 "outputs": [
1242 {
1243 "data": {
1244 "text/plain": [
1245 "['fickler',\n",
1246 " 'adapting',\n",
1247 " 'chump',\n",
1248 " 'foaming',\n",
1249 " 'molested',\n",
1250 " 'carnal',\n",
1251 " 'crumbled',\n",
1252 " 'guts',\n",
1253 " 'minuend',\n",
1254 " 'bombing',\n",
1255 " 'winced',\n",
1256 " 'coccyxes',\n",
1257 " 'solaria',\n",
1258 " 'shinier',\n",
1259 " 'cackles']"
1260 ]
1261 },
1262 "execution_count": 98,
1263 "metadata": {},
1264 "output_type": "execute_result"
1265 }
1266 ],
1267 "source": [
1268 "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",
1269 "ds = random.sample(ds_original, 15)\n",
1270 "ds"
1271 ]
1272 },
1273 {
1274 "cell_type": "code",
1275 "execution_count": 89,
1276 "metadata": {
1277 "scrolled": true
1278 },
1279 "outputs": [
1280 {
1281 "data": {
1282 "text/plain": [
1283 "['regards',\n",
1284 " 'perfect',\n",
1285 " 'instants',\n",
1286 " 'refined',\n",
1287 " 'coddle',\n",
1288 " 'fickler',\n",
1289 " 'gambol',\n",
1290 " 'misprint',\n",
1291 " 'tapes',\n",
1292 " 'impugns',\n",
1293 " 'moonshot',\n",
1294 " 'chump',\n",
1295 " 'brick',\n",
1296 " 'siren',\n",
1297 " 'faddish',\n",
1298 " 'winced',\n",
1299 " 'kielbasy',\n",
1300 " 'market',\n",
1301 " 'puckered',\n",
1302 " 'trains',\n",
1303 " 'welts',\n",
1304 " 'cackles',\n",
1305 " 'foaming',\n",
1306 " 'proceed',\n",
1307 " 'gliding',\n",
1308 " 'guts',\n",
1309 " 'uric',\n",
1310 " 'oaks',\n",
1311 " 'molested',\n",
1312 " 'curled',\n",
1313 " 'boor',\n",
1314 " 'solaria',\n",
1315 " 'gristle',\n",
1316 " 'bombing',\n",
1317 " 'loamier',\n",
1318 " 'ensuing',\n",
1319 " 'cunt',\n",
1320 " 'sunder',\n",
1321 " 'revel',\n",
1322 " 'coaster',\n",
1323 " 'grunts',\n",
1324 " 'mucking',\n",
1325 " 'typesets',\n",
1326 " 'carnal',\n",
1327 " 'whimsy',\n",
1328 " 'scoff',\n",
1329 " 'coccyxes',\n",
1330 " 'meanly',\n",
1331 " 'sprain',\n",
1332 " 'minuend',\n",
1333 " 'ringlet',\n",
1334 " 'fest',\n",
1335 " 'winced',\n",
1336 " 'shinier',\n",
1337 " 'dicier',\n",
1338 " 'thirds',\n",
1339 " 'olives',\n",
1340 " 'garoting',\n",
1341 " 'pastrami',\n",
1342 " 'tranquil',\n",
1343 " 'tamped',\n",
1344 " 'sunup',\n",
1345 " 'crumbled',\n",
1346 " 'throw',\n",
1347 " 'ridges',\n",
1348 " 'chaplets',\n",
1349 " 'curlier',\n",
1350 " 'lugs',\n",
1351 " 'collies',\n",
1352 " 'adapting',\n",
1353 " 'demeanor',\n",
1354 " 'deepen',\n",
1355 " 'lanyard',\n",
1356 " 'tiller',\n",
1357 " 'transfix',\n",
1358 " 'wariness',\n",
1359 " 'times',\n",
1360 " 'mitts',\n",
1361 " 'dowses',\n",
1362 " 'creels',\n",
1363 " 'curds',\n",
1364 " 'quashed',\n",
1365 " 'orgasmic',\n",
1366 " 'ibex',\n",
1367 " 'retraces',\n",
1368 " 'casino']"
1369 ]
1370 },
1371 "execution_count": 89,
1372 "metadata": {},
1373 "output_type": "execute_result"
1374 }
1375 ],
1376 "source": [
1377 "ds_original"
1378 ]
1379 },
1380 {
1381 "cell_type": "code",
1382 "execution_count": 99,
1383 "metadata": {
1384 "scrolled": true
1385 },
1386 "outputs": [
1387 {
1388 "name": "stdout",
1389 "output_type": "stream",
1390 "text": [
1391 "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",
1392 "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",
1393 "present_words = ['probed', 'staple', 'rioted', 'cowhides', 'tops', 'knows', 'lived', 'rhubarb', 'crazies', 'dock', 'apace', 'mown', 'pears', 'wide']\n",
1394 "decoy_words = ['fickler', 'adapting', 'chump', 'foaming', 'molested', 'carnal', 'crumbled', 'guts', 'minuend', 'bombing', 'winced', 'coccyxes', 'solaria', 'shinier', 'cackles']\n",
1395 "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"
1396 ]
1397 }
1398 ],
1399 "source": [
1400 "print('grid = ', g)\n",
1401 "print('padded_grid = ', p)\n",
1402 "print('present_words = ', ws)\n",
1403 "print('decoy_words = ', ds)\n",
1404 "print('Directions: ', [(w, '`' + str(present(g, w)) + '`') for w in ws])"
1405 ]
1406 },
1407 {
1408 "cell_type": "code",
1409 "execution_count": 100,
1410 "metadata": {
1411 "collapsed": true
1412 },
1413 "outputs": [],
1414 "source": [
1415 "# with open('example-wordsearch.txt', 'w') as f:\n",
1416 "# f.write('10x10\\n')\n",
1417 "# f.write(show_grid(p))\n",
1418 "# f.write('\\n')\n",
1419 "# f.write(lcat(sorted(ws + ds)))\n",
1420 "# with open('exmaple-wordsearch-solution.txt', 'w') as f:\n",
1421 "# f.write('10x10\\n')\n",
1422 "# f.write(show_grid(g))\n",
1423 "# f.write('\\n')\n",
1424 "# f.write(lcat(sorted(ws)) + '\\n\\n')\n",
1425 "# f.write(lcat(sorted(ds)))"
1426 ]
1427 },
1428 {
1429 "cell_type": "code",
1430 "execution_count": 77,
1431 "metadata": {
1432 "scrolled": true
1433 },
1434 "outputs": [
1435 {
1436 "name": "stdout",
1437 "output_type": "stream",
1438 "text": [
1439 "probed 3 0 6 Direction.down [(3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0)]\n",
1440 "staple 9 1 6 Direction.right [(9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)]\n",
1441 "rioted 6 7 6 Direction.upleft [(6, 7), (5, 6), (4, 5), (3, 4), (2, 3), (1, 2)]\n",
1442 "cowhides 8 3 8 Direction.up [(8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3)]\n",
1443 "tops 7 4 4 Direction.right [(7, 4), (7, 5), (7, 6), (7, 7)]\n",
1444 "knows 8 2 5 Direction.up [(8, 2), (7, 2), (6, 2), (5, 2), (4, 2)]\n",
1445 "lived 2 4 5 Direction.downright [(2, 4), (3, 5), (4, 6), (5, 7), (6, 8)]\n",
1446 "rhubarb 2 9 7 Direction.down [(2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9)]\n",
1447 "crazies 7 1 7 Direction.up [(7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)]\n",
1448 "dock 8 5 4 Direction.up [(8, 5), (7, 5), (6, 5), (5, 5)]\n",
1449 "apace 5 8 5 Direction.up [(5, 8), (4, 8), (3, 8), (2, 8), (1, 8)]\n",
1450 "mown 0 5 4 Direction.right [(0, 5), (0, 6), (0, 7), (0, 8)]\n",
1451 "pears 0 3 5 Direction.downright [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]\n",
1452 "wide 4 4 4 Direction.upright [(4, 4), (3, 5), (2, 6), (1, 7)]\n"
1453 ]
1454 },
1455 {
1456 "data": {
1457 "text/plain": [
1458 "[(7, 5), (2, 3), (3, 5)]"
1459 ]
1460 },
1461 "execution_count": 77,
1462 "metadata": {},
1463 "output_type": "execute_result"
1464 }
1465 ],
1466 "source": [
1467 "cts = collections.Counter()\n",
1468 "for w in ws:\n",
1469 " _, r, c, d = present(g, w)\n",
1470 " inds = indices(g, r, c, len(w), d)\n",
1471 " for i in inds:\n",
1472 " cts[i] += 1\n",
1473 " print(w, r, c, len(w), d, inds)\n",
1474 "[i for i in cts if cts[i] > 1]"
1475 ]
1476 },
1477 {
1478 "cell_type": "code",
1479 "execution_count": null,
1480 "metadata": {
1481 "collapsed": true
1482 },
1483 "outputs": [],
1484 "source": []
1485 },
1486 {
1487 "cell_type": "code",
1488 "execution_count": 143,
1489 "metadata": {
1490 "scrolled": true
1491 },
1492 "outputs": [
1493 {
1494 "name": "stdout",
1495 "output_type": "stream",
1496 "text": [
1497 "0\n",
1498 "1\n",
1499 "2\n",
1500 "3\n",
1501 "4\n",
1502 "5\n",
1503 "6\n",
1504 "7\n",
1505 "8\n",
1506 "9\n",
1507 "10\n",
1508 "11\n",
1509 "12\n",
1510 "13\n",
1511 "14\n",
1512 "15\n",
1513 "16\n",
1514 "17\n",
1515 "18\n",
1516 "19\n",
1517 "20\n",
1518 "21\n",
1519 "22\n",
1520 "23\n",
1521 "24\n",
1522 "25\n",
1523 "26\n",
1524 "27\n",
1525 "28\n",
1526 "29\n",
1527 "30\n",
1528 "31\n",
1529 "32\n",
1530 "33\n",
1531 "34\n",
1532 "35\n",
1533 "36\n",
1534 "37\n",
1535 "38\n",
1536 "39\n",
1537 "40\n",
1538 "41\n",
1539 "42\n",
1540 "43\n",
1541 "44\n",
1542 "45\n",
1543 "46\n",
1544 "47\n",
1545 "48\n",
1546 "49\n",
1547 "50\n",
1548 "51\n",
1549 "52\n",
1550 "53\n",
1551 "54\n",
1552 "55\n",
1553 "56\n",
1554 "57\n",
1555 "58\n",
1556 "59\n",
1557 "60\n",
1558 "61\n",
1559 "62\n",
1560 "63\n",
1561 "64\n",
1562 "65\n",
1563 "66\n",
1564 "67\n",
1565 "68\n",
1566 "69\n",
1567 "70\n",
1568 "71\n",
1569 "72\n",
1570 "73\n",
1571 "74\n",
1572 "75\n",
1573 "76\n",
1574 "77\n",
1575 "78\n",
1576 "79\n",
1577 "80\n",
1578 "81\n",
1579 "82\n",
1580 "83\n",
1581 "84\n",
1582 "85\n",
1583 "86\n",
1584 "87\n",
1585 "88\n",
1586 "89\n",
1587 "90\n",
1588 "91\n",
1589 "92\n",
1590 "93\n",
1591 "94\n",
1592 "95\n",
1593 "96\n",
1594 "97\n",
1595 "98\n",
1596 "99\n"
1597 ]
1598 }
1599 ],
1600 "source": [
1601 "# for i in range(100):\n",
1602 "# print(i)\n",
1603 "# g, ws = interesting_grid()\n",
1604 "# p = pad_grid(g)\n",
1605 "# ds = decoys(p, ws, ws_words)\n",
1606 "# with open('wordsearch{:02}.txt'.format(i), 'w') as f:\n",
1607 "# f.write('20x20\\n')\n",
1608 "# f.write(show_grid(p))\n",
1609 "# f.write('\\n')\n",
1610 "# f.write(lcat(sorted(ws + ds)))\n",
1611 "# with open('wordsearch-solution{:02}.txt'.format(i), 'w') as f:\n",
1612 "# f.write('20x20\\n')\n",
1613 "# f.write(show_grid(g))\n",
1614 "# f.write('\\n')\n",
1615 "# f.write(lcat(sorted(ws)) + '\\n\\n')\n",
1616 "# f.write(lcat(sorted(ds)))"
1617 ]
1618 },
1619 {
1620 "cell_type": "code",
1621 "execution_count": null,
1622 "metadata": {
1623 "collapsed": true
1624 },
1625 "outputs": [],
1626 "source": []
1627 }
1628 ],
1629 "metadata": {
1630 "kernelspec": {
1631 "display_name": "Python 3",
1632 "language": "python",
1633 "name": "python3"
1634 },
1635 "language_info": {
1636 "codemirror_mode": {
1637 "name": "ipython",
1638 "version": 3
1639 },
1640 "file_extension": ".py",
1641 "mimetype": "text/x-python",
1642 "name": "python",
1643 "nbconvert_exporter": "python",
1644 "pygments_lexer": "ipython3",
1645 "version": "3.5.2+"
1646 }
1647 },
1648 "nbformat": 4,
1649 "nbformat_minor": 1
1650 }