<?xml version="1.0" encoding="windows-1252"?>
<node id="997591" title="Compression in Golf: Part II" created="2012-10-06 03:18:02" updated="2012-10-06 03:18:02">
<type id="120">
perlmeditation</type>
<author id="176576">
eyepopslikeamosquito</author>
<data>
<field name="doctext">
&lt;P&gt;
Preparing our [id://811919|Saving Time] solution for a "pack u" makeover,
as we performed last time in [id://995190], proved straightforward:
 &lt;ul&gt;
  &lt;li&gt; &lt;C&gt;"}"&lt;/C&gt; was replaced with &lt;C&gt;v125&lt;/C&gt;. Cost: one stroke.
  &lt;li&gt; Hard newline replaced with &lt;C&gt;\n&lt;/C&gt;. Cost: one stroke.
  &lt;li&gt; &lt;C&gt;for&lt;/C&gt; loop replaced with &lt;C&gt;map&lt;/C&gt;. Cost: one stroke.
  &lt;li&gt; &lt;C&gt;&lt;&gt;!~/:/..11&lt;/C&gt; replaced with &lt;C&gt;0..s//&lt;&gt;/e./:/&lt;/C&gt;. Cost: three strokes.
 &lt;/ul&gt;
In summary, our original 96-stroke solution was transformed
into a 102-stroke pack-friendly one like so:
&lt;CODE&gt;
# original 96-stroke solution
$c[$_*=.52,5.5-4.7*cos][8+7.4*sin]=($_^$`%12?o:x)&amp;($_^$'/5?o:'}')for&lt;&gt;!~/:/..11;print"@$_
"for@c
# 102-stroke pack-friendly makeover
map$c[$_*=.52,5.5-4.7*cos][8+7.4*sin]=($`%12^$_?o:x)&amp;($'/5^$_
?o:v125),0..s//&lt;&gt;/e./:/;print"@$_\n"for@c#```
&lt;/CODE&gt;
That six stroke investment was returned with interest,
the compressed solution being
three strokes shorter than the original.
&lt;/P&gt;

&lt;P&gt;
Well, that seemed pretty easy.
So let's apply the same trick to the classic [id://903641|99 Bottles of Beer].
&lt;/P&gt;

&lt;P&gt;
That chore turned out to be more laborious than expected,
and of a completely different character.
You see, the shortest (160-stroke) [id://903641|99 Bottles of Beer]
solution:
&lt;CODE&gt;
@c=(@b=(++$n,bottle.'s'x@-,of,beer),on,the,wall),s//Take one down and pass it around, @c.

@c, @b.
/until/, 99\D+/;print$'."Go to the store and buy some more$&amp;"
&lt;/CODE&gt;
apart from being significantly longer,
has an entirely different set of pack-hostile bytes
to deal with, namely:
 &lt;ul&gt;
  &lt;li&gt; Sixteen spaces.
  &lt;li&gt; Three hard newlines.
  &lt;li&gt; Three uppercase characters: T, D and G.
 &lt;/ul&gt;
Sixteen spaces. &lt;B&gt;Sixteen&lt;/B&gt; spaces! &lt;B&gt;Sixteen spaces!!&lt;/B&gt; Aargh!
Oh well, I suppose it could have been worse.
At least there are no pesky ord 123-126 ({ | } ~) characters to trouble us this time.
Yet dealing with those sixteen spaces proved to be an utter pest, as we shall see.
&lt;/P&gt;

&lt;P&gt;&lt;B&gt;How to deal with the sixteen spaces?&lt;/B&gt;&lt;/P&gt;

&lt;P&gt;
I could see only three possibilities:
 &lt;ol&gt;
  &lt;li&gt; Use &lt;C&gt;$"&lt;/C&gt; instead of space; for example, replace &lt;C&gt;Take one&lt;/C&gt; with &lt;C&gt;Take$"one&lt;/C&gt;. Though perhaps the simplest solution, this comes at a horrendous cost of 16 strokes.
  &lt;li&gt; Use &lt;C&gt;v&lt;/C&gt; (say) instead of space; for example, replace &lt;C&gt;Take one&lt;/C&gt; with &lt;C&gt;Takevone&lt;/C&gt;. Then later translate via &lt;C&gt;y/v/\40/&lt;/C&gt; or &lt;C&gt;s/v/$"/g&lt;/C&gt;. This looks more promising, costing only nine strokes: eight for the translation expression, one for a separating comma. The &lt;C&gt;\40&lt;/C&gt; is unfortunate yet I couldn't find anything shorter.
  &lt;li&gt; Use a list and exploit the space automatically inserted between each element when a list is stringified as we already do with &lt;C&gt;@b&lt;/C&gt; and &lt;C&gt;@c&lt;/C&gt; above. Though this approach has perhaps the greatest potential, there are awkward tactical problems to solve.
 &lt;/ol&gt;
If you can think of other approaches, I'm all ears.
&lt;/P&gt;

&lt;P&gt;&lt;B&gt;How to deal with the three newlines?&lt;/B&gt;&lt;/P&gt;

&lt;P&gt;
You can simply replace a hard newline with &lt;C&gt;\n&lt;/C&gt; or &lt;C&gt;$/&lt;/C&gt;, at a cost of three strokes, one per hard newline.
&lt;/P&gt;

&lt;P&gt;
Alternatively, if you are already using &lt;C&gt;y/v/\40/&lt;/C&gt; to convert spaces,
you can sneak in a newline conversion too via &lt;C&gt;y/v_/\40\n/&lt;/C&gt;, say,
where underscore is used in place of hard newline.
This also has a three-stroke penalty.
&lt;/P&gt;

&lt;P&gt;&lt;B&gt;How to deal with G, T and D?&lt;/B&gt;&lt;/P&gt;

&lt;P&gt;
&lt;C&gt;G&lt;/C&gt; can be replaced with &lt;C&gt;\ug&lt;/C&gt; or &lt;C&gt;v71&lt;/C&gt;, at a cost of two strokes.
Similarly, &lt;C&gt;T&lt;/C&gt; can be replaced with &lt;C&gt;\ut&lt;/C&gt; or &lt;C&gt;v84&lt;/C&gt;.
That's all I got.
Suggestions welcome.
&lt;/P&gt;

&lt;P&gt;
The &lt;C&gt;/, 99\D+/&lt;/C&gt; regex can be replaced with
&lt;C&gt;/,.99[^9]*/&lt;/C&gt; or &lt;C&gt;/,.99.*\n+/&lt;/C&gt; at a cost of two strokes.
&lt;/P&gt;

&lt;P&gt;&lt;B&gt;Back to the game&lt;/B&gt;&lt;/P&gt;

&lt;P&gt;
I really thought I was done with those damned beer
bottles. For good.
And then Ruby specialist "dmd" goes and posts a
(presumably compressed) 157-stroke Perl solution.
Well, I could hardly ignore this provocation.
Besides, due to dmd's (presumed) lack of Perl experience,
I felt quietly confident that I could overtake him
without too much effort.
Little did I know.
&lt;/P&gt;

&lt;P&gt;
The two (complementary) strategies I tried in this game are:
 &lt;ol&gt;
  &lt;li&gt; Focus on shortness. Seek out the shortest restricted pack-friendly character set solution you can find. Don't worry about formatting the thing.
  &lt;li&gt; Focus on formatting. Seek out algorithms that fit the required shape like a glove. Don't stress about shortness.
 &lt;/ol&gt;
&lt;/P&gt;

&lt;P&gt;
I quickly discovered that I could make no headway with
a mechanical translation of the shortest 160-stroke
solution to the "pack u" restricted character set.
A different approach was required.
So I kept trying different bottle golf algorithms
until I found approaches that seemed better suited
to the restricted character set environment.
&lt;/P&gt;

&lt;P&gt;
At this early stage, the two shortest solutions I had found were 179 strokes,
using a list to get rid of the wretched spaces (i.e. approach 3 above):
&lt;CODE&gt;
@m=(@z=(++$n,bottle.$&amp;,of,beer),on,the,wall),s/^/,$"@m.\n\n@m,$"@z.\n\u@j/until@j=/s/?(take,one,down,an.d,pass,it,around):(go,to,the,store,an.d,buy,some,more),/^99/m;print$&amp;.$'.$`
&lt;/CODE&gt;
and 180 strokes, replacing spaces with "v" then translating them later (i.e. approach 2 above):
&lt;CODE&gt;
s//\utakevonevdownvandvpassvitvaround,v@s.__/until@s=(@b=++$s.vbottle."s"x@b.vofvbeer,onvthevwall),s//@s,v@b._/,/99/;s/$/\ugovtovthevstorevandvbuyvsomevmore,v@s./;y/v_/\40\n/;print
&lt;/CODE&gt;
Many variations of these two solutions are available.
&lt;/P&gt;

&lt;P&gt;
Disturbingly, that's nineteen strokes longer than the original 160 stroker.
In percentage terms, 160/179 = 0.89 is considerably worse than the
96/102 = 0.94 ratio achieved with [id://995190|Saving Time].
And, to rub salt into the wounds, I couldn't make either of these
solutions fit snugly into any "pack u" shape.
&lt;/P&gt;

&lt;P&gt;
So I reluctantly switched to strategy two above (i.e. focus on shape-fitting)
and finally  managed to wrest the lead from "dmd" at 154 strokes
by shoehorning this longer 182-stroker:
&lt;CODE&gt;
$_=v71.ovtovthevstorevandvbuyvsomevmore;@z=($b=++$n.vbottle."s"x@+.vofvbeer,onvthevwall),s;^;\utakevonevdownvandvpassvitvaround,v@z.\n\n@z,v$b.\n;,y/v/\40/until/,.99[^9]*/;print$'.$&amp;
&lt;/CODE&gt;
into this "pack u54" shape:
&lt;CODE&gt;
#        1         2         3         4         5         6         7
#234567890123456789012345678901234567890123456789012345678901234567890123
v;$_=v71.ovtovthevstorevandvbuyvsomevmore;@z=($b=++$n.vbottle."s"x@+.vof.
vbeer,onvthevwall),s;^;\utakevonevdownvandvpassvitvaround,v@z.\n\n@z,v$b.
;,y/v/\40/until/,.99[^9]*/;print$'.$&amp;
#234567890123456789012345678901234567
#        1         2         3
&lt;/CODE&gt;
&lt;/P&gt;

&lt;P&gt;
The extra length of this solution is more than compensated
for by the perfect fit for the "pack u54" shape, notably
the &lt;C&gt;s;;;&lt;/C&gt; substitution near the end:
&lt;CODE&gt;
s;^;\utakevonevdownvandvpassvitvaround,v@z.\n\n@z,v$b.
;
&lt;/CODE&gt;
This is a miraculous fit:
two strokes are saved by replacing \n with pack's hard newline
and another is shaved by hijacking pack's ";" length byte
for use as the &lt;C&gt;s;;;&lt;/C&gt; substitution delimiter.
&lt;/P&gt;

&lt;P&gt;
After punching the air with my fist,
I hastily generated and submitted a 154-stroke solution
by running this little program:
&lt;CODE&gt;
my $source = &lt;&lt;'PERSEVEROUS';
v;$_=v71.ovtovthevstorevandvbuyvsomevmore;@z=($b=++$n.vbottle."s"x@+.vof.
vbeer,onvthevwall),s;^;\utakevonevdownvandvpassvitvaround,v@z.\n\n@z,v$b.
;,y/v/\40/until/,.99[^9]*/;print$'.$&amp;
PERSEVEROUS
my $out = unpack 'u54', uc($source);
open my $fh, '&gt;', 'b.pl' or die "error: open b.pl: $!";
binmode $fh;
print $fh "eval lc pack u54,'" . $out . "'";
&lt;/CODE&gt;
&lt;/P&gt;

&lt;P&gt;
Three strokes ahead now. Yay!
That should put Ruby upstart "dmd" in his place!
Or so I thought.
Within a few days however, the tenacious "dmd" struck
back by posting a 151 stroke Perl solution.
Drat. Back to the drawing board.
&lt;/P&gt;

&lt;P&gt;&lt;B&gt;References&lt;/B&gt;&lt;/P&gt;

&lt;P&gt;
 &lt;ul&gt;
  &lt;li&gt; [id://995190]
  &lt;li&gt; [id://1000179]
  &lt;li&gt; &lt;a href="http://terje2.frox25.no-ip.org/~golf-info/Book.html"&gt;Terje/mtv pdf book of Perl Golf&lt;/a&gt;
  &lt;li&gt; [id://811919]
  &lt;li&gt; [id://903641]
 &lt;/ul&gt;
&lt;/P&gt;

&lt;P&gt;
&lt;/P&gt;

&lt;P&gt;
&lt;small&gt;
&lt;I&gt;
Acknowledgement: I'd like to thank [mtve] and hallvabo for their help in preparing this series.
&lt;/I&gt;
&lt;/small&gt;
&lt;/P&gt;</field>
</data>
</node>
