14 "import collections\n",
17 "from enum import Enum\n",
18 "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
20 "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
21 " Direction.up: (-1, 0), Direction.down: (1, 0), \n",
22 " Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
23 " Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
38 "# all_words = [w.strip() for w in open('/usr/share/dict/british-english').readlines()\n",
39 "# if all(c in string.ascii_lowercase for c in w.strip())]\n",
40 "# words = [w for w in all_words\n",
41 "# if not any(w in w2 for w2 in all_words if w != w2)]\n",
42 "# open('wordsearch-words', 'w').write(lcat(words))"
69 "output_type": "execute_result"
73 "ws_words = [w.strip() for w in open('wordsearch-words').readlines()\n",
74 " if all(c in string.ascii_lowercase for c in w.strip())]\n",
86 "def empty_grid(w, h):\n",
87 " return [['.' for c in range(w)] for r in range(h)]"
98 "def show_grid(grid):\n",
99 " return lcat(cat(r) for r in grid)"
104 "execution_count": 7,
111 "output_type": "stream",
127 "grid = empty_grid(10, 10)\n",
128 "print(show_grid(grid))"
133 "execution_count": 8,
139 "def indices(grid, r, c, l, d):\n",
140 " dr, dc = delta[d]\n",
141 " w = len(grid[0])\n",
143 " inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
144 " return [(i, j) for i, j in inds\n",
153 "execution_count": 9,
159 "def gslice(grid, r, c, l, d):\n",
160 " return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
165 "execution_count": 10,
171 "def set_grid(grid, r, c, d, word):\n",
172 " for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
179 "execution_count": 11,
186 "output_type": "stream",
202 "set_grid(grid, 2, 3, Direction.downright, 'testword')\n",
203 "print(show_grid(grid))"
208 "execution_count": 12,
219 "execution_count": 12,
221 "output_type": "execute_result"
225 "cat(gslice(grid, 3, 2, 15, Direction.right))"
230 "execution_count": 13,
238 "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
241 "execution_count": 13,
243 "output_type": "execute_result"
247 "re.match(cat(gslice(grid, 3, 2, 4, Direction.right)), 'keen')"
252 "execution_count": 14,
260 "<_sre.SRE_Match object; span=(0, 3), match='kee'>"
263 "execution_count": 14,
265 "output_type": "execute_result"
269 "re.match(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
274 "execution_count": 15,
280 "re.fullmatch(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
285 "execution_count": 16,
291 "re.match(cat(gslice(grid, 3, 2, 4, Direction.right)), 'kine')"
296 "execution_count": 17,
302 "def could_add(grid, r, c, d, word):\n",
303 " s = gslice(grid, r, c, len(word), d)\n",
304 " return re.fullmatch(cat(s), word)"
309 "execution_count": 18,
317 "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
320 "execution_count": 18,
322 "output_type": "execute_result"
326 "could_add(grid, 3, 2, Direction.right, 'keen')"
331 "execution_count": 19,
337 "could_add(grid, 3, 2, Direction.right, 'kine')"
342 "execution_count": 20,
353 "execution_count": 20,
355 "output_type": "execute_result"
359 "random.choice(list(Direction))"
364 "execution_count": 21,
370 "def fill_grid(grid, words, word_count, max_attempts= 1000):\n",
372 " added_words = []\n",
373 " w = len(grid[0])\n",
375 " while len(added_words) < word_count and attempts < max_attempts:\n",
377 " r = random.randrange(w)\n",
378 " c = random.randrange(h)\n",
379 " word = random.choice(words)\n",
380 " d = random.choice(list(Direction))\n",
381 " if could_add(grid, r, c, d, word):\n",
382 " set_grid(grid, r, c, d, word)\n",
383 " added_words += [word]\n",
385 " return grid, added_words"
390 "execution_count": 22,
401 "execution_count": 22,
403 "output_type": "execute_result"
407 "g = empty_grid(20, 20)\n",
408 "g, ws = fill_grid(g, ws_words, 40)\n",
414 "execution_count": 23,
421 "output_type": "stream",
423 "......swoopingg.l.up\n",
424 "..dunsnapped.n.i..ne\n",
425 ".cee.gninarci.m...er\n",
426 "sotpt......k.pmv..mv\n",
427 "euirca.d..c.n.a...pa\n",
428 "snduo.o.eo.e.lgs..ld\n",
429 "itndny.ctks.i.nos.oe\n",
430 "rroev.lsrsss..ifr.ys\n",
431 "eycno.eb.aeub.ttebas\n",
432 "tmetyr..asgetmuemebe\n",
433 "nerie....tvuu.dsraln\n",
434 "in.adbdmbecls.etocei\n",
435 "w..loeu.lilu..s.fh.d\n",
436 "...rtl.e.ec.l...eimw\n",
437 "..oac.d.v..y.e..rnao\n",
438 ".nrhgniknilsc.n..gyd\n",
439 ".pignippay...l.i..f.\n",
440 ".n..skcenrehtael..l.\n",
441 "g....popinjays.s..y.\n",
442 "gnimmugspuds.relppus\n",
444 "ineluctably limpness countrymen slinking beaching restocking vellum convoyed winterises tusked leathernecks sugarcoated mayfly mulching popinjays magnitudes unsnapped prudential yapping spuds softest boron craning unemployable reformers bicycles swooping recondite dowdiness gumming pervades beveled valises suppler prated\n"
449 "print(show_grid(g))\n",
450 "print(len(ws), 'words added')\n",
456 "execution_count": 24,
462 "def present(grid, word):\n",
463 " w = len(grid[0])\n",
465 " for r in range(h):\n",
466 " for c in range(w):\n",
467 " for d in Direction:\n",
468 " if cat(gslice(grid, r, c, len(word), d)) == word:\n",
469 " return True, r, c, d\n",
470 " return False, 0, 0, list(Direction)[0]"
475 "execution_count": 25,
483 "output_type": "stream",
485 "ineluctably (True, 16, 15, <Direction.upleft: 5>)\n",
486 "limpness (True, 0, 16, <Direction.downleft: 7>)\n",
487 "countrymen (True, 2, 1, <Direction.down: 4>)\n",
488 "slinking (True, 15, 11, <Direction.left: 1>)\n",
489 "beaching (True, 8, 17, <Direction.down: 4>)\n",
490 "restocking (True, 9, 5, <Direction.upright: 6>)\n",
491 "vellum (True, 14, 8, <Direction.upright: 6>)\n",
492 "convoyed (True, 4, 4, <Direction.down: 4>)\n",
493 "winterises (True, 12, 0, <Direction.up: 3>)\n",
494 "tusked (True, 9, 12, <Direction.upleft: 5>)\n",
495 "leathernecks (True, 17, 15, <Direction.left: 1>)\n",
496 "sugarcoated (True, 11, 12, <Direction.upleft: 5>)\n",
497 "mayfly (True, 13, 18, <Direction.down: 4>)\n",
498 "mulching (True, 11, 7, <Direction.downleft: 7>)\n",
499 "popinjays (True, 18, 5, <Direction.right: 2>)\n",
500 "magnitudes (True, 3, 14, <Direction.down: 4>)\n",
501 "unsnapped (True, 1, 3, <Direction.right: 2>)\n",
502 "prudential (True, 3, 3, <Direction.down: 4>)\n",
503 "yapping (True, 16, 9, <Direction.left: 1>)\n",
504 "spuds (True, 19, 7, <Direction.right: 2>)\n",
505 "softest (True, 5, 15, <Direction.down: 4>)\n",
506 "boron (True, 11, 5, <Direction.downleft: 7>)\n",
507 "craning (True, 2, 11, <Direction.left: 1>)\n",
508 "unemployable (True, 0, 18, <Direction.down: 4>)\n",
509 "reformers (True, 14, 16, <Direction.up: 3>)\n",
510 "bicycles (True, 11, 8, <Direction.downright: 8>)\n",
511 "swooping (True, 0, 6, <Direction.right: 2>)\n",
512 "recondite (True, 10, 2, <Direction.up: 3>)\n",
513 "dowdiness (True, 15, 19, <Direction.up: 3>)\n",
514 "gumming (True, 19, 6, <Direction.left: 1>)\n",
515 "pervades (True, 0, 19, <Direction.down: 4>)\n",
516 "beveled (True, 8, 12, <Direction.downleft: 7>)\n",
517 "valises (True, 3, 15, <Direction.downleft: 7>)\n",
518 "suppler (True, 19, 19, <Direction.left: 1>)\n",
519 "prated (True, 16, 1, <Direction.upright: 6>)\n"
525 " print(w, present(g, w))"
530 "execution_count": 26,
536 "def interesting(grid, words):\n",
537 " dirs = set(present(grid, w)[3] for w in words)\n",
538 " return len(words) > 35 and len(words) < 40 and len(dirs) + 1 >= len(delta)"
543 "execution_count": 27,
554 "execution_count": 27,
556 "output_type": "execute_result"
565 "execution_count": 28,
571 "def interesting_grid():\n",
574 " grid = empty_grid(20, 20)\n",
575 " grid, words = fill_grid(grid, ws_words, 40)\n",
576 " boring = not interesting(grid, words)\n",
577 " return grid, words"
582 "execution_count": 29,
589 "output_type": "stream",
591 "..reittonk..ss......\n",
592 "tinctured.wcee.....w\n",
593 "serutats.oyozm....o.\n",
594 "b....s..l.eoia...m.r\n",
595 "e.b.y.lf..lpsd..bgye\n",
596 "a.ist.no..less.ssrgm\n",
597 "m.gtfi.lo.orae.n.ura\n",
598 "edaei..i.cwi.mo..mor\n",
599 "demrn..b..in.m...psk\n",
600 "epya...e..sgm....ile\n",
601 "slsg...l..hi.....nrd\n",
602 "tekisyassesdepeebeum\n",
603 "rtec.gninretni...sfo\n",
604 "oiinsetse..baggy.snd\n",
605 "ynn....p..sebircsaui\n",
606 "egs.noitasiretupmocf\n",
607 "r.....artefacts....y\n",
608 "s.....seilaog.winosi\n",
609 ".....eyelidsegener.n\n",
610 "regicidesesopatxuj.g\n",
611 "38 words added; 7 directions\n",
612 "wombs persimmons computerisation ascribes coopering goalies beamed modifying insets cigarets statures libels remarked baggy juxtaposes mesdames grumpiness artefacts skeins assizes inflow depleting beeped reneges interning yellowish regicides eyelids cools orgy nifty knottier destroyers unfurls tinctured bigamy winos essays\n"
617 "g, ws = interesting_grid()\n",
618 "print(show_grid(g))\n",
619 "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
625 "execution_count": 30,
631 "def datafile(name, sep='\\t'):\n",
632 " \"\"\"Read key,value pairs from file.\n",
634 " with open(name) as f:\n",
636 " splits = line.split(sep)\n",
637 " yield [splits[0], int(splits[1])]"
642 "execution_count": 31,
648 "def normalise(frequencies):\n",
649 " \"\"\"Scale a set of frequencies so they sum to one\n",
651 " >>> sorted(normalise({1: 1, 2: 0}).items())\n",
652 " [(1, 1.0), (2, 0.0)]\n",
653 " >>> sorted(normalise({1: 1, 2: 1}).items())\n",
654 " [(1, 0.5), (2, 0.5)]\n",
655 " >>> sorted(normalise({1: 1, 2: 1, 3: 1}).items()) # doctest: +ELLIPSIS\n",
656 " [(1, 0.333...), (2, 0.333...), (3, 0.333...)]\n",
657 " >>> sorted(normalise({1: 1, 2: 2, 3: 1}).items())\n",
658 " [(1, 0.25), (2, 0.5), (3, 0.25)]\n",
660 " length = sum(f for f in frequencies.values())\n",
661 " return collections.defaultdict(int, ((k, v / length) \n",
662 " for (k, v) in frequencies.items()))\n"
667 "execution_count": 32,
673 "english_counts = collections.Counter(dict(datafile('count_1l.txt')))\n",
674 "normalised_english_counts = normalise(english_counts)"
679 "execution_count": 34,
685 "wordsearch_counts = collections.Counter(cat(ws_words))\n",
686 "normalised_wordsearch_counts = normalise(wordsearch_counts)"
691 "execution_count": 35,
697 "def weighted_choice(d):\n",
698 " \"\"\"Generate random item from a dictionary of item counts\n",
700 " target = random.uniform(0, sum(d.values()))\n",
702 " for (l, p) in d.items():\n",
704 " if cuml > target:\n",
708 "def random_english_letter():\n",
709 " \"\"\"Generate a random letter based on English letter counts\n",
711 " return weighted_choice(normalised_english_counts)\n",
713 "def random_wordsearch_letter():\n",
714 " \"\"\"Generate a random letter based on wordsearch letter counts\n",
716 " return weighted_choice(normalised_wordsearch_counts)"
721 "execution_count": 36,
729 "'aaaaaaaabcccddddeeeeeeeeeeeeeeefffggghhhhhiiiiiillllmnnnnnnoooooooooprrsssssssssssssttttttttuuuvwwwy'"
732 "execution_count": 36,
734 "output_type": "execute_result"
738 "cat(sorted(random_english_letter() for i in range(100)))"
743 "execution_count": 37,
751 "'aaaaaabcccddddddeeeeeeggggghhiiiiiiiiiiiiklllmmmmnnnnnnnnnnoooooooooppprrrrrrrrrssssssttttttuuuwwwyy'"
754 "execution_count": 37,
756 "output_type": "execute_result"
760 "cat(sorted(random_wordsearch_letter() for i in range(100)))"
765 "execution_count": 38,
776 "execution_count": 38,
778 "output_type": "execute_result"
782 "random_wordsearch_letter()"
787 "execution_count": 39,
793 "def pad_grid(g0):\n",
794 " grid = copy.deepcopy(g0)\n",
795 " w = len(grid[0])\n",
797 " for r in range(h):\n",
798 " for c in range(w):\n",
799 " if grid[r][c] == '.':\n",
800 " grid[r][c] = random_wordsearch_letter()\n",
806 "execution_count": 40,
813 "output_type": "stream",
815 "streittonkorsssatnal\n",
816 "tincturedswceedrlnuw\n",
817 "serutatsloyozmeieiot\n",
818 "baanfsollleoiasnlmar\n",
819 "ewblyhlfetlpsdyvbgye\n",
820 "aeistonoeilessassrgm\n",
821 "mlgtfitloioraeenwura\n",
822 "edaeiupiscwiamoygmor\n",
823 "demrnasbhcinsmiiapsk\n",
824 "epyakraedrsgmolsnile\n",
825 "slsgtuoloihireneonrd\n",
826 "tekisyassesdepeebeum\n",
827 "rtecigninretnincesfo\n",
828 "oiinsetseddbaggydsnd\n",
829 "ynnnsfapcfsebircsaui\n",
830 "egsonoitasiretupmocf\n",
831 "raioelartefactseawfy\n",
832 "speonsseilaogrwinosi\n",
833 "wrndfeyelidsegenerln\n",
834 "regicidesesopatxujrg\n"
839 "padded = pad_grid(g)\n",
840 "print(show_grid(padded))"
845 "execution_count": 41,
852 "output_type": "stream",
854 "..reittonk..ss......\n",
855 "tinctured.wcee.....w\n",
856 "serutats.oyozm....o.\n",
857 "b....s..l.eoia...m.r\n",
858 "e.b.y.lf..lpsd..bgye\n",
859 "a.ist.no..less.ssrgm\n",
860 "m.gtfi.lo.orae.n.ura\n",
861 "edaei..i.cwi.mo..mor\n",
862 "demrn..b..in.m...psk\n",
863 "epya...e..sgm....ile\n",
864 "slsg...l..hi.....nrd\n",
865 "tekisyassesdepeebeum\n",
866 "rtec.gninretni...sfo\n",
867 "oiinsetse..baggy.snd\n",
868 "ynn....p..sebircsaui\n",
869 "egs.noitasiretupmocf\n",
870 "r.....artefacts....y\n",
871 "s.....seilaog.winosi\n",
872 ".....eyelidsegener.n\n",
873 "regicidesesopatxuj.g\n"
878 "print(show_grid(g))"
883 "execution_count": 42,
891 "output_type": "stream",
893 "wombs (True, 1, 19, <Direction.downleft: 7>)\n",
894 "persimmons (True, 14, 7, <Direction.upright: 6>)\n",
895 "computerisation (True, 15, 18, <Direction.left: 1>)\n",
896 "ascribes (True, 14, 17, <Direction.left: 1>)\n",
897 "coopering (True, 1, 11, <Direction.down: 4>)\n",
898 "goalies (True, 17, 12, <Direction.left: 1>)\n",
899 "beamed (True, 3, 0, <Direction.down: 4>)\n",
900 "modifying (True, 11, 19, <Direction.down: 4>)\n",
901 "insets (True, 13, 2, <Direction.right: 2>)\n",
902 "cigarets (True, 12, 3, <Direction.up: 3>)\n",
903 "statures (True, 2, 7, <Direction.left: 1>)\n",
904 "libels (True, 6, 7, <Direction.down: 4>)\n",
905 "remarked (True, 3, 19, <Direction.down: 4>)\n",
906 "baggy (True, 13, 11, <Direction.right: 2>)\n",
907 "juxtaposes (True, 19, 17, <Direction.left: 1>)\n",
908 "mesdames (True, 7, 13, <Direction.up: 3>)\n",
909 "grumpiness (True, 4, 17, <Direction.down: 4>)\n",
910 "artefacts (True, 16, 6, <Direction.right: 2>)\n",
911 "skeins (True, 10, 2, <Direction.down: 4>)\n",
912 "assizes (True, 6, 12, <Direction.up: 3>)\n",
913 "inflow (True, 6, 5, <Direction.upright: 6>)\n",
914 "depleting (True, 7, 1, <Direction.down: 4>)\n",
915 "beeped (True, 11, 16, <Direction.left: 1>)\n",
916 "reneges (True, 18, 17, <Direction.left: 1>)\n",
917 "interning (True, 12, 13, <Direction.left: 1>)\n",
918 "yellowish (True, 2, 10, <Direction.down: 4>)\n",
919 "regicides (True, 19, 0, <Direction.right: 2>)\n",
920 "eyelids (True, 18, 5, <Direction.right: 2>)\n",
921 "cools (True, 7, 9, <Direction.upleft: 5>)\n",
922 "orgy (True, 7, 18, <Direction.up: 3>)\n",
923 "nifty (True, 8, 4, <Direction.up: 3>)\n",
924 "knottier (True, 0, 9, <Direction.left: 1>)\n",
925 "destroyers (True, 8, 0, <Direction.down: 4>)\n",
926 "unfurls (True, 14, 18, <Direction.up: 3>)\n",
927 "tinctured (True, 1, 0, <Direction.right: 2>)\n",
928 "bigamy (True, 4, 2, <Direction.down: 4>)\n",
929 "winos (True, 17, 14, <Direction.right: 2>)\n",
930 "essays (True, 11, 9, <Direction.left: 1>)\n"
936 " print(w, present(padded, w))"
941 "execution_count": 43,
947 "def decoys(grid, words, all_words, limit=60):\n",
948 " decoy_words = []\n",
949 " while len(words) + len(decoy_words) < limit:\n",
950 " d = random.choice(all_words)\n",
951 " if d not in words and not present(grid, d)[0]:\n",
952 " decoy_words += [d]\n",
953 " return decoy_words"
958 "execution_count": 45,
966 "['blindfolding',\n",
972 " 'psychologies',\n",
977 " 'accessioning',\n",
987 " 'misconstructions']"
990 "execution_count": 45,
992 "output_type": "execute_result"
996 "ds = decoys(padded, ws, ws_words)\n",
1001 "cell_type": "code",
1002 "execution_count": 46,
1010 "output_type": "stream",
1012 "wombs (True, 1, 19, <Direction.downleft: 7>)\n",
1013 "persimmons (True, 14, 7, <Direction.upright: 6>)\n",
1014 "computerisation (True, 15, 18, <Direction.left: 1>)\n",
1015 "ascribes (True, 14, 17, <Direction.left: 1>)\n",
1016 "coopering (True, 1, 11, <Direction.down: 4>)\n",
1017 "goalies (True, 17, 12, <Direction.left: 1>)\n",
1018 "beamed (True, 3, 0, <Direction.down: 4>)\n",
1019 "modifying (True, 11, 19, <Direction.down: 4>)\n",
1020 "insets (True, 13, 2, <Direction.right: 2>)\n",
1021 "cigarets (True, 12, 3, <Direction.up: 3>)\n",
1022 "statures (True, 2, 7, <Direction.left: 1>)\n",
1023 "libels (True, 6, 7, <Direction.down: 4>)\n",
1024 "remarked (True, 3, 19, <Direction.down: 4>)\n",
1025 "baggy (True, 13, 11, <Direction.right: 2>)\n",
1026 "juxtaposes (True, 19, 17, <Direction.left: 1>)\n",
1027 "mesdames (True, 7, 13, <Direction.up: 3>)\n",
1028 "grumpiness (True, 4, 17, <Direction.down: 4>)\n",
1029 "artefacts (True, 16, 6, <Direction.right: 2>)\n",
1030 "skeins (True, 10, 2, <Direction.down: 4>)\n",
1031 "assizes (True, 6, 12, <Direction.up: 3>)\n",
1032 "inflow (True, 6, 5, <Direction.upright: 6>)\n",
1033 "depleting (True, 7, 1, <Direction.down: 4>)\n",
1034 "beeped (True, 11, 16, <Direction.left: 1>)\n",
1035 "reneges (True, 18, 17, <Direction.left: 1>)\n",
1036 "interning (True, 12, 13, <Direction.left: 1>)\n",
1037 "yellowish (True, 2, 10, <Direction.down: 4>)\n",
1038 "regicides (True, 19, 0, <Direction.right: 2>)\n",
1039 "eyelids (True, 18, 5, <Direction.right: 2>)\n",
1040 "cools (True, 7, 9, <Direction.upleft: 5>)\n",
1041 "orgy (True, 7, 18, <Direction.up: 3>)\n",
1042 "nifty (True, 8, 4, <Direction.up: 3>)\n",
1043 "knottier (True, 0, 9, <Direction.left: 1>)\n",
1044 "destroyers (True, 8, 0, <Direction.down: 4>)\n",
1045 "unfurls (True, 14, 18, <Direction.up: 3>)\n",
1046 "tinctured (True, 1, 0, <Direction.right: 2>)\n",
1047 "bigamy (True, 4, 2, <Direction.down: 4>)\n",
1048 "winos (True, 17, 14, <Direction.right: 2>)\n",
1049 "essays (True, 11, 9, <Direction.left: 1>)\n",
1050 "blindfolding (False, 0, 0, <Direction.left: 1>)\n",
1051 "televised (False, 0, 0, <Direction.left: 1>)\n",
1052 "climaxed (False, 0, 0, <Direction.left: 1>)\n",
1053 "autumns (False, 0, 0, <Direction.left: 1>)\n",
1054 "aquaria (False, 0, 0, <Direction.left: 1>)\n",
1055 "bilks (False, 0, 0, <Direction.left: 1>)\n",
1056 "psychologies (False, 0, 0, <Direction.left: 1>)\n",
1057 "sparkled (False, 0, 0, <Direction.left: 1>)\n",
1058 "dorkiest (False, 0, 0, <Direction.left: 1>)\n",
1059 "corollas (False, 0, 0, <Direction.left: 1>)\n",
1060 "polygons (False, 0, 0, <Direction.left: 1>)\n",
1061 "accessioning (False, 0, 0, <Direction.left: 1>)\n",
1062 "bubbled (False, 0, 0, <Direction.left: 1>)\n",
1063 "astringency (False, 0, 0, <Direction.left: 1>)\n",
1064 "debunking (False, 0, 0, <Direction.left: 1>)\n",
1065 "cannery (False, 0, 0, <Direction.left: 1>)\n",
1066 "exhilarates (False, 0, 0, <Direction.left: 1>)\n",
1067 "overzealous (False, 0, 0, <Direction.left: 1>)\n",
1068 "primping (False, 0, 0, <Direction.left: 1>)\n",
1069 "geckos (False, 0, 0, <Direction.left: 1>)\n",
1070 "admiration (False, 0, 0, <Direction.left: 1>)\n",
1071 "misconstructions (False, 0, 0, <Direction.left: 1>)\n"
1076 "for w in ws + ds:\n",
1077 " print(w, present(padded, w))"
1081 "cell_type": "code",
1082 "execution_count": 47,
1089 "output_type": "stream",
1091 "tuiababblerssknalbft\n",
1092 "gnewerodeswskrowerif\n",
1093 "nballooningosfriedum\n",
1094 "iuebksidesaddlessldt\n",
1095 "mrncdbmnnyllasuaceet\n",
1096 "udiesnettirwtsohglli\n",
1097 "uepoeyremeenoyreveum\n",
1098 "cnuselitnegfatterbdp\n",
1099 "asslmulleveiadieneer\n",
1100 "visnmewsrelrsbtleddi\n",
1101 "crouchinghogetrzooms\n",
1102 "dstrihstaewseteaotoo\n",
1103 "vkssrdovulatesrldgon\n",
1104 "snnvengefullyuiawets\n",
1105 "uiofendelleuferrcosi\n",
1106 "ahsdenoixelpmocluitt\n",
1107 "vcdauthorisesnfsnenp\n",
1108 "eyoelmferociouslypng\n",
1109 "lngimmpauperisedtnon\n",
1110 "ytnthstnemecitnehhpc\n",
1111 "38 words added; 7 directions\n",
1112 "Present: abrades authorises babblers ballooning blanks causally chinks complexioned crouching deluded emery enticements erodes everyone fatter ferociously fireworks fried gentiles ghostwritten godsons imprisons mews ovulates owlets pauperised refuelled retracing sidesaddles suavely supine sweatshirts unburdens vacuuming vellum vengefully yeti zooms\n",
1113 "Decoys: chastened doodling ethnologists executrixes freelancing generously halfheartedness harries kinswoman mangles narrowly optimising oversimplifies polystyrene recounts riffing slicking smackers squashy thirsting tiebreakers unexampled\n"
1118 "g, ws = interesting_grid()\n",
1119 "p = pad_grid(g)\n",
1120 "ds = decoys(p, ws, ws_words)\n",
1121 "print(show_grid(p))\n",
1122 "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
1123 "print('Present:', wcat(sorted(ws)))\n",
1124 "print('Decoys:', wcat(sorted(ds)))"
1128 "cell_type": "code",
1129 "execution_count": 49,
1136 "output_type": "stream",
1162 "for i in range(20):\n",
1164 " g, ws = interesting_grid()\n",
1165 " p = pad_grid(g)\n",
1166 " ds = decoys(p, ws, ws_words)\n",
1167 " with open('wordsearch{:02}.txt'.format(i), 'w') as f:\n",
1168 " f.write('20x20\\n')\n",
1169 " f.write(show_grid(p))\n",
1170 " f.write('\\n')\n",
1171 " f.write(lcat(sorted(ws + ds)))\n",
1172 " with open('wordsearch-solution{:02}.txt'.format(i), 'w') as f:\n",
1173 " f.write('20x20\\n')\n",
1174 " f.write(show_grid(g))\n",
1175 " f.write('\\n')\n",
1176 " f.write(lcat(sorted(ws)) + '\\n\\n')\n",
1177 " f.write(lcat(sorted(ds)))"
1181 "cell_type": "code",
1182 "execution_count": null,
1192 "display_name": "Python 3",
1193 "language": "python",
1197 "codemirror_mode": {
1201 "file_extension": ".py",
1202 "mimetype": "text/x-python",
1204 "nbconvert_exporter": "python",
1205 "pygments_lexer": "ipython3",