develooper Front page | perl.fwp | Postings from January 2002

Keith's SUAP explanation

Thread Previous | Thread Next
Keith C. Ivey
January 28, 2002 20:56
Keith's SUAP explanation
Message ID:
3C55E56F.31124.1FCFFFD0@localhost wrote:

> So as soon as you can after the game has finished, I would like
> the golf "artists" to prepare a little description of your
> solution, explaining how it works so beginners can understand,
> describing you thought of it, and so on.
> I will give advance notice, at least:
>   Eugene  (77 char solution)
>   Keith   (74 char solution)
>   BooK    (your gs solution, you know the one)
> should definitely participate!

Thanks for the invitation, and thanks very much for running 
another contest!

I see that several other people tried approaches using the ^ 
operator, but since mine was the shortest and probably the 
weirdest, I'd better explain.

#!/usr/bin/perl -n

Minus the obfuscation and golfish shortening, that's

#!/usr/bin/perl -n
$t = $. & 1;
$t ^= 7 . tr/aeiouy// * ord for /./g;
$t || print;

The -n means that each line of the input file is read and 
assigned to $_.  The next line sets a test variable to 0 if $. 
(the line number) is even and 1 if it's odd.  The next line 
loops through all the letters in the line (the . in the regex 
doesn't match the newline, because there's no /s modifier, and 
/<whatever>/g in a list context returns all the matches).  For 
each letter, the result of tr/aeiou// (1 if it's a vowel, 0 
otherwise) is multiplied by the ASCII value of the letter, and 
then a 7 is appended to the front.  The result of this strange 
operation is xored with the test variable.  So for each letter 
in the word, one number is included in the xor: 797 for "a", 
7101 for "e", 7105 for "i", 7111 for "o", 7117 for "u", 7121 
for "y", and 70 for anything else.  If you examine the bit 
patterns of those numbers carefully (or run an exhaustive test 
program), you'll find that there's no way to combine them with 
xor so that they produce 1, and that the only way they can 
produce 0 is if there's an even number of each (so that each 
number cancels itself out).  That means the test value will 
never be 0 unless the line number is even and the word contains 
even numbers of "a"s, "e"s, "i"s, "o"s, "u"s, "y"s, and 
consonants.  And an even number of consonants means an even 
length for the word if the vowel restrictions are met.  The 
final line prints the word if the test variable is 0.

It took me a while to work out a calculation that would give 
seven separate results (one for each vowel, and one for 
everything else) that could not be xored together in such a way 
that all the bits canceled out.  I submitted a couple of 
entries that passed the test program but that I realized later 
weren't right.  The first ones were this series:

#!/usr/bin/perl -ln
$%=0;$%^=ord for/[yuoeia]/g;$%||1&($.|y)))c)||print

#!/usr/bin/perl -ln
$%=$.&1;$%^=ord for/[yuoeia]/g;$%||1&y|||c||print

#!/usr/bin/perl -ln
$%=($.|y|||c)&1;$%^=ord for/[yuoeia]/g;$%||print

Unfortunately, simply taking the ASCII value of each vowel (in 
these I was ignoring the consonants and checking the length 
separately) didn't give a set of values with the right 
property.  The programs passed the test suite, but that was 
only because the test suite didn't contain any words with odd 
numbers of "e"s, "i"s, "u"s, and "y"s -- impudently unwieldy 
words such as might be used fruitlessly by flunkeyish yuppies 
(as I told Andrew).  I withdrew the entry and substituted 
something longer.

Later I came up with these:

#!/usr/bin/perl -ln
$%=($.|y|||c)&1;$%^=7+ord for/[yuoeia]/g;$%||print

#!/usr/bin/perl -n
$==$.&1;$=^=7+y*yuoeia***ord for/./g;$=||print

But adding 7 to the ASCII values of vowels and using 7 for 
consonants wasn't the solution, either.  I had neglected to 
look at the effect of the initial $.&1 term.  While it wasn't 
possible for the values of the letters to cancel each other 
out, they could combine to cancel out the initial 1 resulting 
from an odd line number.  If a word with odd numbers of "i"s 
and "o"s, like "point", occurred on an odd line, it would 
result in a 0 test variable and be printed erroneously.

I conducted a search for a digit and operator that would fit 
the bill, and I found 7 (among other candidates) and the . 
operator.  Alas, the . did have to be preceded by whitespace to 
avoid a syntax error, so I lost a stroke there.

Andrew's choice of this hole was just right.  Challenging 
enough to keep people away from their work and families until 
the last moment, and with multiple promising approaches.

Keith C. Ivey <>
Washington, DC

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About