The Spelling Bee is a good way to waste a Sunday morning. Its rules are simple.
Naturally, the puzzle is even more fun when you have to devise a cheating method for it. I wrote a bitwise solver in Go forever ago, but I'm trying it the J way today.
First I downloaded a dictionary file that already has proper nouns and words less than 5 letters long filtered out.
I then opened that file and read its lines to a boxed array.
X =: cutopen 1 !: 1 < 'dict'
3 {. X
┌─────┬────────┬────────┐
│aalii│aardvark│aardwolf│
└─────┴────────┴────────┘
I then specified the seven letters, with the primary letter as the first character in the string.
L =: 'ayenpmt'
C =: {. L
If a word is valid, then all its characters will be members of the set L
.
e.&L 'payment'
1 1 1 1 1 1 1
*/@e.&L 'payment'
1
*/@e.&L 'abeyance'
0
A word is also only valid if it contains the primary character C
.
C e. 'payment'
1
The primary filter against the dictionary is a monadic fork that returns 1 if both these criteria are met, and 0 otherwise.
(C&e. *. */@e.&L) 'payment'
1
This fork can be run on every row of X
, returning a truth mask of 1s and 0s that can be applied back to X
in order to return only the valid words. This new set is F
.
F =: (#~(C&e. *. */@e.&L)@>)~ X
3 {. F
┌──────┬─────┬─────┐
│aenean│amapa│ameen│
└──────┴─────┴─────┘
From the filtered set F
it is easy enough to derive a new truth mask A
of all words that contain all letters. Just count which nubs in F
have a length of 7.
A =: 7=#@~.@> F
A # F
┌───────┐
│payment│
└───────┘
"Payment" is the only one here.
Another monadic fork of A
and NOT A
mapped over F
and combined will give the full list of answers, with the three point values segregated at the bottom.
>((F#~-.) , #&F) A
aenean
amapa
ameen
amene
ament
amman
amtman
anama
anana
ananym
anapanapa
anapnea
anent
annat
annet
antenna
antennae
antennate
antetype
apatan
apnea
appay
appet
appete
appetent
ataman
atman
attempt
attent
atypy
eaten
emanant
emanate
empyema
enaena
enapt
enate
enema
entame
mamma
mammate
mammee
mammy
manatee
manent
maney
manna
mannan
manny
manta
mappy
matamata
matapan
matey
matta
matte
maynt
mayten
meant
meatman
meaty
metanym
metate
metatype
nanny
nappe
nappy
natant
natty
neaten
nenta
nepman
netman
paean
pament
pamment
pampean
panama
panman
pannam
panne
pantatype
panty
papane
papaya
papey
papmeat
pappy
patapat
paten
patent
patentee
patta
patte
pattee
patten
patty
pattypan
payee
payeny
peatman
peaty
penman
penna
pennae
pennant
pennate
penta
pentane
peteman
tammy
tampan
tanan
tannate
tapeman
tapen
tapet
tapete
tapnet
tappa
tappen
tappet
tatta
tatty
teaey
teaman
teamman
teammate
teatman
teaty
teetan
teman
tenant
tentamen
tentmate
tepetate
tetany
tmema
tympan
tympana
tympany
yamen
yampa
yappy
yetapa
payment
I'm pleased overall with the terseness (duh) and performance of this solution. J makes it a point to operate on full arrays in memory rather than streams, but this doesn't seem to matter too much for this puzzle.