Перл, 438 291 чол
Натхненні використання Джеффа Burdges стиснення ігровий DEFLATE , стиснений код Ruby , Ventero в і використанні JB про Lingua :: EN :: Числах , мені вдалося стиснути мою запис до 291 символів (ну, байти) , включаючи декомпрессионной код. Оскільки програма містить кілька символів, які не можна роздрукувати, я надав її у форматі MIME Base64 :
dXNlIENvbXByZXNzOjpabGliO2V2YWwgdW5jb21wcmVzcyAneNolkMFqAkEMhu8+RVgELdaIXmXB
S2/FFyhF4k7cHTqTsclMZd++M3pJvo+QH5JiDJ9exkKrj/PqXOKV1bod77qj9b2UeGBZ7w/bpd9s
3rCDruf3uWtwS3qS/vfROy0xsho+oWbB3d+b19YsJHWGhIHp5eQ8GzqSoWkk/xxHH36a24OkuT38
K21kNm77ND81BceCWtlgoBAq4NWrM7gpyzDhxGKQi+bA6NIfG5K4/mg0d0kgTwwdvi67JHVeKKyX
l3acoxnSDYZJveVIBnGGrIUh1BQYqZacIDKc5Gvpt1vEk3wT3EmzejcyeIGqTApZmRftR7BH3B8W
/5Aze7In
Для розкодування програми можна скористатися наступним помічником сценарію Perl:
use MIME::Base64;
print decode_base64 $_ while <>;
Збережіть вихід у файлі з ім'ям 12days.pl
та запустіть його perl -M5.01 12days.pl
. Як зазначалося, для роботи коду потрібно встановити модуль Lingua :: EN :: Числа .
Якщо вам цікаво, читабельна частина коду просто виглядає так:
use Compress::Zlib;eval uncompress '...'
де ...
стоїть 254 байт RFC 1950 стисненого коду Perl. Нестиснений, код становить 361 символів і виглядає приблизно так:
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
Написання цього коду було дивним видом вправи для гольфу: виявляється, що максимальне повторення та мінімізація кількості використаних відмінних символів є набагато важливішими, ніж мінімізація кількості необроблених символів, коли відповідний показник розмір після стиснення .
Щоб видавити останні кілька символів, я написав просту програму, щоб спробувати невеликі варіанти цього коду, щоб знайти той, який найкраще стискає. Для стиснення я використовував утиліту KZIP Кена Сільвермана , яка зазвичай дає кращі коефіцієнти стиснення (за рахунок швидкості), ніж стандартні Zlib навіть при максимальних налаштуваннях стиснення. Звичайно, оскільки KZIP створює лише ZIP-архіви, тоді мені довелося витягнути з архіву необроблений потік DEFLATE і загорнути його в заголовок і контрольну суму RFC 1950. Ось код, який я використав для цього:
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";
}}}}}}}
Якщо це виглядає як жахливий клубок, це тому, що саме воно є.
Для історичного інтересу, ось моє оригінальне рішення з 438 знаків, яке генерує кращі результати, включаючи розриви рядків та пунктуацію:
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
Основні моменти цієї версії пари регулярних виразів s/e?t? .*/th/,s/vt/ft/
, які будують порядки від 4 до 12 від кардиналів на початку подарункових ліній.
Цей код, звичайно, можна також стиснути, використовуючи описаний вище трюк Zlib, але виявляється, що просто стиснення виходу є більш ефективним, отримуючи наступну 338-байтну програму (знову ж у форматі Base64):
dXNlIENvbXByZXNzOjpabGliO3NheSB1bmNvbXByZXNzICd42uWTwU7DMAyG730KP8DGOyA0bsCB
vYBp3MYicSo7W9e3xx3ijCIQDHZIUjn683+/k3ZPAjUSDKxWIeACZYC7qGw1o226hwWqHghSORKM
6FMtkGnT3cKEWpXDSMACCBOhQlWim+7jUKO+SGg5dT8XqAetiSD4nrmPBMDPvXywtllF18OgJH2E
SGJfcR+Ky2KL/b0roMeUWEZ4cXb7biQeGol4LZQUSECdyn4A0vjUBvnMXCcYiYy2uE24ONcvgdOR
pBF9lYDNKObwNnPOTnc5kYjH2JZotyogI4c1Ueb06myXH1S48eYeWbyKgclcJr2D/dnwtfXZ7km8
qOeUiXBysP/VEUrt//LurIGJXCdSWxeHu4JW1ZnS0Ph8XOKloIecSe39w/murYdvbRU+Qyc=
У мене також є 312-байтний gzip-файл архіву, створений з того самого потоку DEFLATE. Я думаю, ви могли б назвати це "сценарієм zcat". :)