Перл, 1428 1099
Він містить 1193 символи ASCII (включаючи 960 перестановлених двійкових цифр). 1193 - 94 = 1099
$s='010011100001100010101100111111101001101011101000100000101011011010100110111111011111101011101000100110111111011100101000011101011110100000101000100101011111111110101100101101011010011100100100011110110001011100100001011010100111100000011110111110011100101000100110111111101001011110101011100110101110101101011110101100111111100010101101101100011110100101011111111111101101101000111111011110100111011100101000011101011110111111011010111111101100101101101011100010100111100000111110';$_=q{$i=join'',A..Z,a..z,0..9,'. ';print map({substr$i,oct'0b'.$_,1}$s=~/.{6}/g),$/;chop($s=<>);$s=join'',map{sprintf"%06b",index$i,$_}$s=~/./g;$t=join'',map{$_ x(480-(()=$s=~/$_/g))}0,1;print"\$s='$s';\$_=q{$_};eval#$t"};eval#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Моя перша конструкція
Перш ніж я взяв пропозицію від Денніса перейти на бінарний, у моїй програмі перестановлено восьмеричні цифри.
Моя перша конструкція кодує кожну рядок у 160 восьмеричних цифрах, по 2 цифри на символ. Це кодування має 100 8 = 64 різних символів. Восьма система має 8 різних цифр. Програма повинна мати 160 копій кожної цифри, тому вона перестановлює 8 × 160 = 1280 цифр.
Я зберігаю 160 цифр, $s
а інші 1120 цифр $t
. Я починаю з програми, яка не є квинтом, а лише друкує завдання до $s
та $t
для наступного запуску. Це воно:
$s = '2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';
$t = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777';
# $i = character map of 64 characters, such that:
# substr($i, $_, 1) is the character at index $_
# index($i, $_) is the index of character $_
$i = join '', 'A'..'Z', 'a'..'z', '0'..'9', '. ';
# Decode $s from octal, print.
# 1. ($s =~ /../g) splits $s into a list of pairs of octal digits.
# 2. map() takes each $_ from this list.
# 3. oct() converts $_ from an octal string to a number.
# 4. substr() on $i converts number to character.
# 5. print() outputs the characters from map() and a final "\n".
print map({ substr $i, oct, 1 } $s =~ /../g), "\n";
# Read new $s, encode to octal.
# 1. ($s = <>) reads a line.
# 2. chop($s) removes the last character of $s, the "\n".
# 3. ($s =~ /./g) splits $s into characters.
# 4. map() encodes each character $_ as a pair of octal digits.
# 5. join() concatenates the pairs from map().
chop($s = <>);
$s = join '', map { sprintf "%02o", index $i, $_ } $s =~ /./g;
# Make new $t.
# 1. map() takes each $_ from 0 to 7.
# 2. $_ x (160 - (() = $s =~ /$_/g)) makes a string where $_ repeats
# 160 times, minus the number of times that $_ appears in $s.
# 3. join() concatentates the strings from map().
$t = join '', map { $_ x (160 - (() = $s =~ /$_/g)) } 0..7;
# Print the new assignments for $s and $t. This is not yet a quine,
# because it does not print the rest of the program.
print "\$s = '$s';\n\$t = '$t';\n";
(() = $s =~ /$_/g))
- призначення порожнього списку змінних. Цей трюк я беру з підручника з контексту на PerlMonks . Це змушує перелічити контекст оператора матчу =~
. У скалярному контексті збіг був би істинним чи хибним, і мені знадобиться цикл, який би хотів $i++ while ($s =~ /$_/g)
рахувати збіги. У контексті списку $s =~ /$_/g
- це список відповідностей. Я ставлю цей список у скалярний контекст віднімання, тому Perl рахує елементи списку.
Щоб зробити квінку, я беру форму $_=q{print"\$_=q{$_};eval"};eval
з лайків Perl за кодом Rosetta . Це одна Призначає рядок q{...}
з , $_
а потім дзвонить eval
, так що я можу мати свій код в рядку , а також запустити його. Моя програма стає лайкою, коли я переношу свої треті до останніх рядків у $_=q{
та };eval
і змінюю останній print
на print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval"
.
Нарешті, я програю програму, змінюючи перше завдання на $t
коментар та видаляючи зайві символи.
Він містить 1522 символи ASCII (включаючи 1280 перестановлених восьмеричних цифр).
1522 - 94 = 1428
$s='2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
$_=q{$i=join'','A'..'Z','a'..'z','0'..'9','. ';print map({substr$i,oct,1}$s=~/../g),"\n";chop($s=<>);$s=join'',map{sprintf"%02o",index$i,$_}$s=~/./g;$t=join'',map{$_ x(160-(()=$s=~/$_/g))}0..7;print"\$s='$s';#$t\n\$_=q{$_};eval"};eval
Перехід на бінарний
У коментарях Денніс зауважив, що 960 перестановлених двійкових цифр буде менше 1280 восьмеричних цифр. Тому я зрозумів кількість перестановлених цифр для кожної бази від 2 до 16.
Maxima 5.29.1 http://maxima.sourceforge.net
using Lisp ECL 13.5.1
...
(%i36) n : floor(x);
(%o36) floor(x)
...
(%i41) plot2d(n * ceiling(log(64) / log(n)) * 80, [x, 2, 16],
[xlabel, "base"], [ylabel, "number of permuted digits"]);
(%o41)
Хоча база 8 є локальним мінімумом, бази 2 і 3 і 4 прив'язують до кращої бази, на 960 перестановлених цифр. Для кодового гольфу найкраще базувати 2, оскільки Perl має перетворення для бази 2.
Заміна 1280 восьмеричних цифр на 960 двійкових цифр економить 320 символів.
Перехід коду з восьмеричного на двійковий коштує 8 символів:
- Перехід
oct
до oct'0b'.$_
витрат 7.
- Перехід
/../g
до /.{6}/g
витрат 2.
- Зміна
"%02o"
на "% 06b" `коштує 0.
- Перехід
160
до 480
витрат 0.
- Змінити,
0..7
щоб 0,1
зберегти 1.
Я дізнався деякі поради щодо гольфу Perl . Вони зберігають 14 символів:
- Змінити
'A'..'Z','a'..'z','0'..'9'
на A..Z,a..z,0..9
, використовуючи голосні слова та голого числа, зберігається 12 символів.
- Змінити,
"\n"
щоб $/
зберегти 2 символи.
Я зберігаю 3 символи, переміщуючи #$t
коментар до кінця файлу. Це видаляє новий рядок, який закінчує коментар, і літерал \n
у квині.
Ці зміни врятують загалом 329 символів і зменшили мою оцінку з 1428 до 1099.