Jumble
March 1, 2019
Our algorithm is to sort the letters of the target, creating a signature, then read a dictionary, calculate the signature of each word in the dictionary, and compare:
(define (jumble target)
(with-input-from-file "words" (lambda ()
(let ((target (sort charlist target))))
(let loop ((word (read)))
(unless (eof-object? word)
(let ((signature (sort charlist (symbol->string word)))))
(if (equal? target signature) word (loop (read))))))))))
And here is the program in action:
> (jumble "lteade") elated
I wrote that program in less time than it took to solve the puzzle; I’m not sure what that says about me. You can run the program at https://ideone.com/jxf1Dc.
I was really happy to get this one right…. although I came up with an archaic one as there is also a solution starting with “d”…
my $x = lc join q(), grep { m{\S} } sort split //, join q(), @ARGV; open my $F,q(<),q(/usr/share/dict/british-english-insane); while(<$F>) { chomp; next unless $x eq lc join q(), sort split //; print "$_\n" }delate (verb)
Quick one in Ruby.
def jumble(word, dict) chars = word.downcase.chars.sort dict.select do |w| w.chomp! chars.size == w.size && chars == w.downcase.chars.sort end end # Dictionary words form macOS words = File.readlines("/usr/share/dict/words") puts jumble('LTEADE', words)Outputs
A Haskell version.
import Control.Monad (forM_) import Data.List (sort) import Data.Maybe (fromMaybe) import Data.Map (Map) import qualified Data.Map as M import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as TIO import System.Environment (getArgs) import Text.Printf (printf) type Dict = Map Text [Text] unjumble :: Dict -> Text -> [Text] unjumble dict letters = fromMaybe [] $ M.lookup (canon letters) dict unjumblePrint :: Dict -> Text -> IO () unjumblePrint dict letters = do let matches = unjumble dict letters printf "%s: %s\n" letters (T.unwords matches) canon :: Text -> Text canon = T.pack . sort . T.unpack . T.toLower dictionaryFrom :: FilePath -> IO Dict dictionaryFrom path = dictFrom . T.words <$> TIO.readFile path where dictFrom = M.fromListWith (++) . map letterSort letterSort word = (canon word, [word]) main :: IO () main = do dict <- dictionaryFrom "/usr/share/dict/words" args <- map T.pack <$> getArgs forM_ args $ unjumblePrint dictHas an option to specify what the word starts with.
def jumble(letters='lteade', startswith=''): from collections import Counter length = len(letters) letters = Counter(letters) prior = lambda w: w.startswith(startswith) is_length = lambda w: len(w) == length clean = lambda w: w.strip().lower() def is_valid(word): word = Counter(word) word.subtract(letters) return sum(map(lambda c: c > 0, word.values())) == 0 dictionary = open('/usr/share/dict/words') if len(startswith): dictionary = filter(prior, dictionary) return filter(is_valid, filter(is_length, map(clean, dictionary))) print(list(jumble('lteade', 'e'))) print(list(jumble('lteade', '')))Here’s a solution in Python.
from collections import Counter puzzle = 'LTEADE' with open('/usr/share/dict/words') as f: for line in f: word = line.strip() if Counter(word.upper()) == Counter(puzzle): print(word)Output:
Solution with gawk, posix awk doesn’t have asort, BYO to make it more portable.
#! /usr/bin/gawk -fjumble - solves a jumbled word puzzle
usage: jumble [-v puzzle="XXX"] [path/to/dictionary]
BEGIN {
IGNORECASE = 1
if( puzzle == "" ) puzzle = "LTEADE"
split(puzzle, puzzle_arr, "")
puzzle_len = asort(puzzle_arr)
}
{
if( length($0) != puzzle_len ) next
split($0, test_arr, "")
asort(test_arr)
for( i = 1 ; i <= puzzle_len ; i++ )
if( test_arr[i] != puzzle_arr[i] ) next
print FILENAME ": " $0
}
In action:
./jumble.awk -v puzzle="LTEADE" /usr/share/dict/*/usr/share/dict/american-english: elated
/usr/share/dict/british: elated
/usr/share/dict/british-english: elated
/usr/share/dict/catala: delate
/usr/share/dict/catalan: delate
/usr/share/dict/german: adelte
/usr/share/dict/german: dealte
/usr/share/dict/german: tadele
/usr/share/dict/ngerman: adelte
/usr/share/dict/ngerman: dealte
/usr/share/dict/ngerman: tadele
/usr/share/dict/usa: elated
/usr/share/dict/words: elated
[…] exercise was posted over at ProgrammingPraxis called […]
Klong version (#5)
:"Shuffle letters" :"" p::{[l]; l::x@<x; print(l); p2(l; 2)} :"If there is a larger # in sublist than the 1st # in sublist..." p2::{[ns]; :[0=""=ns::news((-y)#x); p2a(x; ns; y); p2b(x; y)]} :"Get print new list, and call p2 with it" p2a::{[l n]; n::(#x)-z; print(l::(n#x),y); p2(l; 2)} :"n++; If n<=length(list), p2(list; n)" p2b::{[n]; :[0=(n::y+1)>#x; p2(x;n); n::n]} :"Filter a list of number based upon given function" filter::{[func]; func::x; y@&func'y} :"Print word match" print::{:[0=.sys("grep -q ^",x,"$ /usr/share/dict/words"); .p(x); ""]} :"Return new sublist or ''" news::{[f f2 p s]; s::x; f::*s; f2::filter({x>f}; s); :[0=f2=""; news2(s; f2@<f2); ""]} :"Return new sublist" news2::{[f2 i p s s2]; s::x; f2::y; p::(s?f2@0)@0; i::-1; (*f2),s2@<s2::filter({x; i::i+1; 0=i=p}; s)}lteade:
elated
dbeia:
abide
groegj:
jogger
slenet:
nestle
nargo:
argon
groan
organ
“** Done **”