Perl, 438 291 caratteri
Ispirato dall'uso della compressione DEFLATE di Jeff Burdges , dal codice Ruby compresso di Ventero e dall'uso di Lingua :: EN :: Numbers di JB , sono riuscito a comprimere la mia voce fino a 291 caratteri (bene, byte) incluso il codice di decompressione. Poiché il programma contiene alcuni caratteri non stampabili, l'ho fornito in formato MIME Base64 :
dXNlIENvbXByZXNzOjpabGliO2V2YWwgdW5jb21wcmVzcyAneNolkMFqAkEMhu8+RVgELdaIXmXB
S2/FFyhF4k7cHTqTsclMZd++M3pJvo+QH5JiDJ9exkKrj/PqXOKV1bod77qj9b2UeGBZ7w/bpd9s
3rCDruf3uWtwS3qS/vfROy0xsho+oWbB3d+b19YsJHWGhIHp5eQ8GzqSoWkk/xxHH36a24OkuT38
K21kNm77ND81BceCWtlgoBAq4NWrM7gpyzDhxGKQi+bA6NIfG5K4/mg0d0kgTwwdvi67JHVeKKyX
l3acoxnSDYZJveVIBnGGrIUh1BQYqZacIDKc5Gvpt1vEk3wT3EmzejcyeIGqTApZmRftR7BH3B8W
/5Aze7In
Per decodificare il programma, è possibile utilizzare il seguente script Perl helper:
use MIME::Base64;
print decode_base64 $_ while <>;
Salvare l'output in un file denominato 12days.pled eseguirlo perl -M5.01 12days.pl. Come notato, è necessario che il modulo Lingua :: EN :: Numbers sia installato affinché il codice funzioni.
Nel caso ti stia chiedendo, la parte leggibile del codice appare semplicemente così:
use Compress::Zlib;eval uncompress '...'
dove ...sta per 254 byte di codice Perl compresso RFC 1950 . Non compresso, il codice è lungo 361 caratteri e si presenta così:
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
Scrivere questo codice è stato uno strano tipo di esercizio di golf: risulta che massimizzare la ripetizione e minimizzare il numero di caratteri distinti usati sono molto più importanti che minimizzare il numero di caratteri grezzi quando la metrica rilevante è la dimensione dopo la compressione .
Per eliminare gli ultimi caratteri, ho scritto un semplice programma per provare piccole variazioni di questo codice per trovare quello che comprime meglio. Per la compressione, ho usato l' utilità KZIP di Ken Silverman , che di solito produce razioni di compressione migliori (a costo della velocità) rispetto allo standard Zlib anche con le massime impostazioni di compressione. Naturalmente, dato che KZIP crea solo archivi ZIP, ho dovuto quindi estrarre il flusso DEFLATE grezzo dall'archivio e inserirlo in un'intestazione e checksum RFC 1950. Ecco il codice che ho usato per questo:
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";
}}}}}}}
Se questo sembra un kluge orribile, è perché è esattamente quello che è.
Per interesse storico, ecco la mia soluzione originale a 438 caratteri, che genera un output migliore, comprese interruzioni di linea e punteggiatura:
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
Punti salienti di questa versione la coppia di regexps s/e?t? .*/th/,s/vt/ft/ , che costruiscono gli ordinali da 4 a 12 dai cardinali all'inizio delle linee regalo.
Naturalmente questo codice può anche essere compresso usando il trucco Zlib sopra descritto, ma si scopre che la semplice compressione dell'output è più efficiente, producendo il seguente programma a 338 byte (di nuovo in formato Base64):
dXNlIENvbXByZXNzOjpabGliO3NheSB1bmNvbXByZXNzICd42uWTwU7DMAyG730KP8DGOyA0bsCB
vYBp3MYicSo7W9e3xx3ijCIQDHZIUjn683+/k3ZPAjUSDKxWIeACZYC7qGw1o226hwWqHghSORKM
6FMtkGnT3cKEWpXDSMACCBOhQlWim+7jUKO+SGg5dT8XqAetiSD4nrmPBMDPvXywtllF18OgJH2E
SGJfcR+Ky2KL/b0roMeUWEZ4cXb7biQeGol4LZQUSECdyn4A0vjUBvnMXCcYiYy2uE24ONcvgdOR
pBF9lYDNKObwNnPOTnc5kYjH2JZotyogI4c1Ueb06myXH1S48eYeWbyKgclcJr2D/dnwtfXZ7km8
qOeUiXBysP/VEUrt//LurIGJXCdSWxeHu4JW1ZnS0Ph8XOKloIecSe39w/murYdvbRU+Qyc=
Ho anche un archivio gzip a 312 byte dei testi, costruito dallo stesso flusso DEFLATE. Suppongo che potresti chiamarlo "script zcat". :)