/* * Richard A. DeVenezia * Oct 2004 * Oct 2005 Add comments */ dm 'clear log' log; /** / %*------------------------------------------------------------------- %* Bookworm Deluxe (www.popcap.com) has a dictionary %; data sasuser.bookworm_dictionary (label='www.popcap.com'); index = 0; length word entry $50; do until (end); infile "C:\Opt\games\pop\BookWorm Deluxe\wordlist.txt" end=end; input entry; pl = verify (entry, '0123456789'); if pl > 1 then index = input (substr(entry,1,pl-1), 4.); substr (word,index+1) = substr (entry,pl); output; end; word = 'a'; output; word = 'i'; output; keep word; run; %*------------------------------------------------------------------- %* Source forge has a couple of dictionaries %* - http://sourceforge.net/project/showfiles.php?group_id=10079&package_id=9919 %* Download %* - http://prdownloads.sourceforge.net/wordlist/agid-4.zip?download %; %let userdir = %sysget (USERPROFILE); data _null_; length word $25 pos $10; declare hash words (ordered:'A'); words.defineKey ('word'); words.defineData ('word'); words.defineDone (); do while (not end); infile "&userdir.\My Documents\dictionaries\infl.txt" dlm=' ,|' missover end=end; input word pos @; do until (word=''); word = compress (word,'~ &maxlen %then %let maxlen = &&len&n; %let n = %eval (&n+1); %end; %* number of words in answer; %let n = %eval (&n-1); %* number of letters in answer; %let L = %length (%sysfunc(compress(&answer,%str( )))); data _null_; length %do i = 1 %to &N; word&i $&&len&i %end; ; * hash for dictionary of words; declare hash dict (); dict.defineKey ('word'); dict.defineDone (); length _1 $1; %do i = 2 %to %eval(&maxlen-1); length _&i $&i; * hash for dictionary of letter sequences ; declare hash dict&i (); dict&i..defineKey ("_&i"); dict&i..defineData("_&i"); dict&i..defineDone (); %end; %do i = 1 %to %eval(&n-1); * hash for word paths traversed, will be _NEW_d later; declare hash path&i (); path&i..defineKey ("_1"); path&i..defineDone(); %end; * hash for solutions; declare hash soln (ordered:'a'); soln.defineKey ( %let comma=; %do i = 1 %to &n; &comma "word&i" %let comma=,; %end; ); soln.defineData ( %let comma=; %do i = 1 %to &n; &comma "word&i" %let comma=,; %end; , "_A", "_B", "_C", "_D"); soln.defineDone (); length word $12 ; * populate dictionaries; do until (end_dict); set &dictionary (where=(length(word) in (-1 &wordlens))) end=end_dict; word = lowcase(word); * add word to dictionary hash; if dict.find() eq 0 then continue; dict.add(); _ndict0+1; * add word parts to sub word dictionary hashes; %do i = 2 %to %eval(&maxlen-1); do i = 1 to length(word)-&i+1; _&i = substr(word,i,&i); if dict&i..find() eq 0 then continue; dict&i..add(); _ndict&i + 1; end; %end; end; put (_ndict:)(=/); array L_0_ [&L] $1; * letter pool; array i_0_ [1]; * permutation indices, word 0; array circles [4] $6 a b c d; * add letters to letter pool; do until (end); set pool end=end; ix = 1; do i = 1 to dim(circles); do j = 1 to length (circles[i]); L_0_ [ix] = substr (circles[i],j,1); ix + 1; end; end; * show what is being searched; put _a _b _c _d '-> ' a b c d ; * reset path hashes; %do i = 1 %to %eval(&n-1); path&i..delete(); path&i = _new_ hash(); path&i..defineKey ( %let comma=; %do j = 1 %to &i; &comma "word&j" %let comma=,; %end; ); path&i..defineDone (); %end; link w1; put nsc=; nsc=0; end; soln.output(dataset:"solution_&date"); stop; %* create one set of nested permutation loops %* for each word in the answer; %let _L = &L; %do i = 1 %to &n; w&i: ; %let im1 = %eval (&i-1); %let _L = %eval (&_L - &&len&im1); array L_&i._ [&_L] $1 ; %* letter pool word i; array i_&i._ [&&len&i] ; %* permutation indices word i; * populate letter pool; * pull all letters from prior pool not indexed by prior word ; j = 1; do i = 1 to &_L + &&len&im1; %* is the ith letter in prior pool claimed %* by a permutaion index of the prior word ?; do k = 1 to &&len&im1; if i = i_&im1._ [k] then goto skip&i; end; L_&i._ [j] = L_&im1._ [i]; j + 1; skip&i: end; %* create &&len&i nested loops for word i %* the loops iterate the permutations of &_L things taken &&len&i at a time; %do j = 1 %to &&len&i; do i_&i._&j. = 1 to &_L; %* next iteration if any indices repeat; %do k = 1 %to %eval(&j-1); if i_&i._&j. = i_&i._&k. then continue; %end; %* next iteration if any substring part of permutation is not in dictionary; %if &j < &&len&i %then %do; _1 = L_&i._[i_&i._&j.]; %do k = 2 %to &j; %let x = %eval(&j-&k+1); _&k = L_&i._[i_&i._&x.] || _%eval(&k-1); if dict&k..find() then continue; %end; %end; %end; %let x = 1; word = L_&i._[i_&i._&x.] %do x = %eval(&x+1) %to &&len&i; || L_&i._[i_&i._&x.] %end; ; if dict.find() then continue; word&i = word; %if &i < &n %then %do; if path&i..find() = 0 then continue; path&i..add(); link w%eval(&i+1); %end; %else %do; %let limit=1000; if soln.find() = 0 then continue; soln.add(); nsc+1; if nsc < &limit. then put nsc word1-word&n; else if nsc = &limit. then put nsc '...'; %end; %do j = 1 %to &&len&i; end; %end; return; %end; run; %mend; options mprint; /* %solve (2005_07_12, dictionary=sasuser.agid_dictionary) %solve (2005_07_15, dictionary=sasuser.agid_dictionary) %solve (2006_05_31, dictionary=sasuser.agid_dictionary) */