Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

PGA Golf, Round 1

by jmcnamara (Monsignor)
on May 24, 2001 at 16:51 UTC ( [id://82878] : perlmeditation . print w/replies, xml ) Need Help??

The PGA was the Perl Golf Apocalypse at the 4th Perl Conference.

Uri Guttman has kindly sent me the questions in order to replay the tournament here at PerlMonks.

The tournament was arranged into 17 "holes". Each hole had a stated level of difficulty and a time limit. The time limit doesn't apply here but they have been left in as an indication of the pressure that the contestants were under.

The holes will be submitted in three rounds over three weeks. The PGA suggested solutions for each round will be published before each new round.

We can also turn this into a competition. Send me a /msg if you wish to take part. I will keep track of the scores over the whole course and setup a leadership table.

Even if you haven't played Perl Golf before you should try one or two of these. Dijkstra notwithstanding, Perl Golf is a good way to learn some of Perl's dustier features and if nothing else it will probably get you to read the perlrun manpage.


1. The aim of the tournament is the shortest solution on each hole. You should publish your score with each solution. Counting is as follows:
sub hole{print "hello, world"} For a sub 123456789_123456789_ 20 chars perl -e 'print "hello, world"' For a one liner 123456789_123456789_123456789_ 30 chars
2. "use strict" and -w are not required.

3. All subroutines which should return a single scalar value will be called in a scalar context.

Thanks again to Uri and the others who contributed to the PGA. Uri's Perl Golf page is here.

ROUND 1: Holes 1-6

Hole 1 - Fifth Word

Write a Perl subroutine which returns the fifth word in a string. A word is any sequence of letters, numbers, and/or underscores. The string will be passed as the sole argument and will contain at least 5 words.

* Difficulty: Easy

* Time: 3 minutes

Hole 2 - Error Message

Write a Perl one-liner that prints the following to STDERR:
Can't find label TPC at -e line 5.

* Difficulty: Easy

* Time: 3 minutes

Hole 3 - Smallest Repeating Pattern

Write a subroutine that accepts a string which may consist of a repeating pattern, and returns the smallest repeating substring. If the string does not consist of a repeating pattern, the subroutine should return undef or the empty string. e.g.:
input output 'aaaaaa' 'a' 'ababab' 'ab' 'aabaab' 'aab' 'ababaa' ''
* Difficulty: Easy

* Time: 4 minutes

Hole 4 - Hex to Char

Write a subroutine which, given a string consisting entirely of hexadecimal digits, converts pairs of digits to their ASCII character equivalents and returns the result as a list of characters. The hexadecimal digits A-F may appear in upper or lower case. There will be an even number of digits in the string. e.g.
5065726c206861636b6572 -> ('P', 'e', 'r', 'l', ' ', 'h', 'a', 'c', 'k', 'e', 'r')
* Difficulty: Easy

* Time: 4 minutes

Hole 5 - Max without Sort

Write a subroutine that accepts a list of numbers, and returns the maximum number from the list, without using Perl's built-in sort.

* Difficulty: Easy

* Time: 4 minutes

Hole 6 - Vowel Sort

Write a subroutine that accepts a list of words, and returns the list sorted by the first *vowel* that appears in each word. If two words have the same first vowel, it does not matter which is sorted first. Words will be in lowercase and will always contain at least one vowel. (Vowels are a, e, i, o, and u.)
e.g.: hole('dog', 'cat', 'fish', 'duck', 'lemur') returns: ('cat', 'lemur', 'fish', 'dog', 'duck')

* Difficulty: Easy

* Time: 5 minutes

They get harder. ;-)


Replies are listed 'Best First'.
Re: PGA Golf, Round 1
by jorg (Friar) on May 24, 2001 at 19:15 UTC
    right let's kick things off here... Here is my first Hole, 25chars, took me approx 25 minutes. Makes me wonder if i should've used a Wood number 3 rather than the Iron number 5
    sub a{($_[0]=~/\w+/g)[4]}
    Update mincus pointed out to me that there are only 18 chars i should count. How's that for a caddy !


    "Do or do not, there is no try" -- Yoda

      According to the counting rules (rule 1 above) you only count the characters inside the subroutine block (for one liners you count the whole command line). So yours is 18 chars.

      Not to spoil anyone's fun, but here's a small tip for shaving characters --- use pop rather than $_[0], that gives us a 16 character solution:

      sub S {(pop=~/\w+/g)[4]} 123456789_123456 # 16
Re: PGA Golf, Round 1
by jorg (Friar) on May 24, 2001 at 19:43 UTC
    This second Hole is giving me a freakin headache.. __LINE__ appeared to be a *constant in the true sense so i had to go with
    perl -e; -e; -e; -e; -e "goto TPC"; 123456789-123456789-123456789-12345
    35 big ones in about 1 hour
    perl -e; -e; -e; -e; -e "goto TPC" 123456789-123456789-123456789-1234
    34 and i'm being downvoted already, just let me have a go at this guys, you can show off your dandy Golf later ok?
    It's not like I ever mingle into any of the other Golf compo's...


    "Do or do not, there is no try" -- Yoda
Re: PGA Golf, Round 1
by mr.nick (Chaplain) on May 24, 2001 at 21:15 UTC
    Okay: here are my entries. They aren't particularly good, but they work which is fine for me.

    Hole 1 - 21 chars

    (split/[^\w_]/,pop)[4] 1234567890123456789001
    Hole 2 - 24 chars
    perl -e'\ \ \ \ goto TPC'
    Hole 4 - 31 chars
    map{chr(hex)}unpack("A2"x11,pop) 1234567890123456789012345678901
    Hole 5 - 32 chars
    $x=shift;map{$x=$_ if$_<$x}@_;$x 12345678901234567890123456789012
    Hole 6 - 53 chars (ugh!)
    sort{($a=~/([aeoui])/)[0]cmp($b=~/([aeiou])/)[0]}@_} 1234567890123456789012345678901234567890123456890123
      I feel so smart... I actually pulled an obscure thing of my own... in perl // redoes the previous re, so
      sub hole{sort{($a=~/([aeiou])/)[0]cmp($b=~//)[0]}@_} 123456789_123456789_123456789_123456789_12
      cuts your hole 6 to 42 chars! my small moment of glory...

      Update realized I counted } in sub... actually 42 chars.. not 43...
                      - Ant

Re: PGA Golf, Round 1
by da (Friar) on May 24, 2001 at 20:55 UTC
    Hole 2: I'm working under the assumption that 'one liner' strictly means it is executed as one line; and it's OK to specify I'm using csh otherwise I'm sunk. :-) 25 counting the carriage returns:
    perl -e'/ / / / goto TPC'
    hmm... specifying sh instead of csh, eliminate the / characters, and that's 21.

    Please go easy on me, I'm an amateur. Of course, scoring it is vaguely impossible according to the rules, so I don't imagine this is a valid play...

    --- -DA
    update: took me 5 min., plus 5 min. to try and convince myself it might be valid...
Re: PGA Golf, Round 1
by btrott (Parson) on May 24, 2001 at 21:37 UTC
    Here's my Hole 4, though I feel as if I must be missing something obvious, either incorrect in my answer or a different solution.
    sub h2c{split//,pack"H*",pop} 123456789_123456789_
    20 characters.

    Update: I realize now that the answer is incorrect because it returns a string rather than a list. Thanks all. :)

    Update again: Fixed the answer by adding the split.

      It must be a list of characters.
      sub hole{split//,pack"H*",@_}
      is optimal (I believe).
      Incorrect in your answer: you need to return a list of characters, not a string.

      If God had meant us to fly, he would *never* have give us the railroads.
          --Michael Flanders

Re: PGA Golf, Round 1
by btrott (Parson) on May 24, 2001 at 21:51 UTC
    Hole 6.

    This is really ugly and much too long, but whatever:

    sub hole{$r='([aeiou])';sort{($a=~$r)[0]cmp($b=~$r)[0]}@_} 123456789_123456789_123456789_123456789_12345678
    48 characters, I think.
Re: PGA Golf, Round 1
by ChemBoy (Priest) on May 25, 2001 at 00:27 UTC
    Hole 1 (18, or 16 if I can take a free drop on pop)
    sub {(pop=~/\w+/g)[4]}
    Hole 2 (24 in tcsh)
    perl -e'\ \ \ goto\ TPC'
    Which has been said before, to be sure.
    Hole 3 (20)
    sub {pop=~/^(.+?)\1+$/;$1}
    which takes a 1-stroke penalty for the lack of /s, and one for $ instead of \Z. Oh well.
    Hole 4 (19)
    sub {split//,pack"H*",@_}
    sub {map{chr hex}pop=~/../g}
    for one more stroke and a warmer fuzzier feeling (since I actually got that one done in the time limit).
    Hole 5 (30)
    sub {$a=pop;for(@_){$a>$_ or$a=$_}$a}
    I think this is optimal for Perl 5.004 (tilly can do it better with a more recent revision, I know.)
    Hole 6 (44)
    sub {sub F{pop=~/[aeiou]/;$&}sort{F($a)cmp F$b}@_}
    Which is not as cool as some, but is the best I could do without reading the thread.
    This gives me an overall score of 155 for six holes, which I think is respectable...

    If God had meant us to fly, he would *never* have give us the railroads.
        --Michael Flanders

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: PGA Golf, Round 1
by dooberwah (Pilgrim) on May 24, 2001 at 21:31 UTC
    "These Guys Are Good." - PGA Motto

    -Ben Jacobs (dooberwah)
    one thing i can tell you is you got to be free

Re: PGA Golf, Round 1
by Anonymous Monk on May 24, 2001 at 22:01 UTC
    # 1 -- 16 chars sub g1 { (pop=~/\w+/g)[4] } # 2 -- 19 chars (23 with newlines) perl -e'goto\ \ \ \ TPC' # 3 -- 23 chars # note: using $ instead of \z is *wrong* # note: using . without /s is *wrong* sub g3 { pop=~/^(.*?)\1+\z/s&&$1 } # 4 -- 12 chars sub g4 { pack"H*",pop } # 5 -- 29 chars sub g5 { $x=pop;$x<$_&&($x=$_)for@_;$x } # 6 -- 49 chars sub g6 { sort{($a=~/[aeiou]/g)[0]cmp($b=~/[aeiou]/g)[0]}@_ }

    japhy -- Perl and Regex Hacker
      Um, that is my code. My cookie expired or something. Anyway, direct any ++'s here, please.

      japhy -- Perl and Regex Hacker
      # 4 -- 19 chars sub g4 { split//,pack"H*",@_ } # 6 -- 47 chars sub g6 { sort{($a=~($_='([aeiou])'))[0]cmp($b=~$_)[0]}@_ }

      japhy -- Perl and Regex Hacker
      I had similar solutions. But I improved on hole 3 to 20:
      sub hole{map/^(.*?)\1+\z/s,@_}
      and my solution for hole 5 was also 29 but somewhat different.
      sub hole{$,=pop;$,=$,<$_?$_:$,for@_;$,}
      However we can improve hole 5 to 28 taking your solution and applying my trick to it.:
      sub hole{$,=pop;$_<$,or$,=$_ for@_;$,}

      Oops. My test code put hole 3 in the wrong context. My bad.

Re: PGA Golf, Round 1
by the_slycer (Chaplain) on May 24, 2001 at 22:24 UTC
    Well, not fully complete - missing 3 and 6, maybe I'll update those later (I have to actually work now). Here are my attempts.
    First time golfing :-)

    Hole #1 (score 10): sub b{(split)[4]}
    Hole #2 (score 21):
    perl -e'

    goto TPC
    Hole #4 (score 47): sub b{$_=reverse;push@_,chr(hex(chop.chop))while$_;@_}
    Hole #5 (score 32): sub b{$t=pop;for(@_){$t=$_ if$_>$t}$t}
    Update: Thanks tilly, I would never have noticed hole 5 - though I had some bad feelings about it. I don't know WHAT I was thinking for #1 :-)
    update2: changed 5 to a working one now :-)
      Hole 1 is wrong. (Words cannot include, for instance, punctuation.)

      Hole 5 is wrong. (You are wrong if $t starts larger than any number in the list. Think of a list of negative numbers.)

Re: PGA Golf, Round 1
by petral (Curate) on May 25, 2001 at 18:08 UTC
    I did slightly better in a couple of places, so probably wrong. I'll submit it now, before better solutions show up for everything. (Corrected holes 3 and 4 as per more-careful-readers-of-specs.)
    # hole 1: 16 perl -le 'sub h1 {(pop=~/\w+/g)[4]}' -e'print h1"abc ,., de f g + hi jk"' # hole 2: 20 perl -e' goto TPC' # hole 3: 19 perl -le 'sub h3 {pop=~/^(.+?)\1+\z/s}' -e'print h3 join" ",qw(hihi +hihi)' # hole 4: 19 perl -le 'sub h4 {split"",pack"H*",@_}' -e'$,=$";print h4"68696C6f" +' # hole 5: 22 XXX see below: perl -le 'sub h5 {$_<$x or$x=$_ for@_;$x}' -e'print h5(3,5,2,8,7)' # hole 6: 38 perl -le 'sub h6 {grep{s/.//}sort map{/[aeiou]/;$&.$_}@_}' \ -e'$,=$";print h6 qw(book eel hi huge i pe +a wrap)'
    oopsdate: Yes, 5 doesn't work w/o priming the temporary (which makes it 30 chars).
    So, here's an overly golfish version that I managed to trim to 32:
    perl -le'sub x {$_[-1]<$_[0]?pop:shift;$#_?&x:@_}' -e'print x(-3,-5,-2 +,-8,-7)'
    (And yes, by the time I posted them, the solutions were all pretty much established. jmcnamara said he wasn't posting answers for a week, so it's a guess between not posting 'spoilers' and getting 'rep' -- especially when others are updating as you collect and cut and paste.  --  Anyway, it is kinda neat that, at least for these first few, the straightforward solutions are the best.)


Re: PGA Golf, Round 1
by srawls (Friar) on May 25, 2001 at 00:38 UTC
    Hole #5 -- 27 chars (now 34, added $t-pop;):
    sub MAX {$t=pop; (grep{$t<$_?$t=$_:0}@_)[-1] }

    Update:Changed code--it didn't handle negative numbers before. (thanks for the /msg chemboy)

    The 15 year old, freshman programmer,
    Stephen Rawls

Re: PGA Golf, Round 1
by iamcal (Friar) on May 25, 2001 at 12:00 UTC
    sub hole_one{(pop=~/\w+/g)[4]} #16 characters hole two: perl -e "print STDERR 'Can\'t find label TPC at -e line 5.'" #60 characters (using tachyon's method) sub hole_three{pop=~/^(.*?)\1+$/s} #18 characters (handles carriage returns in the input) sub hole_four{map{chr hex}(pop=~/(..)/g)} #26 characters sub hole_five{$a=pop;(grep{$a=$_ if $_>$a}@_)[-1]} #35 characters (updated for negetive numbers) sub hole_six{sort{($a=~/([aeiou])/)[0]cmp($b=~//)[0]}@_} #42 characters
Re: PGA Golf, Round 1
by tachyon (Chancellor) on May 27, 2001 at 18:00 UTC

    Round 1, 2 minutes

    sub h{pop=~/(?:\w+\W*){4}(\w+)/}

    Round 2, 15 sec

    print STDERR"Can't find label TPC at -e line 5."

    Round 3, 5 mins, Should probably use /s and \z but that's 2 extra chars

    sub f{pop=~/^(.*?)\1+$/}

    Round 4, 6 mins performance level inversly proportional to level of red in bottle

    sub h{$_=pop;s/(..)/chr hex $1/eg;(/../g)}

    Round 5, Back on form, 2 minutes

    sub g{$m=pop;map{$m=$_ if $_>$m}@_;$m}

    Round6, Took too damn long!

    sub v{sort{eval'$a=~/([aeiou])/;$1'cmp eval'$b=~/([aeiou])/;$1'}@_}

    Please sir can I have some more?


    Updated with corrections 29052001, and sadly all added length :-(

      I'm afraid that your solutions to 1, 3, 4, and 5 must be disqualified.

      Hole 1 specifies returning the fifth word; your solution returns some extra whitespace. Additionally, there may be no whitespace after the fifth word, or after any of the words: first-second!third+fourth*fifth.

      For Hole 3, the entire string must consist of the repeated substring. This was demonstrated in the examples, where 'ababab' results in 'ab' but 'ababaaa' results in ''.

      Hole 4 asks for a list of characters, rather than a string. Looks like that one tripped up a lot of people. :)

      Hole 5 features a common gotcha; a correct solution must handle the case where all the values in the list are negative. Another one that a lot of people don't catch. :)

      We tried to make things a little easier at the actual tournament by providing a test scaffold for each hole, which the participants could use to test their code on sample input. Solving these holes is much harder without that.

Re: PGA Golf, Round 1
by tadman (Prior) on May 25, 2001 at 16:11 UTC
    My submissions:

    Hole 1 (16 characters)
    sub f{ (pop=~/w+/g)[4] }
    Hole 2 (31 characters) perl -e# -e# -e# -e# -egoto+TPC Hole 3 (46 characters)
    If only alphanumeric data will be processed:
    sub f{ $p=$_=pop;1while(!/^($p){2,}$/&&$p=~s/.$//);$p }
    If required to support non-alpha, or unusual characters in the input data (requires \Q...\E), then 51 characters:
    sub f{ $p=$_=pop;1while(!/^(\Q$p\E){2,}$/&&$p=~s/.$//s);$p }
    Hole 4 (24 characters)
    sub f{ map{chr hex$_}pop=~/../g }
    Hole 5 (30 characters)
    sub f{ $x=pop;map{$_>$x?$x=$_:0}@_;$x }
    Hole 6 (39 characters)
    sub f{ grep{s/.//}sort map{/[aeiou]/;"$&$_"}@_ }
    Corrected hole 4 (returned string, wanted list).
    Reduced hole 6 (@x=@_ to @_, used $& instead of memorizing)
    Removed first 'version' of hole #5, which didn't handle negative numbers, leaving the longer second version.
      changing "$&$_" to $&.$_ saves you one stroke... 38 chars
                      - Ant