Spelling bee

The Spelling Bee is a good way to waste a Sunday morning. Its rules are simple.

  1. There are seven letters: one primary letter and six secondary ones.
  2. The player has to use these letters to make words. A letter can be used more than once.
  3. Every word must be five letters or more.
  4. Every word must contain the primary letter.
  5. A valid word is worth one point. A valid word containing all seven letters is worth three points.

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.