On Sat, 8 Jun 2002, Stephen Turner wrote:
> Well, you've all very sweetly waited until I woke up before starting the
> discussion. I'm going to thank you by annotating the top 12 solutions for
> you (10 veterans and 2 beginners).
OK, here they are. See attachment (hopefully this won't mess up special
characters).
--
Stephen Turner, Cambridge, UK http://homepage.ntlworld.com/adelie/stephen/
"This is Henman's 8th Wimbledon, and he's only lost 7 matches." BBC, 2/Jul/01
Common elements:
All of these solutions (and everyone below 215) use -056, which sucks the
input in a sentence at a time.
All except Juho use -a, which splits the sentence into words into the special
@F array.
All of them (and everyone below 200) use -p, which loops over sentences and
prints $_ at the end of every loop. (Everyone below 226 used -p or its cousin
-n, and some enthusiastic souls even used both :).
I've reformatted the solutions and annotated them. They should all run
properly. Note that two of them (Alexander and seano) have bugs, and one
(Ton) fails the test script but doesn't have bugs. :-) When I say
"statistic", I mean the "vowels/alphanumerics" thing.
E&OE. Corrections welcome.
#############################################################################
Alexander 176.33
-ap056 ($x,@D)=map{$_.=$"x(3-length);y/aeiouyAEIOUY//."/".s/\w/$&/g}$_,@F;$_="@F
";s/(.{57})...+\./$1.../;$_=@F.": $_
$x: ${s/\S+[ .]+/A.length$&/ge,\pack$_,@D}
"if@F;s/ +$//mg
#############################################################################
#!perl -ap056
($x,@D)=map{$_.=$"x(3-length);y/aeiouyAEIOUY//."/".s/\w/$&/g}$_,@F;
# For the whole line, and for each word, pad out to at least three spaces,
# and calculate the statistic. Save the overall statistic in $x, and the
# word statistics in @D.
$_="@F ";
# Rewrite the line from the words with a single space between each.
# The extra space at the end is to avoid the last word statistic getting
# truncated later, but actually it doesn't suffice. Two spaces are needed
# if the last word is very long.
s/(.{57})...+\./$1.../;
# Truncate the line if necessary.
$_=@F.": $_
$x: ${s/\S+[ .]+/A.length$&/ge,\pack$_,@D}
"if@F;
# Allocate the answer to $_ so that it will get printed by -p.
# The ${...} avoids the need to close and reopen the string.
# It looks up the lengths of the words on the formatted top line, and packs
# the word statistics to that length. Only do this if there are any words.
s/ +$//mg
# We've got extra spaces at the end of each line, so strip them now.
# NB if there weren't any words, $_ is now empty.
#############################################################################
Guillermo 176.25
-pa056 sub
c{uc=~y/AEIOUY//.'/'.s/\w//g}$w=c;@s=map{sprintf"%-3s",$_}@F;$_="@s";s/(.{57})...+\S/$1.../;$_&&=(@c=map{pack"A".y///c,c}@s).":
$_
$w: @c[0..s/ +[^.]//g]
";s/ +$//gm
#############################################################################
#!perl -pa056
sub c{uc=~y/AEIOUY//.'/'.s/\w//g}
# A subroutine to calculate the statistic.
$w=c;
# Save the overall statistic in $w.
@s=map{sprintf"%-3s",$_}@F;
# Pad the words to at least three characters.
$_="@s";
# Rewrite the line with a space between each word.
s/(.{57})...+\S/$1.../;
# Truncate the line if necessary.
$_&&=
# Allocate the result to $_ so that it will get printed by -p.
# "$_&&=something" should be read "$_=something unless !$_".
(@c=map{pack"A".y///c,c}@s).
# For each padded word, pad its word statistic to the same length.
# Also print the number of words.
": $_
$w: @c[0..s/ +[^.]//g]
";
# But now count the number of words on the top line, and only include that
# many word statistics.
s/ +$//gm
# We've got extra spaces at the end of each line, so strip them now.
#############################################################################
Juho 176.21
-p056 @d=map{$_|=$"x3&"$_ ";$"x
y...c|(@z=/[aeiouy]/ig).'/'.s/\w/$&/g}@w=/\S*\w\S*/g,$_;s/(.{57})...+\S/$1.../,$_=@w.":
$_
$d[-1]: @d[0..s/ +[^.]//g]
"if$_="@w";s/ +(
|:)/$1/g
#############################################################################
#!perl -p056
# This is the only one of the top 12 solutions not to use -a.
@d=map{$_|=$"x3&"$_ ";
$"x y///c|(@z=/[aeiouy]/ig).'/'.s/\w/$&/g}
@w=/\S*\w\S*/g,$_;
# For each word (@w, found as nonspaces,alphanumeric,nonspaces), and for
# the whole sentence ($_):
# 1) Pad out to three spaces if necessary. ($_|=$"x3&"$_ "). It might be
# worth pointing out here that bitwise-and, -or and -xor act on strings by
# and-, or-, or xor-ing the bits of the corresponding characters in each
# string. One consequence of this is that the result of & always has the
# length of the shorter string, whereas the result of & always has the length
# of the longer string. Here $_ is being or-ed, hence lengthened, and the
# thing on the right is a three-character string with an appropriate bit
# pattern not to mess up $_.
# 2) Calculate the statistic. (The @z is just to put the vowel match in list
# context, so that it returns the number of matches, not the first match).
# 3) Lengthen the statistic with another logical or. The or-ing is with a
# number of spaces ($" is a short version of ' ') equal to the length of the
# word (y///c measures the length of $_). Luckily digits and slash are
# unchanged by or-ing with space.
# 4) Save these padded statistics in @d.
# At this point, the "if" below sets $_ equal to the words with a single
# space between each, and the next two commands only run if there were any
# words.
s/(.{57})...+\S/$1.../,
# Truncate the sentence if necessary.
$_=@w.": $_
$d[-1]: @d[0..s/ +[^.]//g]
"
# Form the answer in $_ so that it will be printed by -p.
# $d[-1] is the last element of @d, i.e. the overall statistic.
# s/ +[^.]//g counts the number of visible words in the sentence, so
# @d[0..s/ +[^.]//g] is the list of word statistics we want.
if$_="@w";
# See above
s/ +(
|:)/$1/g
# The last statistic on the line, and the overall statistic, may have been
# padded too much. So remove any spaces that followed by new line or colon.
#############################################################################
Martin 175.31
-056npa sub
c{y/aeiouyAEIOUY//."/".y/a-zA-Z0-9//}$_=(@c=map{$_.=$"x($p=/\./?0:length(c)-length);c.$"x-$p}@F)?@F.":
@F
".c.": @c
":"";s/( .{57}).{4,}(
.* .{0,56}\S+).*/$1...$2/
#############################################################################
#!perl -056npa
# The -n is reduntant.
sub c{y/aeiouyAEIOUY//."/".y/a-zA-Z0-9//}
# A subroutine to calculate the statistic
$_=
# Set $_ to the following so that it will be printed by the -p
(@c=map{$_.=$"x($p=/\./?0:length(c)-length);c.$"x-$p}@F)?
# For each word, calculate the length of the statistic minus the length of
# that word. Call this $p: except $p = 0 if this is the last word.
# Pad the word with $p spaces, and pad the statistic with -$p spaces.
# Store the statistics in @c.
@F.": @F
".c.": @c
"
# If @c was non-empty, write down the elements of the answer in $_.
:"";
# Otherwise, make $_ empty.
s/( .{57}).{4,}(
.* .{0,56}\S+).*/$1...$2/
# The line can still be too long here. If it is, just use the first 57
# characters of the top line, and whichever statistics in the bottom line
# start before that character.
#############################################################################
Mtv Europe 174.18
-ap056 sub
B{lc=~y/aeiouy//.v47.(@Q=/\w/g)}$B=$Z=$C=v9;$C^=$C=($C!~/.{58}/|/\./&($Z|=$C.$_)!~s/(.{58}).{4,}/$1.../?$B|=$C.B:0).1^$Z.1for@F;$_=@F?@F.":$Z
".B.":$B
":$T;y/\0/ /
#############################################################################
#!perl -ap056
sub B{lc=~y/aeiouy//.v47.(@Q=/\w/g)}
# A subroutine to calculate the statistic. v47 is the same as '/' but has
# better tie break score.
$B=$Z=$C=v9;
# Set $B, $Z and $C to tabs. (v9 is a shorter form of "\t".) Later, $Z will
# form the sentence, and $B the word statistics: these are their initial tabs.
# $C will be padded out with as many nulls as the length of the sentence to
# date.
$C^=$C=($C!~/.{58}/
|/\./
&($Z|=$C.$_)!~s/(.{58}).{4,}/$1.../
?$B|=$C.B
:0
).1^$Z.1
for@F;
# Ah, a typical Mtv expression. Even with extra spacing, it's a struggle!
# I strongly suspect Mtv to be an alien too.
# For each word:
# 1) $Z|=$C.$_ adds a null and $_ onto the end of $Z.
# 2) If $Z is now past 60 characters, truncate it.
# 3) If it isn't past 60 and we have a full stop; or if it wasn't past 57
# before; then lengthen $B by a null and the corresponding word statistic.
# 4) Set $C to be equal to $B.1^$Z.1. This is just any expression one longer
# than the longer of $B and $Z.
# 5) Set $C=$C^$C, i.e. a string of nulls of this length.
$_=
# Set $_ so that it will be printed by -p.
@F?
# If there were any words...
@F.":$Z
".B.":$B
"
# ... set $_ to be the right thing...
:$T;
# ...otherwise set it blank. ($T was never set. '' would do just as well, but
# $T is better for the tie break).
y/\0/ /
# Change all the nulls into spaces.
#############################################################################
Stephen 172.25
-lpa056 sub b{lc=~y/aeiouy//.'/'.s/\w/$&/g}$m=b$_=sprintf'%-3s 'x@F,@F;s/
+$//?s/(.{57})...+/$1../:last;@0=map{A.y///c}/\S+ +(?!\.)/g;$_=@F.": $_.
$m: ".pack"@0A*",map b,@F
#############################################################################
#!perl -lpa056
# -l strips the full stop off the incoming sentences, and puts a new line on
# the end of the printed result. This is the only golfer's final solution to
# use -l under 230 strokes.
sub b{lc=~y/aeiouy//.'/'.s/\w/$&/g}
# A subroutine to calculate the statistic.
$m=b$_=sprintf'%-3s 'x@F,@F;
# Parsed as $m=b($_=sprintf....); so equivalent to $_=sprintf... ; $m=b;
# Print the words with at least three chars, following each by a space.
# Save the overall statistic in $m.
s/ +$//?s/(.{57})...+/$1../:last;
# If the line finishes with a space, it had a word in; truncate if necessary.
# Otherwise, we've finished.
@0=map{A.y///c}/\S+ +(?!\.)/g;
# Look through the visible words on the formatted top line, excluding the
# last, and find their lengths. We will use these lengths as the lengths
# of the word statistics in the printing. @0 is used rather than @a to save
# a space below.
# Now allocate the result to $_ so that it will get printed by -p.
$_=@F
# First the number of words
.": $_.\n$m: "
# Then the top line and the overall statistic.
.pack"@0A*",map b,@F
# Then for each word, the individual statistics, padded to the right length,
# except the last which takes as long as it takes.
#############################################################################
seano 164.24
-ap056 $_=lc,$_=y/aeiouy//.'/'.s/\w//gfor$g=$_="@F",@F;$_&&=1+s/\S+
/$"^$"x4|$&/eg.(s/(.{57}).{4,}/$1.../,": $_
$g: ").(s/[^ .]+ */shift@F|$"x18&$&/eg,/\D*$/,"$`
")
#############################################################################
#!perl -ap056
$_=lc,$_=y/aeiouy//.'/'.s/\w//gfor$g=$_="@F",@F;
# Starting from the back: put the sentence with a single space between each
# word in $_ and in $g. Then modify $g and @F so that they contain the
# overall and word statistics instead of the sentence and the words.
$_&&=
# If $_ contains any words, set it equal to the following.
1+s/\S+ /$"^$"x4|$&/eg.
# Change all words except the final word (s/\S+ /...eg/) so that they are
# increased to length at least 3 (the word with its space is logical-or'ed
# with ($"x$")x4, i.e. 4 nulls). Put one more than the number of these
# operations, i.e. the total number of words, at the start of $_.
(s/(.{57}).{4,}/$1.../,
# Next, if the sentence is too long, truncate it.
": $_
$g: ").
# And add the sentence and the overall statistic to $_.
(s/[^ .]+ */shift@F|$"x18&$&/eg,
# Now adjust the sentence to turn it into the second line. For each word in
# it, replace the word by the next word statistic, logical-or'ed with as many
# spaces as there are in the word to pad the statistic out to the right
# length. At least, that's what's meant to happen, but there are two bugs.
# First, the maximum number of spaces is set to 18, whereas up to 58 may be
# needed. Secondly, $" & $& produces null when $& is a capital letter, so the
# statistic may be padded with nulls instead of spaces. The quick fix is
# $" xlength$&, but that's another four characters.
/\D*$/,
# Find the non-digits at the end of the expression...
"$`
")
# ...and add to $_ the bit before them.
#############################################################################
Lolly Pop 162.29
-ap056 @q=map{s/$/
/until/\.|...$/g;$"x++pos|($Q=lc=~y/aeiouy//."/".y/0-9A-z//)}@F,$_;s/(.{57}).{4,}/$1.../,$_=@F.":
$_
$Q: @q[0..s/ [^ .]//g]
",s/ +$// if$_="@F"
#############################################################################
#!perl -ap056
@q=map{s/$/ /until/\.|...$/g;
# For each word, and for the whole line, pad with spaces until it is at least
# three characters long, unless it has a full stop...
$"x++pos|($Q=lc=~y/aeiouy//."/".y/0-9A-z//)}@F,$_;
# ... and also calculate its statistic, and pad that out to the right length.
# The ++pos finds the end of the word or line because of the regexp above.
# The statistic is then bitwise-or'ed with this many spaces. Luckily digits
# and slash are unchanged by this operation. All the padded statistics are
# saved in @q, and the last, the overall statistic, in $Q.
# At this point, $_ is set to "@F", the sentence with a single space between
# each word, by the if at the bottom. The rest is only done if there were any
# words.
s/(.{57}).{4,}/$1.../,
# Truncate the line if necessary.
$_=@F.": $_
$Q: @q[0..s/ [^ .]//g]
",
# Print the line. @q[0..s/ [^ .]//g] counts the words on the top line, and
# only includes that many word statistics.
s/ +$//
# Strip the spaces off the end of the second line.
if$_="@F"
# See annotation above.
#############################################################################
Rick 161.24
-056ap
@c=map{s!$!$"x(3-/\./-pos)!e;$"x$-[0]|lc=~y/aeiouy//.'/'.s/\w/$&/g}$_,@F;$_="@F";s/(.{57}).{4,}/$1.../;s!.+!$#c:
$&
@c[0..s/[ .]+//g]
!;s/ +(.*?) *$/: $1/
#############################################################################
#!perl -056ap
@c=map{s!$!$"x(3-/\./-pos)!e;
# For the sentence and each word, pad with spaces to three characters unless
# it has a full stop...
$"x$-[0]|lc=~y/aeiouy//.'/'.s/\w/$&/g}$_,@F;
# ... and also calculate its statistic, and pad that out to the right length.
# $-[0] contains the length of the word because of the s/$/.../ in the previous
# line.
$_="@F";
# Form the sentence from the words with a single space between each.
s/(.{57}).{4,}/$1.../;
# Truncate the sentence if necessary.
s!.+!$#c: $&
@c[0..s/[ .]+//g]
!;
# If $_ is non-empty, change it to the final answer. $#c counts one fewer than
# the number of statistics, which is the number of words. @c[0..s/[ .]+//g]
# counts the words on the top line, and only includes that many word
# statistics.
s/ +(.*?) *$/: $1/
# The @c in the previous command included the overall statistic. So munge the
# second line to format the beginning of the line properly, and to strip
# spaces off the end.
#############################################################################
Marko 160.35
-ap056 @f=map{$_|=$:^$:;$"x+y||
-z|c|y|youYOUaiIEeA||.'/'.s|\w|$&|g}$_,@F;s,(.{57})..+\w.*,$1...,,$#f=@R=/\w\S*/g,$_=@F."
$_
@f
"if$_="@F";s; +(.*?) *$;: $1;mg
#############################################################################
#!perl -ap056
@f=map{$_|=($:^$:);
# $: equals " \n-", which makes $:^$: equal to three nulls. (I've always
# wanted to use $: in a golf solution, and it seems I missed my chance).
# So for the whole sentence and each word, pad to three spaces with nulls...
($"x+y// -z/c)|(y/youYOUaiIEeA//.'/'.s/\w/$&/g)}$_,@F;
# ... calculate the statistic, and pad the statistic to the right length with
# spaces. The y// -z/c has two functions. It changes the nulls we generated
# in the previous line to spaces, while leaving the other characters up to z
# alone, and it counts the length of the word for padding the statistic.
# At this point, $_ is set to "@F", the sentence with a single space between
# each word, by the if below, and the next three commands are only done if
# there were any words.
s/(.{57})..+\w.*/$1.../,
# Truncate the sentence if necessary.
$#f=@R=/\w\S*/g,
# Assigning $#f to the number of words in the sentence shortens @f.
$_=@F." $_
@f
"
# Put the result in $_.
if$_="@F";
# See above.
s/ +(.*?) *$/: $1/mg
# The @f in the previous command included the overall statistic. So munge the
# second line to format the beginning of the line properly, and to strip
# spaces off the end.
#############################################################################
Eugene 151.23
-ap056 sub t{lc=~y/aeiouy//.v47.s//$&/g}$_=/\w/&&(@z=map$_^t^($_^=t^t),@F).": @F
${\t}: @z
";y/\0/ /;s/ +$//m;s/( .{57})...+(.
.* .{0,56}\S+).*/$1..$2/
#############################################################################
#!perl -ap056
sub t{lc=~y/aeiouy//.v47.s//$&/g}
# A subroutine to calculate the statistic. v47 is the same as '/' but has
# better tie break score.
$_=/\w/&&
# If there are any words in the sentence, set $_ equal to the following.
(@z=map$_^t^($_^=t^t),@F).
# For each word, first find the length of its statistic, and pad it to that
# length with nulls (That's just the inmost bracket! t is the statistic, so
# t^t is a string of nulls of the length of the statistic, and $_^=t^t pads
# $_ to that length).
# Now write the map as map{t^$_^$_}@F, where $_ is now the padded $_. So
# this now pads the statistic to the length of the (possibly padded) word.
# In summary, the expression $_^t^($_^=t^t) does both paddings!!!
# Save the list of padded statistics in @z, and put the number of these,
# which is the same as the number of words, as the first thing in the answer.
": @F
${\t}: @z
";
# The rest of the answer. ${\t} calculates the statistic again, for the whole
# line.
y/\0/ /;
# Change all the nulls into spaces. Using a literal null instead of \0 is one
# stroke shorter, but the referees didn't allow nulls in solutions.
s/ +$//m;
# Either the first line or the second line, but not both, could have become
# over-padded, so whichever it is, drop the final spaces.
s/( .{57})...+(.
.* .{0,56}\S+).*/$1..$2/
# We've still got the problem that the line can be too long. If it is, just
# use the first 57 characters of the top line, and whichever statistics in
# the bottom line start before that character.
#############################################################################
Ton 150.22
-ap056 @Q=map{lc^lc^lc=~y/aeiouy//.-map/\w/g,$_^=v0
x3}lc,@F;$_="@F"&"�"x60;s/[^.]{3}$/ /;s/.+/$#Q $_
@Q[0..split]
/;y!\0 -! ./!;s/ +(.*\S) */: $1/g
#############################################################################
#!perl -ap056
@Q=map{lc^lc^lc=~y/aeiouy//.-map/\w/g,$_^=v0 x3}lc,@F;
# Start from the back. For the whole line, and for each word, do some things.
# ($_ works just as well as the last lc, but lc has better tie-breaker.)
# The things are:
# 1) pad the word to at least three characters with nulls ($_^=v0 x3).
# 2) calculate the statistic, but as "vowels-alphanumerics" instead of
# "vowels/alphanumerics"!
# 3) pad the statistic to the length of the word with nulls (lc^lc is a
# string of nulls of the length of the word. Note that lc^lc^lc does
# not occur in this command despite appearances to the contrary: it's
# parsed as lc^lc^(statistic)).
$_="@F"&"�"x60;
# Write $_ as the words with a single space between each, but shortened to
# at most 60 characters.
s/[^.]{3}$/ /;
# If we have three non-dots at the end (so the line was too long), change
# them into three tabs.
s/.+/$#Q $_
@Q[0..split]
/;
# Assemble the line. split in scalar context counts the number of words on
# the first line. It is important that the dots at the end of the line are
# tabs here, so that the split on whitespace doesn't pick up an extra word.
y!\0 -! ./!;
# Now change nulls to spaces, tabs to dots, and dashes to slashes. This
# causes the program to fail the test script, but that's because the script
# is buggy: it contains dashes which are not legal characters according to
# the rules
s/ +(.*\S) */: $1/g
# The @Q[0..split] earlier included the overall statistic. So munge the
# second line to format the beginning of the line properly, and to strip
# spaces off the end.
#############################################################################