Code Golf: Word Unscrambler

7

Write a program that either accepts input via stdin or from the command line. It will then unscramble the words, printing out the unscrambled version of each word.You get a text file containing every word (most of them) in the English dictionary to use. (Here is the file: Word List, and you can either use it from the web or save it as a text file and use it from there.)

Inputs to measure the score:

bbuleb lwrfoe kaec rtawe cokr kmli pcaee

Correct Outputs:

bubble flower cake water rock milk peace

bubble fowler cake water cork milk peace

(Word case doesn't matter, and please post your score and outputs along with your code!)

Scoring:

Score = (Amount of correct outputs) x (100 / (Code Length))

The code with the highest score wins!

Edit: This is my first post, please be kind!

3aw5TZetdf

Posted 2012-03-13T09:16:37.043

Reputation: 387

Scoring is suboptimal. say 'bubble flower cake water rock milk peace' scores hard-to-beat 213 and yet isn't very interesting. – J B – 2012-03-13T10:17:14.193

6Many scrambles have multiple correct unscrambles...I mean "opst" could easily be "stop" or "pots" or "post" or "tops". – dmckee --- ex-moderator kitten – 2012-03-13T14:01:16.527

1I notice that all answers so far have loaded the wordlist from the web. Is there any requirement that the file cannot be local? – Steven Rumbalski – 2012-03-13T19:36:48.597

@StevenRumbalski No, you can either use it from the web or locally. – 3aw5TZetdf – 2012-03-13T20:29:45.223

I want to repeat dmckee's question: "bbuleb lwrfoe kaec rtawe cokr kmli pcaee" can be decoded as: bubble fowler cake water cork milk peace. Is this be considered correct output? If it isn't, it seems that some hard-coding of the requirements into my program would be needed. – Steven Rumbalski – 2012-03-13T21:04:12.997

You state that "Word case doesn't matter", does that mean that we can assume our inputs are in the same case as the word file (because currently they aren't). – Steven Rumbalski – 2012-03-13T21:11:45.780

1@StevenRumbalski fowler and cork is considered correct output and the inputs can be the same case as the word life. (Will edit the post about the correct outputs) – 3aw5TZetdf – 2012-03-14T01:17:12.373

If the word source is avaliable, why (Amount of correct outputs) in score? – l4m2 – 2018-05-04T02:09:57.260

Answers

3

GolfScript, 27 chars, 7 correct outputs ⇒ score ≈ 25.926

n%(\:w;' '%{$:c;w{$c=}?}%n*

GolfScript doesn't have a file I/O operator, so I had to get a bit clever with the input. Specifically,

  • the scrambled words should be given on the first input line, separated by spaces, and
  • the wordlist should be given on the subsequent input lines, one word per line.

The scrambled words and the wordlist need to have the same letter case.

Here's an example invocation from a Unix shell command line, assuming that the code above has been saved as unscramble.gs, the GolfScript interpreter as golfscript.rb and the wordlist as wordlist.txt:

(echo BBULEB LWRFOE KAEC RTAWE COKR KMLI PCAEE; cat wordlist.txt) \
  | ruby golfscript.rb unscramble.gs 

This will produce the following output:

BUBBLE
FLOWER
CAKE
WATER
CORK
MILK
PEACE

The way it works is simply by sorting the letters in each input word and selecting the first word in the wordlist that produces the same string when its letters are sorted. Nearly half of the code is actually just for input parsing (and output formatting): all the real work is done in the {$:c;w{$c=}?}% loop.

Here's a de-golfed version with comments showing how it works:

n %                 # split the input on newlines
( \ :w ;            # pop the first line off the list of lines and assign the rest to w
' ' %               # split the first line on spaces

# apply the following map to each scrambled word:
{
    $ :c ;          # sort the letters in the word and assign the sorted word to c
    w { $ c = } ?   # find the first word in w that, sorted, equals c
} %

n *                 # join the results with newlines for output

Ilmari Karonen

Posted 2012-03-13T09:16:37.043

Reputation: 19 513

Wow, this answer is amazing! – 3aw5TZetdf – 2012-03-28T07:01:50.190

5

Python 3 / 84 chars / 7 correct outputs / score 8.3333

edit As per clarifications, removed .upper() and considering all 7 ouputs correct.

a=sorted
for b in input().split():print([c for c in open('x')if a(b)==a(c[:-1])][0])

Output:

BUBBLE
FLOWER
CAKE
WATER
CORK
MILK
PEACE

Steven Rumbalski

Posted 2012-03-13T09:16:37.043

Reputation: 1 353

3

Python, 189 171 156 chars / 6 7 correct outputs / "spirit of the law"

from urllib import*
z=sorted
x=dict((`z(m)`,m)for m in urlopen("http://bit.ly/wZYCmE").read().split())
for n in raw_input().split():print x[`z(n.upper())`]

(It gets "fowler" instead of "flower", both are on the input list and have the same letters.)

Edit: Steven Rumbalski's suggestions

Python, 144 chars / 7 correct outputs / "letter of the law"

for x in raw_input().split():print{620:'bubble',655:'flower',404:'cake',547:'water',431:'rock',429:'milk',510:'peace'}[sum(map(ord,x.lower()))]

marinus

Posted 2012-03-13T09:16:37.043

Reputation: 30 224

x=dict((z(m),m)for m in urlopen("http://bit.lywZYCmE").read().split()) – Steven Rumbalski – 2012-03-13T19:43:08.807

z=lambda p:tuple(sorted(p)) – Steven Rumbalski – 2012-03-13T19:47:43.730

Since you are using Python 2, you can save by taking advantage of backticks. Have z=sorted, then instead of z(m) use \z(m)`` – Steven Rumbalski – 2012-03-13T22:31:11.173

2

bash, grep, sed, sort: 144 chars, 144/7=20.57 (all correct)

s(){
echo $1|sed 's/./\n&/g'|sort
}
for w in $*
do
for m in $(egrep "^["$w"]{"${#w}"}$" d)
do
[[ `s $w` = `s $m` ]] &&(echo $m;break)
done
done

d is the filename of the dict; for testing on Linux replace it with $d as d=/usr/share/dict/words and subtract 1 from the filesize, to avoid a local copy.

usage:

./unscramble.sh bbuleb lwrfoe kaec rtawe cokr kmli pcaee
bubble
flower
cake
water
cork
rock
milk
peace

works well with dict/words, so I didn't download anything, lazy me! :)

user unknown

Posted 2012-03-13T09:16:37.043

Reputation: 4 210

1

Perl, 173 characters / 6 correct outputs

use LWP::Simple;
sub e{my$m;$m.=$_ for sort split//,uc$_[0];$m}$_=get"http://bit.ly/wZYCmE";
@x=split/\n/;$_=<>;for(split){$l=$_;for(@x){print"$_ ",$l=''if(e$_)eq e$l}}

marinus

Posted 2012-03-13T09:16:37.043

Reputation: 30 224

1

JavaScript, 357 330 chars [node.js] / 7 correct outputs

function g(w,s){return s===+s?g[a=w.toUpperCase().split("").sort().join("")]=g[a]||w:w.split("\n").map(g)&&s.split(" ").map(g).join(" ")}require('http').get({host:'web.mit.edu',path:'/kilroi/Public/bot/wordlist'},function(r){b=[];function f(c){c?b.push(c):console.log(g(b.join(""),process.argv[2]))}r.on('data',f),r.on('end',f)})

Eugh... slightly prettier version below. Doesn't read from stdin (string to check is first command-line argument), but it does fetch the dictionary from the net. The g function receives a string with the dictionary content (w) and a string to check (s); this is the most interesting part I suppose.

(It should theoretically work on any input string, as long as there's a permutation of each word in the dictionary. Oh, and the output is currently upper-case [as it is in the dictionary])

function g(w,s) {
  return s===+s
       ? g[a=w.toUpperCase().split("").sort().join("")] = g[a] || w
       : w.split("\n").map(g) && s.split(" ").map(g).join(" ")
}

require('http').get({host:'web.mit.edu',path:'/kilroi/Public/bot/wordlist'}, function(r) {
  b=[]
  function f(c) {
    c ? b.push(c)
      : console.log(g(b.join(""), process.argv[2]))
  }
  r.on('data',f)
  r.on('end',f)
})

FireFly

Posted 2012-03-13T09:16:37.043

Reputation: 7 107

1

Q,38 chars, 7 correct, 18.42105 points

{1#d(&)1=asc[x]~/:(asc')d:(_)read0`:d}

d is the dictionary file, stored locally in the same working directory.

usage:

{1#d(&)1=asc[x]~/:(asc')d:(_)read0`:d} each ("bbuleb";"lwrfoe";"kaec";"rtawe";"cokr";"kmli";"pcaee")
"bubble"
"flower"
"cake"
"water"
"cork"
"milk"
"peace"

tmartin

Posted 2012-03-13T09:16:37.043

Reputation: 3 917

1

PHP 270bytes Source. SCORE- ?

I'm not sure if if this type of output is accepted, please inform if its wrong.

<?$s=explode(PHP_EOL,file_get_contents('http://bit.ly/wZYCmE'));$n=explode(' ',$argv[1]);for($i=0;$i<count($n);$i++){$f=0;for($j=0;$j<count($s);$j++){$t1=str_split(trim($n[$i]));sort($t1);$t2=str_split($s[$j]);sort($t2);if($t1==$t2){$f++?echo'/':0;echo$s[$j];}}echo' ';}

Run:

php unscramble.php "BBULEB LWRFOE KAEC RTAWE COKR KMLI PCAEE"

Output:

BUBBLE FLOWER/FOWLER CAKE WATER CORK/KROC/ROCK MILK PEACE

l0n3sh4rk

Posted 2012-03-13T09:16:37.043

Reputation: 1 387

It has the right output! – 3aw5TZetdf – 2012-04-26T21:52:14.470

0

Jelly, 14 bytes, 7 correct outputs ⇒ score = 50 (Feedback appreciated!)

ɠḲ©µ³ḲŒ!f®ḢƊ€K

Try it online! (Long URL)

Feed space-separated dictionary on stdin and space-separated scrambled words as the first argument, e.g. curl http://web.mit.edu/kilroi/Public/bot/wordlist | tr '\n' ' ' | jelly fun unscrambler.j "BBULEB LWRFOE KAEC RTAWE COKR KMLI PCAEE"

ɠḲ©µ³ḲŒ!f®ḢƊ€K
ɠḲ©µ               read the dictionary from stdin splitting on spaces, and save it to the register
    ³Ḳ             split the scrambled word list argument on spaces
            Ɗ      define a function of the previous three links taking an input W:
       Œ!f®        get all permutations of W, and filter it with the dictionary
                   (aka, remove all words in the dictionary that are not permutations of W)
           Ḣ       take the head, so we return just one unscrambled word per scrambled word
              €K    run that Ɗ function on each of the unscrambled words, and split the results with spaces

Harry

Posted 2012-03-13T09:16:37.043

Reputation: 1 189

In Jelly, taking input from whatever source is most convenient, and in whatever form is most convenient, can matter a lot. STDIN is pretty clunky. If you put the dictionary in you can get rid of the register (11 bytes); if you take input as lists you get 8 bytes

– Lynn – 2018-05-09T10:37:07.677