4 "cell_type": "markdown",
8 "# Honeycomb letter puzzle\n",
9 "Solving the puzzle as posted on [FiveThirtyEight](https://fivethirtyeight.com/features/can-you-solve-the-vexing-vexillology/), also solved by [David Robinson](http://varianceexplained.org/r/honeycomb-puzzle/).\n"
14 "execution_count": 45,
20 "import collections\n",
21 "from dataclasses import dataclass\n",
40 "output_type": "execute_result"
44 "with open('enable1.txt') as f:\n",
45 " words = [line.strip() for line in f]"
55 "words = set(w for w in words \n",
57 " if len(frozenset(w)) <= 7\n",
75 "output_type": "execute_result"
79 "word_sets = collections.defaultdict(set)\n",
81 " letters = frozenset(w)\n",
82 " word_sets[letters].add(w)"
87 "execution_count": 11,
92 "@dataclass(frozen=True)\n",
93 "class Honeycomb():\n",
95 " letters: frozenset\n",
97 " def __repr__(self):\n",
98 " return f'{self.mandatory}|{\"\".join(sorted(self.letters - set(self.mandatory)))}'"
103 "execution_count": 13,
108 "def present(target, honeycomb):\n",
109 " return ( (honeycomb.mandatory in target) \n",
110 " and target.issubset(honeycomb.letters)\n",
116 "execution_count": 17,
121 "def score(present_set):\n",
123 " for w in word_sets[present_set]:\n",
124 " if len(w) == 4:\n",
127 " score += len(w)\n",
128 " if len(present_set) == 7:\n",
129 " score += len(word_sets[present_set]) * 7\n",
135 "execution_count": 22,
140 "def score_honeycomb(honeycomb):\n",
141 " return sum(sc for letters, sc in scored_sets.items() \n",
142 " # if honeycomb.mandatory in letters\n",
143 " # if letters.issubset(honeycomb.letters)\n",
144 " if present(letters, honeycomb)\n",
150 "execution_count": 30,
156 "output_type": "stream",
158 "pangram sets: 7986\n"
163 "pangram_sets = [s for s in word_sets.keys() if len(s) == 7 if 's' not in s]\n",
164 "print(\"pangram sets:\", len(pangram_sets))"
169 "execution_count": 31,
174 "with open('pangaram_words.txt', 'w') as f:\n",
175 " for s in pangram_sets:\n",
176 " for w in word_sets[s]:\n",
177 " f.write(f'{w}\\n')"
182 "execution_count": 32,
188 "output_type": "stream",
195 "# ps_honeycombs = []\n",
197 "# for ps in pangram_sets:\n",
198 "# for mand in ps:\n",
199 "# ps_honeycombs.append(Honeycomb(mandatory=mand, letters=ps))\n",
201 "ps_honeycombs = [Honeycomb(mandatory=mand, letters=ps) \n",
202 " for ps in pangram_sets\n",
203 " for mand in ps]\n",
204 "print(len(ps_honeycombs), \"honeycombs\")"
209 "execution_count": 38,
219 "execution_count": 38,
221 "output_type": "execute_result"
225 "partitioned_scored_sets = {l: {s: scored_sets[s] for s in scored_sets if l in s} \n",
226 " for l in string.ascii_lowercase}"
231 "execution_count": 39,
236 "def partitioned_score_honeycomb(honeycomb):\n",
237 " return sum(sc for letters, sc in partitioned_scored_sets[honeycomb.mandatory].items() \n",
238 " if letters.issubset(honeycomb.letters)\n",
244 "execution_count": 40,
250 "output_type": "stream",
260 "1min 25s ± 2.51 s per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
266 "# best_honyecomb = max(ps_honeycombs, key=partitioned_score_honeycomb)\n",
267 "# print(best_honyecomb, partitioned_score_honeycomb(best_honyecomb))"
272 "execution_count": 44,
273 "id": "0239b444-1240-4744-8547-c41367527785",
278 "output_type": "stream",
288 "5min 38s ± 4.58 s per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
294 "best_honyecomb = max(ps_honeycombs, key=score_honeycomb)\n",
295 "print(best_honyecomb, partitioned_score_honeycomb(best_honyecomb))"
300 "execution_count": 46,
301 "id": "7e4173b4-26a9-4198-b572-d57db321fe94",
303 "lines_to_next_cell": 2
308 "output_type": "stream",
310 " 1612136594 function calls in 589.284 seconds\n",
312 " Ordered by: standard name\n",
314 " ncalls tottime percall cumtime percall filename:lineno(function)\n",
315 " 55902 0.316 0.000 589.070 0.011 1101428662.py:1(score_honeycomb)\n",
316 " 1846420 257.034 0.000 588.167 0.000 1101428662.py:2(<genexpr>)\n",
317 "1210893222 276.103 0.000 331.132 0.000 1250517269.py:1(present)\n",
318 " 1 0.000 0.000 589.284 589.284 <string>:1(<module>)\n",
319 " 1 0.000 0.000 589.284 589.284 {built-in method builtins.exec}\n",
320 " 1 0.214 0.214 589.284 589.284 {built-in method builtins.max}\n",
321 " 55902 0.567 0.000 588.733 0.011 {built-in method builtins.sum}\n",
322 " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n",
323 "399229242 55.030 0.000 55.030 0.000 {method 'issubset' of 'frozenset' objects}\n",
324 " 55902 0.021 0.000 0.021 0.000 {method 'items' of 'dict' objects}\n",
331 "# cProfile.run('max(ps_honeycombs, key=score_honeycomb)')"
336 "execution_count": 47,
337 "id": "8f2de1b8-6a09-44eb-af7b-3e16c902859f",
339 "lines_to_next_cell": 2
344 "output_type": "stream",
346 " 401243372 function calls in 150.954 seconds\n",
348 " Ordered by: standard name\n",
350 " ncalls tottime percall cumtime percall filename:lineno(function)\n",
351 " 55902 0.226 0.000 150.835 0.003 346452243.py:1(partitioned_score_honeycomb)\n",
352 " 1846420 86.829 0.000 150.189 0.000 346452243.py:2(<genexpr>)\n",
353 " 1 0.000 0.000 150.954 150.954 <string>:1(<module>)\n",
354 " 1 0.000 0.000 150.954 150.954 {built-in method builtins.exec}\n",
355 " 1 0.119 0.119 150.954 150.954 {built-in method builtins.max}\n",
356 " 55902 0.407 0.000 150.596 0.003 {built-in method builtins.sum}\n",
357 " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n",
358 "399229242 63.360 0.000 63.360 0.000 {method 'issubset' of 'frozenset' objects}\n",
359 " 55902 0.013 0.000 0.013 0.000 {method 'items' of 'dict' objects}\n",
366 "# cProfile.run('max(ps_honeycombs, key=partitioned_score_honeycomb)')"
371 "execution_count": null,
372 "id": "4c3a5684-346b-4cf7-b238-391f9a6ba2dd",
380 "formats": "ipynb,py:light"
383 "display_name": "Python 3 (ipykernel)",
384 "language": "python",
392 "file_extension": ".py",
393 "mimetype": "text/x-python",
395 "nbconvert_exporter": "python",
396 "pygments_lexer": "ipython3",