Perl, 438 291 karakter
Terinspirasi oleh Jeff Burdges yang menggunakan kompresi DEFLATE , kode Ruby terkompresi Ventero dan JB menggunakan Lingua :: EN :: Numbers , saya berhasil mengompres entri saya menjadi 291 karakter (yah, byte) termasuk kode dekompresi. Karena program ini mengandung beberapa karakter yang tidak dapat dicetak, saya telah menyediakannya dalam format MIME Base64 :
dXNlIENvbXByZXNzOjpabGliO2V2YWwgdW5jb21wcmVzcyAneNolkMFqAkEMhu8+RVgELdaIXmXB
S2/FFyhF4k7cHTqTsclMZd++M3pJvo+QH5JiDJ9exkKrj/PqXOKV1bod77qj9b2UeGBZ7w/bpd9s
3rCDruf3uWtwS3qS/vfROy0xsho+oWbB3d+b19YsJHWGhIHp5eQ8GzqSoWkk/xxHH36a24OkuT38
K21kNm77ND81BceCWtlgoBAq4NWrM7gpyzDhxGKQi+bA6NIfG5K4/mg0d0kgTwwdvi67JHVeKKyX
l3acoxnSDYZJveVIBnGGrIUh1BQYqZacIDKc5Gvpt1vEk3wT3EmzejcyeIGqTApZmRftR7BH3B8W
/5Aze7In
Untuk menghapus kode program, Anda dapat menggunakan skrip Perl pembantu berikut:
use MIME::Base64;
print decode_base64 $_ while <>;
Simpan output dalam file bernama 12days.pl
dan jalankan dengan perl -M5.01 12days.pl
. Seperti disebutkan, Anda harus menginstal modul Lingua :: EN :: Numbers agar kode dapat berfungsi.
Jika Anda bertanya-tanya, bagian kode yang dapat dibaca terlihat seperti ini:
use Compress::Zlib;eval uncompress '...'
di mana ...
kepanjangan dari 254 byte dari RFC 1950 kode Perl terkompresi. Tanpa kompresi, kodenya panjangnya 361 karakter dan terlihat seperti ini:
use Lingua'EN'Numbers"/e/";s==num2en(12-$i++)." "=e,y"." "for@n=qw=drummers.drumming pipers.piping lords.a.leaping ladies.dancing maids.a.milking swans.a.swimming geese.a.laying golden.rings calling.birds french.hens turtle.doves.and=;say"on the ".num2en_ordinal($_)." day of christmas my true love gave to me @n[$i--..@n]a partridge in a pear tree
"for 1..12
Menulis kode ini adalah jenis latihan golf yang aneh: ternyata pengulangan memaksimalkan dan meminimalkan jumlah karakter berbeda yang digunakan jauh lebih penting daripada meminimalkan jumlah karakter mentah ketika metrik yang relevan adalah ukuran setelah kompresi .
Untuk memeras beberapa karakter terakhir, saya menulis sebuah program sederhana untuk mencoba variasi kecil dari kode ini untuk menemukan kode yang paling kompres. Untuk kompresi, saya menggunakan utilitas KZIP Ken Silverman , yang biasanya menghasilkan rasio kompresi yang lebih baik (dengan biaya kecepatan) daripada Zlib standar bahkan pada pengaturan kompresi maksimum. Tentu saja, karena KZIP hanya membuat arsip ZIP, saya kemudian harus mengekstrak aliran DEFLATE mentah dari arsip dan membungkusnya dalam header dan checksum RFC 1950. Berikut kode yang saya gunakan untuk itu:
use Compress::Zlib;
use 5.010;
@c = qw(e i n s);
@q = qw( " );
@p = qw( = @ ; , );
@n = ('\n',"\n");
$best = 999;
for$A(qw(e n .)){ for$B(@q){ for$C(@q,@p){ for$D(@p){ for$E(@q,@p){ for$F(qw(- _ . N E)){ for$G("-","-"eq$F?():$F){ for$H(@c){ for$I(@c,@p){ for$N(@n){ for$X(11,"\@$I"){ for$Y('$"','" "',$F=~/\w/?$F:()){ for$Z('".num2en_ordinal($_)."'){
$M="Lingua'EN'Numbers";
$code = q!use MB/A/B;sDDnum2en(12-$H++).YDe,yCFC Cfor@I=qwEdrummersFdrumming pipersFpiping lordsGaGleaping ladiesFdancing maidsGaGmilking swansGaGswimming geeseGaGlaying goldenFrings callingFbirds frenchFhens turtleFdovesFandE;say"on the Z day of christmas my true love gave to me @I[$H--..X]a partridge in a pear treeN"for 1..12!.$/;
$code =~ s/[A-Z]/${$&}/g;
open PL, ">12days.pl" and print PL $code and close PL or die $!;
$output = `kzipmix-20091108-linux/kzip -b0 -y 12days.pl.zip 12days.pl`;
($len) = ($output =~ /KSflating\s+(\d\d\d)/) or die $output;
open ZIP, "<12days.pl.zip" and $zip = join("", <ZIP>) and close ZIP or die $!;
($dfl) = ($zip =~ /12days\.pl(.{$len})/s) or die "Z $len: $code";
$dfl = "x\xDA$dfl" . pack N, adler32($code);
$dfl =~ s/\\(?=[\\'])|'/\\$&/g;
next if $best <= length $dfl;
$best = length $dfl;
$bestcode = $code;
warn "$A$B$C$D$E$F$G$H$I $X $Y $best: $bestcode\n";
open PL, ">12days_best.pl" and print PL "use Compress::Zlib;eval uncompress '$dfl'" and close PL or die $!;
}}}}}}
print STDERR "$A$B$C$D$E$F\r";
}}}}}}}
Jika ini terlihat seperti kluge yang mengerikan, itu karena memang seperti itu.
Untuk kepentingan sejarah, inilah solusi 438-char asli saya, yang menghasilkan output yang lebih bagus, termasuk jeda baris dan tanda baca:
y/_/ /,s/G/ing/for@l=qw(twelve_drummers_drummG eleven_pipers_pipG ten_lords-a-leapG nine_ladies_dancG eight_maids-a-milkG seven_swans-a-swimmG six_geese-a-layG five_golden_rGs four_callG_birds three_french_hens two_turtle_doves);s/e?t? .*/th/,s/vt/ft/for@n=@l;@n[9..11]=qw(third second first);say map("\u$_,\n","\nOn the $n[11-$_] day of Christmas,\nMy true love gave to me",@l[-$_..-1]),$_?"And a":A," partridge in a pear tree."for 0..11
Sorotan dari versi ini adalah sepasang regexps s/e?t? .*/th/,s/vt/ft/
, yang menyusun tata cara untuk 4 hingga 12 dari para kardinal di awal garis hadiah.
Kode ini, tentu saja, juga dapat dikompres menggunakan trik Zlib yang dijelaskan di atas, tetapi ternyata dengan mengompresi output lebih efisien, menghasilkan program 338-byte berikut (dalam format Base64, lagi):
dXNlIENvbXByZXNzOjpabGliO3NheSB1bmNvbXByZXNzICd42uWTwU7DMAyG730KP8DGOyA0bsCB
vYBp3MYicSo7W9e3xx3ijCIQDHZIUjn683+/k3ZPAjUSDKxWIeACZYC7qGw1o226hwWqHghSORKM
6FMtkGnT3cKEWpXDSMACCBOhQlWim+7jUKO+SGg5dT8XqAetiSD4nrmPBMDPvXywtllF18OgJH2E
SGJfcR+Ky2KL/b0roMeUWEZ4cXb7biQeGol4LZQUSECdyn4A0vjUBvnMXCcYiYy2uE24ONcvgdOR
pBF9lYDNKObwNnPOTnc5kYjH2JZotyogI4c1Ueb06myXH1S48eYeWbyKgclcJr2D/dnwtfXZ7km8
qOeUiXBysP/VEUrt//LurIGJXCdSWxeHu4JW1ZnS0Ph8XOKloIecSe39w/murYdvbRU+Qyc=
Saya juga memiliki arsip gzip 312 byte lirik, dibangun dari aliran DEFLATE yang sama. Saya kira Anda bisa menyebutnya "skrip zcat". :)