Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Perl Golf idea

by sweepy838 (Acolyte)
on Apr 27, 2012 at 20:51 UTC ( #967717=perlquestion: print w/replies, xml ) Need Help??
sweepy838 has asked for the wisdom of the Perl Monks concerning the following question:

So here's the rules should you decide to play. Create a script as small as you can that will unscramble a list of given words using a dictionary, there is a challenge on a site called hackthissite with a very similar objective but i thought it would be a great idea to make this a perl golf competition? and it should not give possible matches, it should try to solve each word, if it cant then move on. enjoy :) and yes, i am also taking part :p ps: i've already written mine using C so this isn't a "do my homework" post, its just a bit of fun.

Replies are listed 'Best First'.
Re: Perl Golf idea
by davido (Archbishop) on Apr 27, 2012 at 21:46 UTC

    Why don't you go ahead and post a Perl version of your own here, just for a bit of fun. The worst you could do is just transcribe the C version over to a Perl equivalent, and then you'd be showing us a target to try to best.


      haha yes the WORST i could do is convert it to perl! im ashamed of posting it yet.. im trying to make it better. but here is the c version:
      string myword; string wlist = "dict.txt";string line; int strLen = myword.length( +);int c = 0; ifstream cfile(wlist); if (cfile.is_open()) { while (cfile.good()) { getline (cfile,line); if (strLen == line.length()) { bool match[strLen];string used[strLen];int matchcount = + 0; for (int i = 0; i < strLen; i++) { string ch = myword.substr(i, 1); for (int y = 0; y < strLen; ++y) { string kh = line.substr(y, 1); if (ch == kh) { if (used[y] == ch) match[matchcount] = 0; else { used[y] = ch; match[matchcount] = 1; matchcount++; break; } } } } c = 0; for (int t = 0; t < strLen; t++){if (match[t] == true) + ++c; } if (c == strLen) { return line; } delete [] match; } } cfile.close(); }
      I have a feeling that people think i'm getting them to do my "homework" ? seriously?

        Rewritten in Cerl (C++ transliterated into something that a Perl interpreter in a good mood may care to execute):

        my $myword; my $wlist = "dict.txt"; my $strLen = length $myword; open my $cfile, '<', $wlist or die "Can't open $wlist: $!\n"; while (defined (my $line = <$cfile>)) { next if $strLen != length $line; my @match; my @used; my $matchcount = 0; for (my $i = 0; $i < $strLen; $i++) { my $ch = substr $myword, $i, 1; for (my $y = 0; $y < $strLen; ++$y) { next if $ch ne substr $line, $y, 1; if ($used[$y] eq $ch) { $match[$matchcount] = 0; } else { $used[$y] = $ch; $match[$matchcount] = 1; $matchcount++; last; } } } my $c = 0; for (my $t = 0; $t < $strLen; $t++) { ++$c if ($match[$t]); } return $line if ($c == $strLen); } close $cfile;

        This is of course completely untested and not what I would consider to be Perlish, although it is strict compliant. Note that the minor structure changes I made could actually be pushed back to the original C++ code to clean up that code somewhat.

        True laziness is hard work
Re: Perl Golf idea
by thundergnat (Deacon) on Apr 30, 2012 at 20:01 UTC

    Here's a kind of half-assed one. Feed it the path to the dictionary file and a word and it will return all the matches.


    perl -e"sub w{join'',sort@_[0]=~/./g};$w=w pop;($w eq w$_)&&print for<>" ./dict.txt acert



    (with the dict.txt file I had. YMMV).

      Nice. I've managed to knock off twelve characters though...

      • @_[0] can be replaced with pop. This needs whitespace before it, but it's still shorter. Savings: 1 character.
      • eq can be replaced by the smart match operator, allowing the whitespace around it to be dropped. Savings: 2 characters.
      • Semicolon after sub definition not needed. Savings: 1 character.

      Now we've got:

      perl -E'sub w{join"",sort pop=~/./g}$w=w pop;($w~~w$_)&&print for<>' . +/dict.txt acert

      But, hell, we can go shorter. Let's switch from the join"",... construct with the babycart operator inside an interpolated string... "@{[...]}". Can't remember why I did this - doesn't actually reduce the size of the code, but I think it was necessary for some of the later stuff.

      perl -E'sub w{"@{[sort pop=~/./g]}"}$w=w pop;($w~~w$_)&&print for<>' . +/dict.txt acert

      Next, we stop passing a parameter to the w function, and use $_ instead. This means that we can take advantage of the fact that regular expressions get applied to $_ by default, giving us massive savings inside the function. Outside the function it's a mixed blessing. We need to assign that pop to $_ giving us a whole new statement. But we don't need to pass anything to w on either of its invocations, and we can drop the parentheses around the smart match comparison.

      perl -E'sub w{"@{[sort/./g]}"}$_=pop;$w=w;$w~~w&&print for<>' ./dict.t +xt acert

      Those two assignments in the middle started to grind my gears. I figured there must be a way to ditch the semicolon between them... and there is! The w function no longer cares about what parameters it's passed.

      perl -E'sub w{"@{[sort/./g]}"}$w=w$_=pop;$w~~w&&print for<>' ./dict.tx +t acert

      I could go two characters shorter, but only swapping from print to say which adds unsightly blank lines to the output.

      UPDATE: five characters more. Smart match can deal with arrayrefs!

      perl -E'sub w{[sort/./g]}$w=w$_=pop;$w~~w&&print for<>' ./dict.txt ace +rt
      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
        One character less:
        perl -nlE'sub w{[sort/./g]}INIT{$w=w$_=pop}$w~~w&&say' ./dict.txt acer +t
        And if you don't mind the (second) argument getting printed, another 3 chars less:
        perl -nlE'sub w{[sort/./g]}$w||=w$_=pop;$w~~w&&say' ./dict.txt acert

        Umm. Wow. I knew there was room for improvement reduction but... tobyink++

Re: Perl Golf idea
by brx (Pilgrim) on May 02, 2012 at 13:41 UTC

    Here is a summary of replies to this little informal golf contest. I hope there will be more replies.

    • thundergnat

      perl -e'sub w{join"",sort@_[0]=~/./g};$w=w pop;($w eq w$_)&&print for<>' ./dict.txt acert
    • tobyink

      perl -E'sub w{[sort/./g]}$w=w$_=pop;$w~~w&&print for<>' ./dict.txt acert
    • JavaFan

      perl -nlE'sub w{[sort/./g]}INIT{$w=w$_=pop}$w~~w&&say' ./dict.txt acert
    • brx

      perl -E'@a=sort pop=~/./g;print grep@a~~[sort//g],<>' ./dict.txt acert
    • JavaFan, with the second argument getting printed (a dummy line must be added at the begining of dict.txt)

      perl -nlE'sub w{[sort/./g]}$w||=w$_=pop;$w~~w&&say' ./dict.txt acert
    • brx, with an extra newline after last line printed

      perl -E'@a=sort pop=~/./g;say grep@a~~[sort//g],<>' ./dict.txt acert
    • Update: thundergnat

      perl -nlE'($w//=[sort pop=~/./g])~~[sort//g]&&say' ./dict.txt acert

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://967717]
Approved by davido
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (10)
As of 2018-01-18 15:05 GMT
Find Nodes?
    Voting Booth?
    How did you see in the new year?

    Results (212 votes). Check out past polls.