Ever since Elin came into my life, things just became a lot better.
Someone you can bounce things off, somebody who is a great friend.
We do just about everything together. It's nice having that type of
person around you. She's so much like me. She's very competitive,
very feisty, just like I am.

Curiously, in addition to code golf, I've enjoyed a life long
passion for real, physical golf.
Though I can't compete with Tiger Woods (either on or off the golf course),
my golf was once strong enough to represent my club in pennant matches.
I fondly remember competing against other clubs in the good ol' days,
especially punching the air with my fist while eyeballing my match play
opponent after holing a crucial putt from the edge of the green.
Though unable to physically eyeball my code golf opponents nowadays,
I do frequently indulge in Tiger-esque fist pumps while code golfing at my desk,
sometimes even leaping out of my chair to do so.

By all accounts though, I'm nowhere near as competitive, or feisty,
as Tiger Woods and his wife Elin.
Nonetheless, I am a very competitive person.
So, while acknowledging the learning aspect of the game,
and appreciating its artistic side,
the main attraction of code golf, for me, has always
been fun and competition.

And this game was chock full of stimulating competition.
Long before Jasper began his historic Perl whittle,
my competitive juices were squirting at the Python and PHP leaderboards:
Python because of an even more relentless whittler than Jasper,
namely Norway's leading golfer, hallvabo;
PHP because I found myself locked in a duel with legendary Texan PHP golfer
ToastyX, winner of 15 of 16 PHP golf contests, often by ridiculous margins.

First to Python and hallvabo. Last April, just hours after I posted my Roman article,
hallvabo, who had been breathing down my neck just one stroke off the pace,
sprinted past me snatching the Python lead from my clenched fists, which
were now shaking in fury in the general direction of Norway and
its majestic fjords.

looks much more Perlish to me, exploiting three of Perl's distinctive features:
autovivification; space insertion between array elements when
string interpolating; and default arguments
to Perl built-ins.
And Jasper's proved to be the superior Perl golf approach.

Alas, Jasper's beautiful and elegant Perl solution
transmogrifies into a grotesque monster when translated
into any of the other three languages:
no autovivification; no default arguments to built-ins; no insertion of
spaces between interpolated array elements; sin and cos built-ins AWOL
in Python and Ruby; and PHP's array semantics just too weird for words.
And that's just listing the obvious horrors.

Finding the "right" golfic approach for each language is something of
a dark art and there is precious little advice available on this difficult topic.
Shed light on this
dark side
of programming, this article will.

Before revealing my shortest Ruby, Python and PHP solutions therefore,
I'll compare and contrast how different aspects of this game
are best coded in each of the four languages.

Reading and Converting Hours and Minutes from Stdin

Let's begin by analysing a basic part of any solution to this game:
reading the digital time from stdin and converting to a 0..11 clock face mark.
In all four languages, this aspect of my solutions remained
essentially unchanged throughout this competition.

Technique

Perl

Ruby

Python

PHP

Reading HH:MM

<>=~/:/

r=*$<

r=raw_input()

$r=fgets(STDIN)

Extracting hours

$`%12

r.to_i%12

int(r[:2])%12

$r%12

Extracting minutes

$'/5

r[3,2].to_i/5

int(r[3:])/5

"$r[3]$r[4]"/5

Number of strokes

16

27

38

34

Of all the aspects of this game, this one most clearly demonstrates
why Perl and Ruby have defeated Python and PHP in 27 of 28 games played
at the codegolf web site.
Most codegolf challenges require you to read from stdin and there is
simply no short way to do that in Python and PHP.

Note that Python is the only language whose string to int
conversion routine refuses to convert the string "12:" to the integer 12,
forcing you to employ r[:2], rather than plain old r,
at a cost of four strokes.
While this extra level of strictness may well be a boon when writing
production code, it's an irritant when golfing.

Note too how many strokes the Ruby and Python string to int conversions consume.
Were it not for this handicap, I suspect Ruby would mostly out-golf Perl.

Eliminating Jasper's "god-awful ternary"

In case you've forgotten, and as discussed last time, Jasper's
infamous "god-awful ternary" is:

Eliminating this eyesore was a fascinating
challenge in this game in all four languages.

Technique

Perl

Ruby

Python

PHP

Jasper's eyesore

($_^$h?o:x)&($_^$m?o:'}')

'ohmx'[1&1>>i-h^2&2<<i-m,1]

'ohxm'[-(i==m)^(i==h)]

($i^$h?o:x)&($i^$m?o:'}')

Number of strokes

25

27

22

25

As will be seen later when the shortest solutions for each language
are revealed, the above table is quite crude in that it does not take
account of the many tactical wrinkles available in this game.
Having said that, it does help us understand the fundamentals
of each language.
In particular, note that:

Python does not support string bitwise operators. You can fake them, but you don't want to. No, really you don't: chr((i^h and 111or 120)&(i^m and 111or 125)). Python's lack of a short ?: operator is fatal here. These sorts of problems are almost always better golfed using Python's powerful and concise string slices, in this case: 'ohmx'[expr].

Though Ruby does not support string bitwise operators, you can fake them with: (i==h ??x:?o)&(i==m ??}:?o). The two stroke ?o (rather than 111) combined with a short ?: operator makes this approach more attractive than in Python. Nonetheless, shorter Ruby alternatives are available via 'ohmx'[expr]. Note that i==h above cannot be shortened to i^h or i-h, as it was in the other languages, because zero evaluates to true in Ruby.

Ruby does not allow Booleans in numeric expressions, making expr in 'ohmx'[expr] much more challenging to concoct than in Python.

Surprisingly, and unlike Python, Ruby returns the integer ord value if you use 'ohmx'[expr], forcing you to essay the longer 'ohmx'[expr,1] or '%c'%'ohmx'[expr] to get at the character.

Perl and PHP, unlike Python and Ruby, do not allow you to address individual characters in a string via the clear and concise 'ohmx'[expr] notation. Though Perl does provide substr for this purpose, that is usually too long for golf. I'd love to see Perl support the 'ohmx'[expr] notation for strings.

All four languages allow you to index strings and arrays from their end via negative indices. This proved handy here in Python in that [-(i==m)^(i==h)] is one stroke less than the pedestrian [2*(i==m)+(i==h)]: the latter generates indices of 0,1,2,3; the former 0,1,-2,-1.

In PHP, '}' above can be shortened by one stroke by exploiting the string bitwise negation operator, as described in the next section.

Python Update: Much later I learnt that hallvabo applied his favourite
slice and dice technique in this game.
That is, instead of:

Perl is perhaps the only computer language in history where the ability
to compose poems affected its design.
Without use strict, Perl is poetry for golfers because barewords,
sans quotation marks, are two strokes shorter than equivalent quoted strings.
How on earth did barewords come about?
Well, when Larry was designing Perl at JPL in the early 1990s, his concentration was
frequently interrupted by poetry readings in the next cubicle.
His cubicle buddy from those early days, you see, was gifted poet Sharon Hopkins.
And Sharon liked writing poems in Perl. This most improbable chance circumstance
affected the early design of Perl, with barewords a feature added primarily to allow
Sharon to write better Perl poems. Incidentally, Sharon remains a close Wall
family friend today -- though I have no information on whether Perl 6 will
similarly feature a Sharon-inspired poetry mode.

A Perl bareword starts with an "alphabetic" [A-Za-z_] character and
is followed by zero or more [A-Za-z_0-9] characters.
This is an oversimplification though, in that some lowercase characters,
such as m and s, require quoting to disambiguate them from
Perl operators (such as pattern match m and substitution s).
All other characters, in particular those in the ord range 127-255, require
quoting in Perl.
But not in PHP, as we shall see.

Oh, freddled gruntbuggly thy micturations are to me
As plurdled gabbleblochits on a lurgid bee.
Groop, I implore thee, my foonting turlingdromes.
And hooptiously drangle me with crinkly bindlewurdles
Or else I shall rend thee in the gobberwarts with my blurglecruncheon, see if I don't!

Like Ford and Arthur, I'm sure I'd find listening to PHP poetry agonizing.
That said, I'm (thankfully) unaware of any sort of PHP poetry community,
and so have no idea why barewords are similarly allowed in PHP.
Perhaps for Perl compatibility.
Curiously, PHP allows many more barewords than Perl because characters
in the ord range 127-255 are deemed "alphabetic" by PHP.
Whether this was a deliberate design decision or an accident of implementation,
I don't know, but golfers are fond of it because combining this eccentric "feature"
with PHP's Perl-like string bitwise ~ operator allows you to
save at least one stroke with just about any string!
In this game, for instance, the string '%' requires three strokes in the
other three languages. Not so in PHP. Given that ord(~'%') evaluates to 218
(i.e. 255-ord('%')), you can write the three stroke '%' string as a
two stroker, namely ~X, where X is the character with ord value 218.

Python is the BOM

Python and Ruby always require all strings to be quoted.
Hardly poetic, but more sensible IMHO.
Ruby provides no further restrictions that I'm aware of.
Python, on the other hand, is annoyingly picky.
The characters with ord values 0 (NULL), 10 (LF) and 13 (CR)
cannot be placed inside quoted strings; you must use the two stroke
escapes \0, \n and \r instead.
Worse, characters in the ord range 128-255 cannot be placed inside Python
quoted strings at all unless you start the file with a three character
UTF-8 BOM,
namely chr(0xef).chr(0xbb).chr(0xbf).
That is, you have to take a three stroke penalty drop in Python to use strings
in the 128-255 ord range; this proved crucial in this game, as will be
seen later.

String Interpolation

Consider how to create a "Dear John" string in each of the
four languages:

What's the shortest way to create this peculiar printf format string
in each of the four languages?

Technique

Perl

Ruby

Python

PHP

String interpolate

"%@{[expr]}s"

"%#{expr}s"

"%%%ds"%expr

~X.expr.s

Number of strokes

13

11

12

9

where X above is the character with ord value 218.
Poor old
Baby Cart
baby-stepped to the finish line in last place in this oddball race.
This is hardly surprising given Baby Cart was not really designed; it was
independently "invented" shortly after Perl 5 was released in 1994
by both L.Wall and R.Schwartz ... and later celebrated as one of Perl's
secret operators.

String Multiply

Consider how to create a string of five Xs in Python, Ruby, Perl and PHP:

That is, the string multiply operator is commutative in Python,
but not in Perl or Ruby.
This language idiosyncrasy makes string multiply based solutions
most attractive in Python. To illustrate, note these code snippets
from my string multiply based solutions to this game:

Of note in this solution is the ~60495%i/4 magic formula,
three strokes longer than the earlier Perl one of 318%i/9.
Why on Earth would I do that?
Well, by going longer on the magic formula, my search program
revealed that I could constrain the magic string to
characters in the 0-127 range and thus avoid
Python's dreaded three stroke BOM penalty.
Crucial here is that the former magic formula, though three strokes
longer, only costs two strokes in practice because of the
requirement for a space after print, as shown below:

Using %c looks odd, but turned out to be shorter because you now don't need
a trailing ,1 in expr in 'ohmx'[expr].

I really struggled with the expr in 'ohmx'[expr] above because
Ruby, unlike Python, does not allow Booleans to be used in
numeric expressions.

Generally, my Ruby golf is pretty weak, so I expect someone
like flagitious could peer at the solution above, pull a face, and then shorten
it with ease.

Number of Leading Spaces

For subtle tactical reasons, the Perl, Python and Ruby
string multiply based solutions differ slightly in the
number of leading spaces, as shown in the table below.

Index

Perl 318%i/9

Python ~60495%i/4

Ruby 327%i/9

0

8

8

9

1

4

4

5

2

7

6

8

3

1

1

2

4

13

12

14

5

0

0

1

6

15

14

16

7

1

1

2

8

13

12

14

9

4

4

5

10

7

6

8

11

8

8

9

Notice that the Ruby solution, using "%#{327%i/9}c",
requires one more space for each index than Perl's plain
string multiply $"x(318%$_/9).
The Python solution, on the other hand, requires one less space
than the Perl one, but only for indices 2, 4, 6, 8 and 10
(corresponding to clock face marks 1, 2, 3, 4 and 5).
This is due to a quirk in Python's print statement when
you end it with a comma to suppress the usual newline
suffix: if what is printed does not already end in a newline
(as in the print statements before clock face marks
1, 2, 3, 4 and 5), the newline suffix is replaced by
a space.

PHP (129 strokes)

Lacking a string multiply operator, I had little choice but to squeeze all
I could out of printf, constructing a PHP version of my 102 stroke
Perl "Baby Cart" solution, discussed earlier.

Of note in this solution is the exploitation of printf's
return value to terminate the loop.
Notice that PHP's printf function --
like C, but unlike Perl, Ruby and Python -- returns
the number of characters output.
For this "loop termination via printf return value" trick to work, the
printf return value corresponding to the last clock face mark (i.e. 6)
must be distinct from all the other clock face marks.
Luckily, for clock face mark 6, we have a choice of three
different printf format strings, namely 9.1, 10.2 and 11.3.
And we need them, for only one of them, 11.3, is distinct.
Like most winning golf solutions, this one requires an element of luck.

I had an enjoyable tussle with ToastyX in this game.
He was about 20 strokes ahead at one point, but I "did a Jasper"
and just kept on relentlessly whittling until I eventually overtook him.
After this protracted duel, ToastyX and I found ourselves
30 strokes clear of the field.

Hanging up the Clubs

Much as I enjoy playing golf, it's taking more time than I can afford,
so it's time to hang up the clubs for now.

Sometimes I think I enjoy writing articles about golf
more than actually playing.
I hope you've enjoyed reading this series of articles
as much as I've enjoyed writing them.

What was ToastyX up to?
If he'd read my node and wanted to catch up, why not
just post 129?
What's with the failed 127 and 128 attempts?
Of course, it's perfectly possible he had
not read my node and, Jasper-like, concocted
a completely different 129 stroke solution.
I had no way of knowing, but
was alarmed by those failed 127 and 128 attempts.
My previous golfing experience told me that failed
attempts like these are frequently followed
by a successful submission.
To lose the lead now would be intolerable.
What to do?

looking for anything that makes me pull a face.
The only thing that truly disgusted me was
the hideous "$r[3]$r[4]" expression.
Surely something can be done to shorten this.
I started by rechecking the excellent
wikipedia string function comparison page.
Nope, PHP does not support string slices, a la Python and Ruby,
no matter how much I'd like it to.
The best I could find was substr($r,3) --
which is exactly the same length as before.

PHP function names tend to be quite verbose, so the best chance
is surely to apply an operator to $r.
What about our old friend, the string bitwise & operator?
If I could apply this operator to convert the first three characters
of $r to white space, while leaving the last two characters
unchanged, that would do it.

To investigate this possibility, I started by running a little Perl program:

is essentially a PHP version of the 103-stroke Perl
solution described in detail at Spending Time on Saving Time [golf],
where GGGGGGGGGGGGGGGGGGGGGGGG is a (bitwise negated) 24 character string with ord values
0, 8, 22, 40, 59, 77, 92, 102, 84, 63, 43, 26, 14, 9, 23, 24, 41, 42, 60, 61, 78, 79, 93, 103,
XXXXX is a string with ord values 176, 176, 176, 255, 255,
B is ord value 253 (i.e. "}" with the high bit set),
S is ord value 160 (i.e. space with the high bit set),
and N is ord value 138 (i.e. newline with the high bit set).

ToastyX deserved to win the game with this brilliant concoction
because it can easily be shortened by five strokes simply
by removing the chr() above.
Maybe he knew PHP too well and didn't bother
to look up the strpos function.
As a PHP novice, I looked it up and was surprised
to learn that, in addition to a character string, strpos also
accepts an ord value as its second argument, thus making
the chr() wrapping unnecessary.

where h represents hours (0..23) and m minutes (0..11).
How to shorten?

Though relying on inspiration in cases like these might work on a good day,
a more dependable approach is to write a program to search for shorter solutions.
Accordingly, I wrote the following Ruby brute force searcher:

As an aside, writing "eval" search programs like these seems to be a good way
to unearth bugs in dusty corners of a language; at least, I had to remove
'**' from the sym array above to workaround various random
crashes and hangs of the Ruby interpreter.

Anyway, after dutifully chugging away for several hours, the above program
did find a lucky hit, namely:

Of course, I have no idea if this is the same one stroke improvement that leonid found.
If not, and he reads this post, I expect shortly to watch him move ahead to 110 strokes. :)

My main point is that relying on inspiration alone, I doubt I would ever
have thought of this new shortened solution.
That is, writing and running little search programs like these is part
and parcel of being a serious golfer.

Update: Some time later, I discovered an easier way to get to 111
by changing the way hours and minutes are extracted from stdin, as shown below:

By way of explanation, note that the Ruby gets function automatically
sets $_. And, like Perl, ~/:/ automatically sets $'.
Unlike Perl though, ~/:/ returns the (zero-based) index of the match.
In this game therefore, ~/:/ always returns two (the index of :
in, for example, 12:34).

At first glance, the new method looks like a step backwards
because it consumes one more stroke than the original.
As is often the case in golf though, a tactical trick is available
to shorten it.
By pure luck, you see, the original 2&2<<i%12-m expression
contains two twos! So we can replace one of them with the return value of
~/:/ thus transforming the new approach from one stroke longer
to one stroke shorter:

This (cheating) 126-stroke Python "solution" is not
correct for all possible inputs but has a good chance
of passing the (poor) set of test data provided for
this game.
To clarify, I chose 42 in the original magic formula
for artistic effect only; any number greater than
eleven will do.
Replacing 42 with i therefore works
for eleven of the twelve string ord values, namely
48, 23, 85, 22, 86, 87, 20, 88, 31, 77, 78 ... but fails
for the single ord value that is less than eleven,
namely the 9 that forms the string's sixth character.

Hallvabo was kind enough to send me his two best solutions to this game.
Here is his (second-placed) 128 stroke Python entry:

where XXXXXXXXXXXX above is a string with ord values
72, 71, 205, 34, 158, 9, 147, 20, 160, 43, 101, 186.
Note that both these solutions require a leading 3-character BOM (0xef, 0xbb, 0xbf).
Note too that hallvabo employed his favourite "slice and dice" trick once again, just as he did in 99 Bottles of Beer.

It never occurred to me to use "slice and dice" in this game.
As it turns out, the two different techniques produce
similar lengths, as indicated below:

While I'm still able to remember, I list below the other new
(albeit unsuccessful) Ruby solutions I found while searching
for the elusive 111 stroker.
It's possible I've missed something and one of these
attempts might be transformed from a loser into a winner.

The following solutions are all of a similar form to the
original 111 stroker, namely: