4 # formats: ipynb,py:light
8 # format_version: '1.5'
9 # jupytext_version: 1.11.1
11 # display_name: Python 3 (ipykernel)
16 # # Honeycomb letter puzzle
17 # 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/).
22 from dataclasses
import dataclass
26 def only_letters(text
):
27 return ''.join([c
.lower() for c
in text
if c
in string
.ascii_letters
])
30 only_letters('Hell!o')
32 with
open('/usr/share/dict/british-english') as f
:
33 words
= [line
.rstrip() for line
in f
]
36 with
open('enable1.txt') as f
:
37 words
= [line
.rstrip() for line
in f
]
40 words
= set(only_letters(w
)
42 if len(only_letters(w
)) >= 4
43 if len(frozenset(only_letters(w
))) <= 7
48 word_sets
= collections
.defaultdict(set)
50 letters
= frozenset(w
)
51 word_sets
[letters
].add(w
)
54 word_sets
[frozenset('elephant')]
57 @dataclass(frozen
=True)
63 return f
'{self.mandatory}|{"".join(sorted(self.letters - set(self.mandatory)))}'
66 honeycomb
= Honeycomb(mandatory
='g', letters
=frozenset('apxmelg'))
70 def present(honeycomb
, target
):
71 return (honeycomb
.mandatory
in target
) and target
.issubset(honeycomb
.letters
)
74 present_sets
= [s
for s
in word_sets
if present(honeycomb
, s
)]
79 for s
in present_sets
:
83 def score(present_set
):
85 for w
in word_sets
[present_set
]:
90 if len(present_set
) == 7:
91 score
+= len(word_sets
[present_set
]) * 7
95 sum(score(present_set
) for present_set
in present_sets
)
97 set('megaplex') in words
99 scored_sets
= {s
: score(s
) for s
in word_sets
}
101 for s
in present_sets
:
102 print(s
, word_sets
[s
], score(s
), scored_sets
[s
])
105 def score_honeycomb(honeycomb
):
106 return sum(sc
for letters
, sc
in scored_sets
.items()
107 if honeycomb
.mandatory
in letters
108 if letters
.issubset(honeycomb
.letters
)
109 # if present(honeycomb, letters)
113 score_honeycomb(honeycomb
)
118 # for mand in 'abcde':
119 # remaining = set('abcde') - set(mand)
120 # for others in itertools.combinations(remaining, r=3):
121 # hcs.append(Honeycomb(mandatory=mand, letters=frozenset(others) | frozenset(mand)))
131 # for mand in string.ascii_lowercase:
132 # remaining = set(string.ascii_lowercase) - set(mand)
133 # for others in itertools.combinations(remaining, r=6):
134 # honeycombs.append(Honeycomb(mandatory=mand, letters=frozenset(others) | frozenset(mand)))
136 # print(len(honeycombs))
141 # candidate_letters = set(string.ascii_lowercase)
142 # candidate_letters.remove('s')
143 # candidate_letters = frozenset(candidate_letters)
145 # for mand in candidate_letters:
146 # remaining = candidate_letters - set(mand)
147 # for others in itertools.combinations(remaining, r=6):
148 # honeycombs.append(Honeycomb(mandatory=mand, letters=frozenset(others) | frozenset(mand)))
150 # print(len(honeycombs))
153 # [(h, score_honeycomb(h)) for h in honeycombs[:5]]
157 # max(honeycombs, key=score_honeycomb)
160 pangram_sets
= [s
for s
in word_sets
.keys() if len(s
) == 7 if 's' not in s
]
166 for ps
in pangram_sets
:
168 ps_honeycombs
.append(Honeycomb(mandatory
=mand
, letters
=ps
))
170 print(len(ps_honeycombs
))
174 # max(ps_honeycombs, key=score_honeycomb)
177 ## 1 a,e,g,i,n,r,t r 3898
178 ## 2 a,e,g,i,n,r,t n 3782
179 ## 3 a,e,g,i,n,r,t e 3769
182 score_honeycomb(Honeycomb('r', frozenset('aeginrt')))
184 score_honeycomb(Honeycomb('n', frozenset('aeginrtn')))
186 score_honeycomb(Honeycomb('e', frozenset('aeginrte')))
188 partitioned_scored_sets
= {l
: {s
: scored_sets
[s
] for s
in scored_sets
if l
in s
}
189 for l
in string
.ascii_lowercase
}
190 len(partitioned_scored_sets
)
193 def partitioned_score_honeycomb(honeycomb
):
194 return sum(sc
for letters
, sc
in partitioned_scored_sets
[honeycomb
.mandatory
].items()
195 if letters
.issubset(honeycomb
.letters
)
200 print(max(ps_honeycombs
, key
=partitioned_score_honeycomb
))
203 # partitioned_score_honeycomb(Honeycomb('a', 'abc'))
206 # max(len(partitioned_scored_sets[k]) for k in partitioned_scored_sets)