Perl, 438 291 caractères
Inspiré par l'utilisation de la compression DEFLATE par Jeff Burdges , le code Ruby compressé de Ventero et l'utilisation de Lingua :: EN :: Numbers par JB , j'ai réussi à compresser mon entrée à 291 caractères (enfin, octets), y compris le code de décompression. Étant donné que le programme contient des caractères non imprimables, je l'ai fourni au format MIME Base64 :
dXNlIENvbXByZXNzOjpabGliO2V2YWwgdW5jb21wcmVzcyAneNolkMFqAkEMhu8+RVgELdaIXmXB
S2/FFyhF4k7cHTqTsclMZd++M3pJvo+QH5JiDJ9exkKrj/PqXOKV1bod77qj9b2UeGBZ7w/bpd9s
3rCDruf3uWtwS3qS/vfROy0xsho+oWbB3d+b19YsJHWGhIHp5eQ8GzqSoWkk/xxHH36a24OkuT38
K21kNm77ND81BceCWtlgoBAq4NWrM7gpyzDhxGKQi+bA6NIfG5K4/mg0d0kgTwwdvi67JHVeKKyX
l3acoxnSDYZJveVIBnGGrIUh1BQYqZacIDKc5Gvpt1vEk3wT3EmzejcyeIGqTApZmRftR7BH3B8W
/5Aze7In
Pour désencoder le programme, vous pouvez utiliser le script Perl d'assistance suivant:
use MIME::Base64;
print decode_base64 $_ while <>;
Enregistrez la sortie dans un fichier nommé 12days.pl
et exécutez-le avec perl -M5.01 12days.pl
. Comme indiqué, vous devez avoir installé le module Lingua :: EN :: Numbers pour que le code fonctionne.
Au cas où vous vous poseriez la question, la partie lisible du code ressemble simplement à ceci:
use Compress::Zlib;eval uncompress '...'
où ...
représente 254 octets de code Perl compressé RFC 1950 . Non compressé, le code contient 361 caractères et ressemble à ceci:
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
L'écriture de ce code était un type étrange d'exercice de golf: il s'avère que la répétition maximisée et la minimisation du nombre de caractères distincts utilisés sont beaucoup plus importantes que la minimisation du nombre de caractères bruts lorsque la métrique pertinente est la taille après compression .
Pour extraire les derniers caractères, j'ai écrit un programme simple pour essayer de petites variations de ce code pour trouver celui qui compresse le mieux. Pour la compression, j'ai utilisé l' utilitaire KZIP de Ken Silverman , qui donne généralement de meilleures rations de compression (au prix de la vitesse) que le Zlib standard, même avec les paramètres de compression maximum. Bien sûr, puisque KZIP crée uniquement des archives ZIP, j'ai dû ensuite extraire le flux DEFLATE brut de l'archive et l'envelopper dans un en-tête et une somme de contrôle RFC 1950. Voici le code que j'ai utilisé pour cela:
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";
}}}}}}}
Si cela ressemble à un horrible kluge, c'est parce que c'est exactement ce que c'est.
Pour l'intérêt historique, voici ma solution originale de 438 caractères, qui génère une sortie plus agréable, y compris les sauts de ligne et la ponctuation:
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
Faits saillants de cette version la paire de regexps s/e?t? .*/th/,s/vt/ft/
, qui construisent les ordinaux pour 4 à 12 à partir des cardinaux au début des lignes de cadeaux.
Ce code peut, bien sûr, également être compressé à l'aide de l'astuce Zlib décrite ci-dessus, mais il s'avère que la simple compression de la sortie est plus efficace, produisant le programme suivant de 338 octets (au format Base64, encore):
dXNlIENvbXByZXNzOjpabGliO3NheSB1bmNvbXByZXNzICd42uWTwU7DMAyG730KP8DGOyA0bsCB
vYBp3MYicSo7W9e3xx3ijCIQDHZIUjn683+/k3ZPAjUSDKxWIeACZYC7qGw1o226hwWqHghSORKM
6FMtkGnT3cKEWpXDSMACCBOhQlWim+7jUKO+SGg5dT8XqAetiSD4nrmPBMDPvXywtllF18OgJH2E
SGJfcR+Ky2KL/b0roMeUWEZ4cXb7biQeGol4LZQUSECdyn4A0vjUBvnMXCcYiYy2uE24ONcvgdOR
pBF9lYDNKObwNnPOTnc5kYjH2JZotyogI4c1Ueb06myXH1S48eYeWbyKgclcJr2D/dnwtfXZ7km8
qOeUiXBysP/VEUrt//LurIGJXCdSWxeHu4JW1ZnS0Ph8XOKloIecSe39w/murYdvbRU+Qyc=
J'ai également une archive gzip de 312 octets des paroles, construite à partir du même flux DEFLATE. Je suppose que vous pourriez l'appeler un "script zcat". :)