--- /dev/null
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import string\n",
+ "import re\n",
+ "import random\n",
+ "import collections\n",
+ "import copy\n",
+ "\n",
+ "from enum import Enum\n",
+ "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
+ " \n",
+ "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
+ " Direction.up: (-1, 0), Direction.down: (1, 0), \n",
+ " Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
+ " Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
+ "\n",
+ "cat = ''.join\n",
+ "wcat = ' '.join\n",
+ "lcat = '\\n'.join"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# all_words = [w.strip() for w in open('/usr/share/dict/british-english').readlines()\n",
+ "# if all(c in string.ascii_lowercase for c in w.strip())]\n",
+ "# words = [w for w in all_words\n",
+ "# if not any(w in w2 for w2 in all_words if w != w2)]\n",
+ "# open('wordsearch-words', 'w').write(lcat(words))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# ws_words = [w.strip() for w in open('wordsearch-words').readlines()\n",
+ "# if all(c in string.ascii_lowercase for c in w.strip())]\n",
+ "# ws_words[:10]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "ws_words = [w.strip() for w in open('/usr/share/dict/british-english').readlines()\n",
+ " if all(c in string.ascii_lowercase for c in w.strip())]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def empty_grid(w, h):\n",
+ " return [['.' for c in range(w)] for r in range(h)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def show_grid(grid):\n",
+ " return lcat(cat(r) for r in grid)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "..........\n",
+ "..........\n",
+ "..........\n",
+ "..........\n",
+ "..........\n",
+ "..........\n",
+ "..........\n",
+ "..........\n",
+ "..........\n",
+ "..........\n"
+ ]
+ }
+ ],
+ "source": [
+ "grid = empty_grid(10, 10)\n",
+ "print(show_grid(grid))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def indices(grid, r, c, l, d):\n",
+ " dr, dc = delta[d]\n",
+ " w = len(grid[0])\n",
+ " h = len(grid)\n",
+ " inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
+ " return [(i, j) for i, j in inds\n",
+ " if i >= 0\n",
+ " if j >= 0\n",
+ " if i < h\n",
+ " if j < w]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def gslice(grid, r, c, l, d):\n",
+ " return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def set_grid(grid, r, c, d, word):\n",
+ " for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
+ " grid[i][j] = l\n",
+ " return grid"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "..........\n",
+ "..........\n",
+ "...t......\n",
+ "....e.....\n",
+ ".....s....\n",
+ "......t...\n",
+ ".......w..\n",
+ "........o.\n",
+ ".........r\n",
+ "..........\n"
+ ]
+ }
+ ],
+ "source": [
+ "set_grid(grid, 2, 3, Direction.downright, 'testword')\n",
+ "print(show_grid(grid))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'..e.....'"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cat(gslice(grid, 3, 2, 15, Direction.right))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "re.match(cat(gslice(grid, 3, 2, 4, Direction.right)), 'keen')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "<_sre.SRE_Match object; span=(0, 3), match='kee'>"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "re.match(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "re.fullmatch(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "re.match(cat(gslice(grid, 3, 2, 4, Direction.right)), 'kine')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def could_add(grid, r, c, d, word):\n",
+ " s = gslice(grid, r, c, len(word), d)\n",
+ " return re.fullmatch(cat(s), word)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "could_add(grid, 3, 2, Direction.right, 'keen')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "could_add(grid, 3, 2, Direction.right, 'kine')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "<Direction.right: 2>"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "random.choice(list(Direction))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def fill_grid(grid, words, word_count, max_attempts=10000):\n",
+ " attempts = 0\n",
+ " added_words = []\n",
+ " w = len(grid[0])\n",
+ " h = len(grid)\n",
+ " while len(added_words) < word_count and attempts < max_attempts:\n",
+ " attempts += 1\n",
+ " r = random.randrange(w)\n",
+ " c = random.randrange(h)\n",
+ " word = random.choice(words)\n",
+ " d = random.choice(list(Direction))\n",
+ " if len(word) >=4 and not any(word in w2 for w2 in added_words) and could_add(grid, r, c, d, word):\n",
+ " set_grid(grid, r, c, d, word)\n",
+ " added_words += [word]\n",
+ " attempts = 0\n",
+ " return grid, added_words"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "40"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "g = empty_grid(20, 20)\n",
+ "g, ws = fill_grid(g, ws_words, 40)\n",
+ "len(ws)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "..pouchexecrate.....\n",
+ ".hazardous....t.wive\n",
+ "...sniradnam.aselcnu\n",
+ "s.weeklies.rnb......\n",
+ "e..lamenessse.o.....\n",
+ "i.tsallab..s.a.i....\n",
+ "tslim.......f.c.l...\n",
+ "iwheelbase...f.tges.\n",
+ "ed....llabhgihinirr.\n",
+ "dw.limbs..nj.bitev.s\n",
+ "te.wiltediu.ructs.e.\n",
+ "elsombretv.oqes..a..\n",
+ "ll..e..te.iela....m.\n",
+ "ie.a..un.lheleiretoc\n",
+ "ord..bi.scsp...kiths\n",
+ "ts.malcentilitren...\n",
+ "..i.e.sexetrov.stolb\n",
+ ".r.s...ruof....htrof\n",
+ "bgnihsirevopmi.....c\n",
+ "....graciousness....\n",
+ "40 words added\n",
+ "lameness impoverishing plasters wilted toilet forth coterie hazardous abutting chequing weeklies sombre execrate mastiffs boilers uncles centilitre mandarins wheelbase graciousness vortexes dwellers ballast limbs four tans highball wive broils beads mils reactive select deities shtik juveniles blots pouch brim coon\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(show_grid(g))\n",
+ "print(len(ws), 'words added')\n",
+ "print(wcat(ws))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def present(grid, word):\n",
+ " w = len(grid[0])\n",
+ " h = len(grid)\n",
+ " for r in range(h):\n",
+ " for c in range(w):\n",
+ " for d in Direction:\n",
+ " if cat(gslice(grid, r, c, len(word), d)) == word:\n",
+ " return True, r, c, d\n",
+ " return False, 0, 0, list(Direction)[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "lameness (True, 4, 3, <Direction.right: 2>)\n",
+ "impoverishing (True, 18, 13, <Direction.left: 1>)\n",
+ "plasters (True, 14, 11, <Direction.upright: 6>)\n",
+ "wilted (True, 10, 3, <Direction.right: 2>)\n",
+ "toilet (True, 15, 0, <Direction.up: 3>)\n",
+ "forth (True, 17, 19, <Direction.left: 1>)\n",
+ "coterie (True, 13, 19, <Direction.left: 1>)\n",
+ "hazardous (True, 1, 1, <Direction.right: 2>)\n",
+ "abutting (True, 15, 4, <Direction.upright: 6>)\n",
+ "chequing (True, 14, 9, <Direction.upright: 6>)\n",
+ "weeklies (True, 3, 2, <Direction.right: 2>)\n",
+ "sombre (True, 11, 2, <Direction.right: 2>)\n",
+ "execrate (True, 0, 7, <Direction.right: 2>)\n",
+ "mastiffs (True, 12, 18, <Direction.upleft: 5>)\n",
+ "boilers (True, 3, 13, <Direction.downright: 8>)\n",
+ "uncles (True, 2, 19, <Direction.left: 1>)\n",
+ "centilitre (True, 15, 6, <Direction.right: 2>)\n",
+ "mandarins (True, 2, 11, <Direction.left: 1>)\n",
+ "wheelbase (True, 7, 1, <Direction.right: 2>)\n",
+ "graciousness (True, 19, 4, <Direction.right: 2>)\n",
+ "vortexes (True, 16, 13, <Direction.left: 1>)\n",
+ "dwellers (True, 8, 1, <Direction.down: 4>)\n",
+ "ballast (True, 5, 8, <Direction.left: 1>)\n",
+ "limbs (True, 9, 3, <Direction.right: 2>)\n",
+ "four (True, 17, 10, <Direction.left: 1>)\n",
+ "tans (True, 1, 14, <Direction.downleft: 7>)\n",
+ "highball (True, 8, 13, <Direction.left: 1>)\n",
+ "wive (True, 1, 16, <Direction.right: 2>)\n",
+ "broils (True, 9, 13, <Direction.downleft: 7>)\n",
+ "beads (True, 11, 5, <Direction.downleft: 7>)\n",
+ "mils (True, 6, 4, <Direction.left: 1>)\n",
+ "reactive (True, 3, 11, <Direction.downright: 8>)\n",
+ "select (True, 14, 10, <Direction.upright: 6>)\n",
+ "deities (True, 9, 0, <Direction.up: 3>)\n",
+ "shtik (True, 14, 19, <Direction.left: 1>)\n",
+ "juveniles (True, 9, 11, <Direction.downleft: 7>)\n",
+ "blots (True, 16, 19, <Direction.left: 1>)\n",
+ "pouch (True, 0, 2, <Direction.right: 2>)\n",
+ "brim (True, 18, 0, <Direction.upright: 6>)\n",
+ "coon (True, 18, 19, <Direction.upleft: 5>)\n"
+ ]
+ }
+ ],
+ "source": [
+ "for w in ws:\n",
+ " print(w, present(g, w))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def interesting(grid, words, words_limit=40, direction_slack=1):\n",
+ " dirs = set(present(grid, w)[3] for w in words)\n",
+ " return len(words) > words_limit and len(dirs) + direction_slack >= len(delta)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 48,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "interesting(g, ws)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def interesting_grid(width=20, height=20, words_limit=40, direction_slack=1):\n",
+ " boring = True\n",
+ " while boring:\n",
+ " grid = empty_grid(width, height)\n",
+ " grid, words = fill_grid(grid, ws_words, 80)\n",
+ " boring = not interesting(grid, words, words_limit=words_limit, direction_slack=direction_slack)\n",
+ " return grid, words"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "dexawwt....ybossm..t\n",
+ "snaprhlukulele..o.er\n",
+ "...erioteb.hrevordla\n",
+ "..sivc..pr.tdekcahkp\n",
+ "atve..h.oiselapcy.cd\n",
+ "nesrehpargohtill.pue\n",
+ "n.leaveyis.smuguhhrt\n",
+ "eyhsifnt.r...aeesetc\n",
+ "xverbseebasedlritl.a\n",
+ ".r..k.wie..mdonaiaeg\n",
+ "..ac.nsof.admeeulsoo\n",
+ "g.opo.cmanaotpqiinmp\n",
+ "nc.us.a.lpnteaerdkiu\n",
+ "ionjoys.leirinioicns\n",
+ "wnkcent.skeracllkase\n",
+ "oab..erusopxeao.antt\n",
+ "dureifidimuhed.nskea\n",
+ "aga...capitols..scrl\n",
+ "h.v.sandblaster..i.i\n",
+ "s.e..sdratoelhitsn.d\n",
+ "61 words added; 8 directions\n",
+ "newscast kittenish cocks lithographers truckle leotards they exposure dehumidifier sandblaster alien paddle shadowing gondola wrest joys minster pales chairs fishy capitols based gums pheromones saki moiety waxed guano thriven dilate moray icons adman ukulele hacked rope rise clue acted nicknack spar verbs boss annex neck repeater befalls drover leave pans brave brigs opus live noun tail riot care hits quilt part\n"
+ ]
+ }
+ ],
+ "source": [
+ "g, ws = interesting_grid()\n",
+ "print(show_grid(g))\n",
+ "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
+ "print(wcat(ws))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def datafile(name, sep='\\t'):\n",
+ " \"\"\"Read key,value pairs from file.\n",
+ " \"\"\"\n",
+ " with open(name) as f:\n",
+ " for line in f:\n",
+ " splits = line.split(sep)\n",
+ " yield [splits[0], int(splits[1])]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def normalise(frequencies):\n",
+ " \"\"\"Scale a set of frequencies so they sum to one\n",
+ " \n",
+ " >>> sorted(normalise({1: 1, 2: 0}).items())\n",
+ " [(1, 1.0), (2, 0.0)]\n",
+ " >>> sorted(normalise({1: 1, 2: 1}).items())\n",
+ " [(1, 0.5), (2, 0.5)]\n",
+ " >>> sorted(normalise({1: 1, 2: 1, 3: 1}).items()) # doctest: +ELLIPSIS\n",
+ " [(1, 0.333...), (2, 0.333...), (3, 0.333...)]\n",
+ " >>> sorted(normalise({1: 1, 2: 2, 3: 1}).items())\n",
+ " [(1, 0.25), (2, 0.5), (3, 0.25)]\n",
+ " \"\"\"\n",
+ " length = sum(f for f in frequencies.values())\n",
+ " return collections.defaultdict(int, ((k, v / length) \n",
+ " for (k, v) in frequencies.items()))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "english_counts = collections.Counter(dict(datafile('count_1l.txt')))\n",
+ "normalised_english_counts = normalise(english_counts)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wordsearch_counts = collections.Counter(cat(ws_words))\n",
+ "normalised_wordsearch_counts = normalise(wordsearch_counts)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "normalised_wordsearch_counts = normalise(collections.Counter(normalised_wordsearch_counts) + collections.Counter({l: 0.05 for l in string.ascii_lowercase}))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def weighted_choice(d):\n",
+ " \"\"\"Generate random item from a dictionary of item counts\n",
+ " \"\"\"\n",
+ " target = random.uniform(0, sum(d.values()))\n",
+ " cuml = 0.0\n",
+ " for (l, p) in d.items():\n",
+ " cuml += p\n",
+ " if cuml > target:\n",
+ " return l\n",
+ " return None\n",
+ "\n",
+ "def random_english_letter():\n",
+ " \"\"\"Generate a random letter based on English letter counts\n",
+ " \"\"\"\n",
+ " return weighted_choice(normalised_english_counts)\n",
+ "\n",
+ "def random_wordsearch_letter():\n",
+ " \"\"\"Generate a random letter based on wordsearch letter counts\n",
+ " \"\"\"\n",
+ " return weighted_choice(normalised_wordsearch_counts)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'aaaaaabbccddeeeeeeeeeeeffggghhhhhhiiiiiiiiillllmmnnnnnnnooooooooooppppqrrrrrrrssstttttttttuuwyyyyyyz'"
+ ]
+ },
+ "execution_count": 36,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cat(sorted(random_english_letter() for i in range(100)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'aaaaaaaabbbccccddeeeeeeeeggghhhiiiiiiiijjkkllllnnnnoooooooooopppqqrrrrrssssssttttttuuuuvvwxxxxxyzzzz'"
+ ]
+ },
+ "execution_count": 37,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cat(sorted(random_wordsearch_letter() for i in range(100)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'x'"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "random_wordsearch_letter()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def pad_grid(g0):\n",
+ " grid = copy.deepcopy(g0)\n",
+ " w = len(grid[0])\n",
+ " h = len(grid)\n",
+ " for r in range(h):\n",
+ " for c in range(w):\n",
+ " if grid[r][c] == '.':\n",
+ " grid[r][c] = random_wordsearch_letter()\n",
+ " return grid"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "dexawwtmxepybossmezt\n",
+ "snaprhlukulelefaoder\n",
+ "ijreriotebahrevordla\n",
+ "jrsivcciprstdekcahkp\n",
+ "atvecshkoiselapcydcd\n",
+ "nesrehpargohtilljpue\n",
+ "nuleaveyisasmuguhhrt\n",
+ "eyhsifntzrmnsaeesetc\n",
+ "xverbseebasedlritlla\n",
+ "prcckzwiefamdonaiaeg\n",
+ "osacqnsofgadmeeulsoo\n",
+ "gdoporcmanaotpqiinmp\n",
+ "ncmusbaslpnteaerdkiu\n",
+ "ionjoyswleirinioicns\n",
+ "wnkcentcskeracllkase\n",
+ "oabsuerusopxeaodantt\n",
+ "dureifidimuhedgnskea\n",
+ "agagvccapitolsgyscrl\n",
+ "hkvgsandblasterdhihi\n",
+ "syenesdratoelhitsnod\n"
+ ]
+ }
+ ],
+ "source": [
+ "padded = pad_grid(g)\n",
+ "print(show_grid(padded))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "dexawwt....ybossm..t\n",
+ "snaprhlukulele..o.er\n",
+ "...erioteb.hrevordla\n",
+ "..sivc..pr.tdekcahkp\n",
+ "atve..h.oiselapcy.cd\n",
+ "nesrehpargohtill.pue\n",
+ "n.leaveyis.smuguhhrt\n",
+ "eyhsifnt.r...aeesetc\n",
+ "xverbseebasedlritl.a\n",
+ ".r..k.wie..mdonaiaeg\n",
+ "..ac.nsof.admeeulsoo\n",
+ "g.opo.cmanaotpqiinmp\n",
+ "nc.us.a.lpnteaerdkiu\n",
+ "ionjoys.leirinioicns\n",
+ "wnkcent.skeracllkase\n",
+ "oab..erusopxeao.antt\n",
+ "dureifidimuhed.nskea\n",
+ "aga...capitols..scrl\n",
+ "h.v.sandblaster..i.i\n",
+ "s.e..sdratoelhitsn.d\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(show_grid(g))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "newscast (True, 7, 6, <Direction.down: 4>)\n",
+ "kittenish (True, 14, 9, <Direction.upright: 6>)\n",
+ "cocks (True, 12, 1, <Direction.upright: 6>)\n",
+ "lithographers (True, 5, 14, <Direction.left: 1>)\n",
+ "truckle (True, 7, 18, <Direction.up: 3>)\n",
+ "leotards (True, 19, 12, <Direction.left: 1>)\n",
+ "they (True, 3, 11, <Direction.up: 3>)\n",
+ "exposure (True, 15, 12, <Direction.left: 1>)\n",
+ "dehumidifier (True, 16, 13, <Direction.left: 1>)\n",
+ "sandblaster (True, 18, 4, <Direction.right: 2>)\n",
+ "alien (True, 9, 17, <Direction.downleft: 7>)\n",
+ "paddle (True, 12, 9, <Direction.upright: 6>)\n",
+ "shadowing (True, 19, 0, <Direction.up: 3>)\n",
+ "gondola (True, 9, 19, <Direction.downleft: 7>)\n",
+ "wrest (True, 0, 5, <Direction.downleft: 7>)\n",
+ "joys (True, 13, 3, <Direction.right: 2>)\n",
+ "minster (True, 11, 18, <Direction.down: 4>)\n",
+ "pales (True, 4, 14, <Direction.left: 1>)\n",
+ "chairs (True, 3, 5, <Direction.downright: 8>)\n",
+ "fishy (True, 7, 5, <Direction.left: 1>)\n",
+ "capitols (True, 17, 6, <Direction.right: 2>)\n",
+ "based (True, 8, 8, <Direction.right: 2>)\n",
+ "gums (True, 6, 14, <Direction.left: 1>)\n",
+ "pheromones (True, 5, 17, <Direction.downleft: 7>)\n",
+ "saki (True, 16, 16, <Direction.up: 3>)\n",
+ "moiety (True, 11, 7, <Direction.up: 3>)\n",
+ "waxed (True, 0, 4, <Direction.left: 1>)\n",
+ "guano (True, 17, 1, <Direction.up: 3>)\n",
+ "thriven (True, 0, 6, <Direction.downleft: 7>)\n",
+ "dilate (True, 19, 19, <Direction.up: 3>)\n",
+ "moray (True, 0, 16, <Direction.down: 4>)\n",
+ "icons (True, 13, 12, <Direction.downright: 8>)\n",
+ "adman (True, 7, 13, <Direction.downleft: 7>)\n",
+ "ukulele (True, 1, 7, <Direction.right: 2>)\n",
+ "hacked (True, 3, 17, <Direction.left: 1>)\n",
+ "rope (True, 5, 8, <Direction.up: 3>)\n",
+ "rise (True, 12, 15, <Direction.upright: 6>)\n",
+ "clue (True, 4, 15, <Direction.down: 4>)\n",
+ "acted (True, 8, 19, <Direction.up: 3>)\n",
+ "nicknack (True, 19, 17, <Direction.up: 3>)\n",
+ "spar (True, 12, 4, <Direction.upleft: 5>)\n",
+ "verbs (True, 8, 1, <Direction.right: 2>)\n",
+ "boss (True, 0, 12, <Direction.right: 2>)\n",
+ "annex (True, 4, 0, <Direction.down: 4>)\n",
+ "neck (True, 14, 5, <Direction.left: 1>)\n",
+ "repeater (True, 13, 11, <Direction.upright: 6>)\n",
+ "befalls (True, 8, 8, <Direction.down: 4>)\n",
+ "drover (True, 2, 17, <Direction.left: 1>)\n",
+ "leave (True, 6, 2, <Direction.right: 2>)\n",
+ "pans (True, 1, 3, <Direction.left: 1>)\n",
+ "brave (True, 15, 2, <Direction.down: 4>)\n",
+ "brigs (True, 2, 9, <Direction.down: 4>)\n",
+ "opus (True, 10, 19, <Direction.down: 4>)\n",
+ "live (True, 1, 6, <Direction.downleft: 7>)\n",
+ "noun (True, 10, 5, <Direction.downleft: 7>)\n",
+ "tail (True, 11, 12, <Direction.downright: 8>)\n",
+ "riot (True, 2, 4, <Direction.right: 2>)\n",
+ "care (True, 14, 13, <Direction.left: 1>)\n",
+ "hits (True, 19, 13, <Direction.right: 2>)\n",
+ "quilt (True, 11, 14, <Direction.upright: 6>)\n",
+ "part (True, 3, 19, <Direction.up: 3>)\n"
+ ]
+ }
+ ],
+ "source": [
+ "for w in ws:\n",
+ " print(w, present(padded, w))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def decoys(grid, words, all_words, limit=100):\n",
+ " decoy_words = []\n",
+ " dlen_limit = max(len(w) for w in words)\n",
+ " while len(words) + len(decoy_words) < limit:\n",
+ " d = random.choice(all_words)\n",
+ " if d not in words and len(d) >= 4 and len(d) <= dlen_limit and not present(grid, d)[0]:\n",
+ " decoy_words += [d]\n",
+ " return decoy_words"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['friendship',\n",
+ " 'stepping',\n",
+ " 'featheriest',\n",
+ " 'thriftily',\n",
+ " 'mutilation',\n",
+ " 'nook',\n",
+ " 'clewing',\n",
+ " 'meditated',\n",
+ " 'gooier',\n",
+ " 'cripples',\n",
+ " 'ponderously',\n",
+ " 'roundelay',\n",
+ " 'curtailed',\n",
+ " 'redeemed',\n",
+ " 'perimeters',\n",
+ " 'harelips',\n",
+ " 'overcompensating',\n",
+ " 'rejoicings',\n",
+ " 'adobe',\n",
+ " 'decreasing',\n",
+ " 'interstices',\n",
+ " 'curd',\n",
+ " 'orientate',\n",
+ " 'blueberries',\n",
+ " 'juniors',\n",
+ " 'broadloom',\n",
+ " 'debarring',\n",
+ " 'chandeliers',\n",
+ " 'segues',\n",
+ " 'army',\n",
+ " 'snuck',\n",
+ " 'pugilistic',\n",
+ " 'snugs',\n",
+ " 'dexterity',\n",
+ " 'dallies',\n",
+ " 'curving',\n",
+ " 'newsletter',\n",
+ " 'torn',\n",
+ " 'beaching',\n",
+ " 'limit',\n",
+ " 'blackguards',\n",
+ " 'breezier',\n",
+ " 'reoccur',\n",
+ " 'cabins']"
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ds = decoys(padded, ws, ws_words)\n",
+ "ds"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "opted (True, 5, 7, <Direction.downright: 8>)\n",
+ "haywire (True, 8, 9, <Direction.downleft: 7>)\n",
+ "busting (True, 4, 17, <Direction.left: 1>)\n",
+ "succinct (True, 7, 17, <Direction.down: 4>)\n",
+ "institute (True, 16, 18, <Direction.up: 3>)\n",
+ "illicit (True, 13, 14, <Direction.left: 1>)\n",
+ "hypersensitivity (True, 16, 15, <Direction.left: 1>)\n",
+ "placement (True, 3, 11, <Direction.left: 1>)\n",
+ "bathrobe (True, 0, 5, <Direction.right: 2>)\n",
+ "inured (True, 4, 0, <Direction.right: 2>)\n",
+ "caveats (True, 3, 8, <Direction.downleft: 7>)\n",
+ "revisiting (True, 2, 11, <Direction.left: 1>)\n",
+ "pulp (True, 15, 11, <Direction.right: 2>)\n",
+ "teacup (True, 7, 16, <Direction.downleft: 7>)\n",
+ "threading (True, 18, 6, <Direction.right: 2>)\n",
+ "queered (True, 5, 13, <Direction.right: 2>)\n",
+ "parking (True, 6, 9, <Direction.right: 2>)\n",
+ "advent (True, 1, 11, <Direction.left: 1>)\n",
+ "chasuble (True, 19, 19, <Direction.left: 1>)\n",
+ "mosey (True, 7, 5, <Direction.downleft: 7>)\n",
+ "highboys (True, 19, 4, <Direction.right: 2>)\n",
+ "recharging (True, 18, 19, <Direction.up: 3>)\n",
+ "flue (True, 12, 2, <Direction.upright: 6>)\n",
+ "plywood (True, 3, 18, <Direction.left: 1>)\n",
+ "gluing (True, 12, 12, <Direction.upleft: 5>)\n",
+ "worrier (True, 1, 12, <Direction.right: 2>)\n",
+ "karma (True, 17, 9, <Direction.left: 1>)\n",
+ "peepers (True, 8, 7, <Direction.downleft: 7>)\n",
+ "vulnerable (True, 17, 10, <Direction.right: 2>)\n",
+ "boycott (True, 15, 1, <Direction.right: 2>)\n",
+ "rummy (True, 5, 4, <Direction.left: 1>)\n",
+ "tonic (True, 8, 13, <Direction.downleft: 7>)\n",
+ "children (True, 15, 0, <Direction.up: 3>)\n",
+ "reales (True, 6, 1, <Direction.right: 2>)\n",
+ "rectal (True, 7, 15, <Direction.down: 4>)\n",
+ "sledded (True, 14, 16, <Direction.up: 3>)\n",
+ "collocates (True, 14, 5, <Direction.right: 2>)\n",
+ "edict (True, 17, 4, <Direction.left: 1>)\n",
+ "captor (True, 14, 5, <Direction.upright: 6>)\n",
+ "amulet (True, 9, 4, <Direction.upright: 6>)\n",
+ "slipper (True, 2, 13, <Direction.right: 2>)\n",
+ "foot (True, 0, 0, <Direction.right: 2>)\n",
+ "chef (True, 14, 4, <Direction.upright: 6>)\n",
+ "goods (True, 6, 15, <Direction.right: 2>)\n",
+ "salter (True, 1, 5, <Direction.left: 1>)\n",
+ "crows (True, 18, 0, <Direction.right: 2>)\n",
+ "paeans (True, 12, 14, <Direction.up: 3>)\n",
+ "fences (True, 0, 18, <Direction.left: 1>)\n",
+ "iron (True, 5, 9, <Direction.right: 2>)\n",
+ "liras (True, 0, 19, <Direction.down: 4>)\n",
+ "stages (True, 19, 16, <Direction.up: 3>)\n",
+ "defer (True, 14, 2, <Direction.upright: 6>)\n",
+ "racy (True, 5, 4, <Direction.downleft: 7>)\n",
+ "gaps (True, 7, 11, <Direction.right: 2>)\n",
+ "aspen (True, 12, 10, <Direction.upleft: 5>)\n",
+ "rams (True, 6, 0, <Direction.downright: 8>)\n",
+ "friendship (False, 0, 0, <Direction.left: 1>)\n",
+ "stepping (False, 0, 0, <Direction.left: 1>)\n",
+ "featheriest (False, 0, 0, <Direction.left: 1>)\n",
+ "thriftily (False, 0, 0, <Direction.left: 1>)\n",
+ "mutilation (False, 0, 0, <Direction.left: 1>)\n",
+ "nook (False, 0, 0, <Direction.left: 1>)\n",
+ "clewing (False, 0, 0, <Direction.left: 1>)\n",
+ "meditated (False, 0, 0, <Direction.left: 1>)\n",
+ "gooier (False, 0, 0, <Direction.left: 1>)\n",
+ "cripples (False, 0, 0, <Direction.left: 1>)\n",
+ "ponderously (False, 0, 0, <Direction.left: 1>)\n",
+ "roundelay (False, 0, 0, <Direction.left: 1>)\n",
+ "curtailed (False, 0, 0, <Direction.left: 1>)\n",
+ "redeemed (False, 0, 0, <Direction.left: 1>)\n",
+ "perimeters (False, 0, 0, <Direction.left: 1>)\n",
+ "harelips (False, 0, 0, <Direction.left: 1>)\n",
+ "overcompensating (False, 0, 0, <Direction.left: 1>)\n",
+ "rejoicings (False, 0, 0, <Direction.left: 1>)\n",
+ "adobe (False, 0, 0, <Direction.left: 1>)\n",
+ "decreasing (False, 0, 0, <Direction.left: 1>)\n",
+ "interstices (False, 0, 0, <Direction.left: 1>)\n",
+ "curd (False, 0, 0, <Direction.left: 1>)\n",
+ "orientate (False, 0, 0, <Direction.left: 1>)\n",
+ "blueberries (False, 0, 0, <Direction.left: 1>)\n",
+ "juniors (False, 0, 0, <Direction.left: 1>)\n",
+ "broadloom (False, 0, 0, <Direction.left: 1>)\n",
+ "debarring (False, 0, 0, <Direction.left: 1>)\n",
+ "chandeliers (False, 0, 0, <Direction.left: 1>)\n",
+ "segues (False, 0, 0, <Direction.left: 1>)\n",
+ "army (False, 0, 0, <Direction.left: 1>)\n",
+ "snuck (False, 0, 0, <Direction.left: 1>)\n",
+ "pugilistic (False, 0, 0, <Direction.left: 1>)\n",
+ "snugs (False, 0, 0, <Direction.left: 1>)\n",
+ "dexterity (False, 0, 0, <Direction.left: 1>)\n",
+ "dallies (False, 0, 0, <Direction.left: 1>)\n",
+ "curving (False, 0, 0, <Direction.left: 1>)\n",
+ "newsletter (False, 0, 0, <Direction.left: 1>)\n",
+ "torn (False, 0, 0, <Direction.left: 1>)\n",
+ "beaching (False, 0, 0, <Direction.left: 1>)\n",
+ "limit (False, 0, 0, <Direction.left: 1>)\n",
+ "blackguards (False, 0, 0, <Direction.left: 1>)\n",
+ "breezier (False, 0, 0, <Direction.left: 1>)\n",
+ "reoccur (False, 0, 0, <Direction.left: 1>)\n",
+ "cabins (False, 0, 0, <Direction.left: 1>)\n"
+ ]
+ }
+ ],
+ "source": [
+ "for w in ws + ds:\n",
+ " print(w, present(padded, w))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "s.esevresed...dwhims\n",
+ "e.tbk..vapourse.bn.d\n",
+ "h.ificembracesnslo.e\n",
+ "ctr.egukiwic..ddui.r\n",
+ "inor.dwh.rips.rrftsa\n",
+ "reue.eeisrar.tiefiyl\n",
+ "mmli.mgrg.muarth.slc\n",
+ "ieft.un.a.bnbuemdole\n",
+ "nn.nesimrliertseepad\n",
+ "ei.imeloeccdeh.epob.\n",
+ "dfsaprlrio.saf.smri.\n",
+ "cnpdt.ofrn.usu..ap.h\n",
+ "oom.ispeccgntlpew.sa\n",
+ "tcu.e.l.lu.eda.vsgin\n",
+ "e.bdsb.oarrmneloplsg\n",
+ "r.olaetrleromrkr.isa\n",
+ "ibatnhd.nlpoaeic.bir\n",
+ "eesiee.i.luepno.o.e.\n",
+ "snt.d.o.y.pcte.p.mr.\n",
+ "u....jtoquesylduol..\n",
+ "sfesevresedpzcdwhims\n",
+ "eotbkvgvapoursehbnyd\n",
+ "hiificembracesnslone\n",
+ "ctrnegukiwicurdduivr\n",
+ "inorydwhrripscrrftsa\n",
+ "reueleeisrarvtiefiyl\n",
+ "mmlinmgrgzmuarthgslc\n",
+ "ieftuunyanbnbuemdole\n",
+ "nncnesimrliertseepad\n",
+ "eirimeloeccdehzepobm\n",
+ "dfsaprlrioisafesmriq\n",
+ "cnpdtsofrnausuodapxh\n",
+ "oomlispeccgntlpewasa\n",
+ "tcuaehlzluledakvsgin\n",
+ "eibdsbeoarrmneloplsg\n",
+ "rbolaetrleromrkrnisa\n",
+ "ibatnhdtnlpoaeicibir\n",
+ "eesieerimluepnoholey\n",
+ "sntadvoaycpctespsmro\n",
+ "uamapjtoquesylduoldp\n",
+ "56 words added; 8 directions\n",
+ "Present: abreast bigwig bluff bodes bumps clothe concur confinement coteries crier cull daintier declared dendrites denim deserves embraces empties federal fluorite from glib guarded hangar herds iambic joiner kiwi loudly menus mocked panoply pearl poem polling prints proposition pruned resume rices riches rips roped rove seal seem shucks sissier swamped syllabi tine toque truthful unstabler vapours whims\n",
+ "Decoys: abrasions adapters aimlessness alkali awakens blowing burnouses burped cattily coal commences confusion contrivance crudest curies depravity distribute diva emigrate emulsion giveaway hangman house lifeboats maze middy mines mystified obtain organic parsons postulate prefixes pretenders razors scone sloes spuds straight subtleties systematise turncoats unpacked waivers\n"
+ ]
+ }
+ ],
+ "source": [
+ "g, ws = interesting_grid()\n",
+ "p = pad_grid(g)\n",
+ "ds = decoys(p, ws, ws_words)\n",
+ "print(show_grid(g))\n",
+ "print(show_grid(p))\n",
+ "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
+ "print('Present:', wcat(sorted(ws)))\n",
+ "print('Decoys:', wcat(sorted(ds)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "...p.mown.\n",
+ ".sdse..ee.\n",
+ ".e.elad.cr\n",
+ "pi.dtir.ah\n",
+ "rzsiwovspu\n",
+ "oawh.kieab\n",
+ "brow.c.rda\n",
+ "ecnotops.r\n",
+ "d.kc.d...b\n",
+ ".staple...\n",
+ "\n",
+ "fhjpamownq\n",
+ "wsdseuqeev\n",
+ "ieaeladhcr\n",
+ "piedtiriah\n",
+ "rzsiwovspu\n",
+ "oawhakieab\n",
+ "browpcfrda\n",
+ "ecnotopssr\n",
+ "dikchdnpnb\n",
+ "bstapleokr\n",
+ "14 words added; 6 directions\n",
+ "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
+ "Decoys: adapting bombing boor brick cackles carnal casino chaplets chump coaster coccyxes coddle collies creels crumbled cunt curds curled curlier deepen demeanor dicier dowses ensuing faddish fest fickler foaming gambol garoting gliding gristle grunts guts ibex impugns instants kielbasy lanyard loamier lugs market meanly minuend misprint mitts molested moonshot mucking oaks olives orgasmic pastrami perfect proceed puckered quashed refined regards retraces revel ridges ringlet scoff shinier siren solaria sprain sunder sunup tamped tapes thirds throw tiller times trains tranquil transfix typesets uric wariness welts whimsy winced winced\n"
+ ]
+ }
+ ],
+ "source": [
+ "g, ws = interesting_grid(width=10, height=10, words_limit=5, direction_slack=6)\n",
+ "p = pad_grid(g)\n",
+ "ds = decoys(p, ws, ws_words)\n",
+ "print(show_grid(g))\n",
+ "print()\n",
+ "print(show_grid(p))\n",
+ "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
+ "print('Present:', wcat(sorted(ws)))\n",
+ "print('Decoys:', wcat(sorted(ds)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 98,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['fickler',\n",
+ " 'adapting',\n",
+ " 'chump',\n",
+ " 'foaming',\n",
+ " 'molested',\n",
+ " 'carnal',\n",
+ " 'crumbled',\n",
+ " 'guts',\n",
+ " 'minuend',\n",
+ " 'bombing',\n",
+ " 'winced',\n",
+ " 'coccyxes',\n",
+ " 'solaria',\n",
+ " 'shinier',\n",
+ " 'cackles']"
+ ]
+ },
+ "execution_count": 98,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ds_original = ['regards', 'perfect', 'instants', 'refined', 'coddle', 'fickler', 'gambol', 'misprint', 'tapes', 'impugns', 'moonshot', 'chump', 'brick', 'siren', 'faddish', 'winced', 'kielbasy', 'market', 'puckered', 'trains', 'welts', 'cackles', 'foaming', 'proceed', 'gliding', 'guts', 'uric', 'oaks', 'molested', 'curled', 'boor', 'solaria', 'gristle', 'bombing', 'loamier', 'ensuing', 'cunt', 'sunder', 'revel', 'coaster', 'grunts', 'mucking', 'typesets', 'carnal', 'whimsy', 'scoff', 'coccyxes', 'meanly', 'sprain', 'minuend', 'ringlet', 'fest', 'winced', 'shinier', 'dicier', 'thirds', 'olives', 'garoting', 'pastrami', 'tranquil', 'tamped', 'sunup', 'crumbled', 'throw', 'ridges', 'chaplets', 'curlier', 'lugs', 'collies', 'adapting', 'demeanor', 'deepen', 'lanyard', 'tiller', 'transfix', 'wariness', 'times', 'mitts', 'dowses', 'creels', 'curds', 'quashed', 'orgasmic', 'ibex', 'retraces', 'casino']\n",
+ "ds = random.sample(ds_original, 15)\n",
+ "ds"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 89,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['regards',\n",
+ " 'perfect',\n",
+ " 'instants',\n",
+ " 'refined',\n",
+ " 'coddle',\n",
+ " 'fickler',\n",
+ " 'gambol',\n",
+ " 'misprint',\n",
+ " 'tapes',\n",
+ " 'impugns',\n",
+ " 'moonshot',\n",
+ " 'chump',\n",
+ " 'brick',\n",
+ " 'siren',\n",
+ " 'faddish',\n",
+ " 'winced',\n",
+ " 'kielbasy',\n",
+ " 'market',\n",
+ " 'puckered',\n",
+ " 'trains',\n",
+ " 'welts',\n",
+ " 'cackles',\n",
+ " 'foaming',\n",
+ " 'proceed',\n",
+ " 'gliding',\n",
+ " 'guts',\n",
+ " 'uric',\n",
+ " 'oaks',\n",
+ " 'molested',\n",
+ " 'curled',\n",
+ " 'boor',\n",
+ " 'solaria',\n",
+ " 'gristle',\n",
+ " 'bombing',\n",
+ " 'loamier',\n",
+ " 'ensuing',\n",
+ " 'cunt',\n",
+ " 'sunder',\n",
+ " 'revel',\n",
+ " 'coaster',\n",
+ " 'grunts',\n",
+ " 'mucking',\n",
+ " 'typesets',\n",
+ " 'carnal',\n",
+ " 'whimsy',\n",
+ " 'scoff',\n",
+ " 'coccyxes',\n",
+ " 'meanly',\n",
+ " 'sprain',\n",
+ " 'minuend',\n",
+ " 'ringlet',\n",
+ " 'fest',\n",
+ " 'winced',\n",
+ " 'shinier',\n",
+ " 'dicier',\n",
+ " 'thirds',\n",
+ " 'olives',\n",
+ " 'garoting',\n",
+ " 'pastrami',\n",
+ " 'tranquil',\n",
+ " 'tamped',\n",
+ " 'sunup',\n",
+ " 'crumbled',\n",
+ " 'throw',\n",
+ " 'ridges',\n",
+ " 'chaplets',\n",
+ " 'curlier',\n",
+ " 'lugs',\n",
+ " 'collies',\n",
+ " 'adapting',\n",
+ " 'demeanor',\n",
+ " 'deepen',\n",
+ " 'lanyard',\n",
+ " 'tiller',\n",
+ " 'transfix',\n",
+ " 'wariness',\n",
+ " 'times',\n",
+ " 'mitts',\n",
+ " 'dowses',\n",
+ " 'creels',\n",
+ " 'curds',\n",
+ " 'quashed',\n",
+ " 'orgasmic',\n",
+ " 'ibex',\n",
+ " 'retraces',\n",
+ " 'casino']"
+ ]
+ },
+ "execution_count": 89,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ds_original"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 99,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "grid = [['.', '.', '.', 'p', '.', 'm', 'o', 'w', 'n', '.'], ['.', 's', 'd', 's', 'e', '.', '.', 'e', 'e', '.'], ['.', 'e', '.', 'e', 'l', 'a', 'd', '.', 'c', 'r'], ['p', 'i', '.', 'd', 't', 'i', 'r', '.', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', '.', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', '.', 'c', '.', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', '.', 'r'], ['d', '.', 'k', 'c', '.', 'd', '.', '.', '.', 'b'], ['.', 's', 't', 'a', 'p', 'l', 'e', '.', '.', '.']]\n",
+ "padded_grid = [['f', 'h', 'j', 'p', 'a', 'm', 'o', 'w', 'n', 'q'], ['w', 's', 'd', 's', 'e', 'u', 'q', 'e', 'e', 'v'], ['i', 'e', 'a', 'e', 'l', 'a', 'd', 'h', 'c', 'r'], ['p', 'i', 'e', 'd', 't', 'i', 'r', 'i', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', 'a', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', 'p', 'c', 'f', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', 's', 'r'], ['d', 'i', 'k', 'c', 'h', 'd', 'n', 'p', 'n', 'b'], ['b', 's', 't', 'a', 'p', 'l', 'e', 'o', 'k', 'r']]\n",
+ "present_words = ['probed', 'staple', 'rioted', 'cowhides', 'tops', 'knows', 'lived', 'rhubarb', 'crazies', 'dock', 'apace', 'mown', 'pears', 'wide']\n",
+ "decoy_words = ['fickler', 'adapting', 'chump', 'foaming', 'molested', 'carnal', 'crumbled', 'guts', 'minuend', 'bombing', 'winced', 'coccyxes', 'solaria', 'shinier', 'cackles']\n",
+ "Directions: [('probed', '`(True, 3, 0, <Direction.down: 4>)`'), ('staple', '`(True, 9, 1, <Direction.right: 2>)`'), ('rioted', '`(True, 6, 7, <Direction.upleft: 5>)`'), ('cowhides', '`(True, 8, 3, <Direction.up: 3>)`'), ('tops', '`(True, 7, 4, <Direction.right: 2>)`'), ('knows', '`(True, 8, 2, <Direction.up: 3>)`'), ('lived', '`(True, 2, 4, <Direction.downright: 8>)`'), ('rhubarb', '`(True, 2, 9, <Direction.down: 4>)`'), ('crazies', '`(True, 7, 1, <Direction.up: 3>)`'), ('dock', '`(True, 8, 5, <Direction.up: 3>)`'), ('apace', '`(True, 5, 8, <Direction.up: 3>)`'), ('mown', '`(True, 0, 5, <Direction.right: 2>)`'), ('pears', '`(True, 0, 3, <Direction.downright: 8>)`'), ('wide', '`(True, 4, 4, <Direction.upright: 6>)`')]\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('grid = ', g)\n",
+ "print('padded_grid = ', p)\n",
+ "print('present_words = ', ws)\n",
+ "print('decoy_words = ', ds)\n",
+ "print('Directions: ', [(w, '`' + str(present(g, w)) + '`') for w in ws])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 100,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "# with open('example-wordsearch.txt', 'w') as f:\n",
+ "# f.write('10x10\\n')\n",
+ "# f.write(show_grid(p))\n",
+ "# f.write('\\n')\n",
+ "# f.write(lcat(sorted(ws + ds)))\n",
+ "# with open('exmaple-wordsearch-solution.txt', 'w') as f:\n",
+ "# f.write('10x10\\n')\n",
+ "# f.write(show_grid(g))\n",
+ "# f.write('\\n')\n",
+ "# f.write(lcat(sorted(ws)) + '\\n\\n')\n",
+ "# f.write(lcat(sorted(ds)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "probed 3 0 6 Direction.down [(3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0)]\n",
+ "staple 9 1 6 Direction.right [(9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)]\n",
+ "rioted 6 7 6 Direction.upleft [(6, 7), (5, 6), (4, 5), (3, 4), (2, 3), (1, 2)]\n",
+ "cowhides 8 3 8 Direction.up [(8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3)]\n",
+ "tops 7 4 4 Direction.right [(7, 4), (7, 5), (7, 6), (7, 7)]\n",
+ "knows 8 2 5 Direction.up [(8, 2), (7, 2), (6, 2), (5, 2), (4, 2)]\n",
+ "lived 2 4 5 Direction.downright [(2, 4), (3, 5), (4, 6), (5, 7), (6, 8)]\n",
+ "rhubarb 2 9 7 Direction.down [(2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9)]\n",
+ "crazies 7 1 7 Direction.up [(7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)]\n",
+ "dock 8 5 4 Direction.up [(8, 5), (7, 5), (6, 5), (5, 5)]\n",
+ "apace 5 8 5 Direction.up [(5, 8), (4, 8), (3, 8), (2, 8), (1, 8)]\n",
+ "mown 0 5 4 Direction.right [(0, 5), (0, 6), (0, 7), (0, 8)]\n",
+ "pears 0 3 5 Direction.downright [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]\n",
+ "wide 4 4 4 Direction.upright [(4, 4), (3, 5), (2, 6), (1, 7)]\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "[(7, 5), (2, 3), (3, 5)]"
+ ]
+ },
+ "execution_count": 77,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cts = collections.Counter()\n",
+ "for w in ws:\n",
+ " _, r, c, d = present(g, w)\n",
+ " inds = indices(g, r, c, len(w), d)\n",
+ " for i in inds:\n",
+ " cts[i] += 1\n",
+ " print(w, r, c, len(w), d, inds)\n",
+ "[i for i in cts if cts[i] > 1]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 143,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "0\n",
+ "1\n",
+ "2\n",
+ "3\n",
+ "4\n",
+ "5\n",
+ "6\n",
+ "7\n",
+ "8\n",
+ "9\n",
+ "10\n",
+ "11\n",
+ "12\n",
+ "13\n",
+ "14\n",
+ "15\n",
+ "16\n",
+ "17\n",
+ "18\n",
+ "19\n",
+ "20\n",
+ "21\n",
+ "22\n",
+ "23\n",
+ "24\n",
+ "25\n",
+ "26\n",
+ "27\n",
+ "28\n",
+ "29\n",
+ "30\n",
+ "31\n",
+ "32\n",
+ "33\n",
+ "34\n",
+ "35\n",
+ "36\n",
+ "37\n",
+ "38\n",
+ "39\n",
+ "40\n",
+ "41\n",
+ "42\n",
+ "43\n",
+ "44\n",
+ "45\n",
+ "46\n",
+ "47\n",
+ "48\n",
+ "49\n",
+ "50\n",
+ "51\n",
+ "52\n",
+ "53\n",
+ "54\n",
+ "55\n",
+ "56\n",
+ "57\n",
+ "58\n",
+ "59\n",
+ "60\n",
+ "61\n",
+ "62\n",
+ "63\n",
+ "64\n",
+ "65\n",
+ "66\n",
+ "67\n",
+ "68\n",
+ "69\n",
+ "70\n",
+ "71\n",
+ "72\n",
+ "73\n",
+ "74\n",
+ "75\n",
+ "76\n",
+ "77\n",
+ "78\n",
+ "79\n",
+ "80\n",
+ "81\n",
+ "82\n",
+ "83\n",
+ "84\n",
+ "85\n",
+ "86\n",
+ "87\n",
+ "88\n",
+ "89\n",
+ "90\n",
+ "91\n",
+ "92\n",
+ "93\n",
+ "94\n",
+ "95\n",
+ "96\n",
+ "97\n",
+ "98\n",
+ "99\n"
+ ]
+ }
+ ],
+ "source": [
+ "# for i in range(100):\n",
+ "# print(i)\n",
+ "# g, ws = interesting_grid()\n",
+ "# p = pad_grid(g)\n",
+ "# ds = decoys(p, ws, ws_words)\n",
+ "# with open('wordsearch{:02}.txt'.format(i), 'w') as f:\n",
+ "# f.write('20x20\\n')\n",
+ "# f.write(show_grid(p))\n",
+ "# f.write('\\n')\n",
+ "# f.write(lcat(sorted(ws + ds)))\n",
+ "# with open('wordsearch-solution{:02}.txt'.format(i), 'w') as f:\n",
+ "# f.write('20x20\\n')\n",
+ "# f.write(show_grid(g))\n",
+ "# f.write('\\n')\n",
+ "# f.write(lcat(sorted(ws)) + '\\n\\n')\n",
+ "# f.write(lcat(sorted(ds)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.5.2+"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}