Программа, которая переставляет себя, чтобы закодировать строку (quine-вариант)

16

Напишите программу, которая печатает следующую строку из 80 символов:

Эта программа из codegolf.stackexchange.com переставляет себя для кодирования строки.

затем принимает одну строку ввода, затем печатает свой исходный код с возможными переупорядоченными точками кода (ни один не добавлен и ни один не удален). Когда этот код выполняется, то же самое должно произойти, за исключением того, что напечатанная строка будет самой последней строкой ввода.

Регулярное выражение в стиле Perl ^[A-Za-z0-9. ]{80}$будет соответствовать любой строке ввода. Вы не можете делать никаких дополнительных предположений.

Оценка представления - это количество кодовых точек в исходном коде за вычетом 94 . Ниже - лучше.

Код не должен делать ничего, что было бы неприемлемо в квине ( например, чтение файла). В частности, любая заявка с отрицательной оценкой должна быть обманом, как 93! менее 64 80 .

Добавлено 2014-04-21: Весь исходный код вашей программы должен быть правильно сформирован в кодировке символов, в которой вы подсчитываете кодовые точки. Например, вы не можете использовать 80 последовательных байтов в диапазоне конечных байтов UTF-8 (80..BF) и считать каждый как один символ U + FFFD REPLACEMENT CHARACTER (или, что еще хуже, вообще не кодовый пункт).

Кроме того, если кодирование допускает несколько способов кодирования кодовой точки ( например, SCSU ), ваша программа, а также все программы, которые она генерирует прямо или косвенно, должны использовать только одну из них (или, по крайней мере, все должны обрабатываться одинаково во всем коде). ).

PleaseStand
источник
Перечитав ваш вопрос, я не уверен, что мой ответ делает именно то, что вы имели в виду. Исправлена ​​ли передача новой строки в программу, или она должна запустить интерактивное приглашение?
Деннис
@ Денис: Это не то, почему ваш ответ не приемлем. Скорее, он читает ввод перед печатью «Эта программа из [...]».
Пожалуйста, встаньте
Вот что я имел в виду, я просто не очень хорошо это выразил. Интерпретатор GolfScript читает все, что ему передано, перед тем, как начать выполнение скрипта. Единственный способ избежать этого - запустить подсказку, которая делает невозможным передачу труб.
Деннис
Привет, я пытаюсь это в JavaScript. Кажется невозможным создать квин, не читая текст между тегами <script>? Какова цель перестановки исходного кода? Вы говорите «возможно, переупорядочено»; это значит переставлять только при необходимости?
bacchusbeale

Ответы:

5

GolfScript, 231 162 131

'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~

Как это устроено

Мы начнем с выбора 94 различных символов, которые будут переставлены для кодирования строки. Любой 94 символа будет работать, но мы выбираем следующее для целей игры в гольф:

\n .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
àáâãäåçèéêëìíîïðñòóôõöøùúûüýÿ

Давайте назовем массив этих символов «&».

Строка ввода всегда будет содержать 81 символ (включая LF). Все эти символы присутствуют в первых 65 символах «&». Это единственная причина выбора символов в верхних 128 байтах.

Мы заменяем каждый символ строки его индексом в «&», поэтому LF становится 0, пробел становится 1 и т. Д.

Мы рассматриваем 81 полученный номер цифрами одного базового 65 числа. Давайте назовем этот номер «N».

Теперь мы перечисляем все возможные перестановки «&» и извлекаем перестановку, соответствующую числу сверху. Это достигается следующим образом:

  1. Установите c = 1и A = [].
  2. Готовься N % cк A.
  3. Установите N = N / cи c = c + 1.
  4. Если c < 95, вернитесь к 2.
  5. Установите i = 0и s = "".
  6. Получите символ &[A[i]], добавьте его к «s» и удалите его из «&».
  7. Set i = i + 1.
  8. Если i < 94вернуться к 6.

Предположим, у нас есть кодовые блоки «E» и «D», которые кодируют и декодируют строку, как описано выше.

Теперь нам нужна оболочка для тех блоков кода, которая соответствует требованиям вопроса:

'encoded string'{\.$[{}/]:&; D puts '"#{`head -1`}"'~ E "'".@+\+\'.~'}.~

Это делает следующее:

  • {…}.~определяет блок, дублирует его и выполняет вторую копию. Первая копия останется в стеке.

  • \.$ заменяет закодированную строку на блок и создает копию закодированной строки с отсортированными символами.

  • [{}/]:&; преобразует строку сверху в массив, сохраняет ее в «&» и удаляет ее.

  • D puts декодирует закодированную строку и печатает результат

  • '"#{`head -1`}"'~читает одну строку ввода, выполняя head -1в оболочке.

  • E "'".@+\+ кодирует строку, добавляет и добавляет одинарную кавычку.

  • \'.~'Меняет местами закодированную строку и блок и добавляет строку '.~'.

  • После того, как блок был выполнен, GolfScript печатает содержимое стека (закодированная строка, блок и '.~') и завершает работу.

«Е» можно определить следующим образом:

{&?}%        # Replace each character by its index in “&”.
);           # Remove the last integer from the array, since it corresponds to the LF.
65base       # Convert the array to an integer “N” by considering it a base 65 number.
[            #
  94,        # For each integer “c” in 0 … 93:
  {          #
    )        # Increment “c”.
    1$1$%    # Push “N % c”.
    @@/      # Rotate “N % c” below “N” and “c” and divide the first by the latter.
  }/;        # Discard “N”.
]            # Collect the results of “N % c” in an array “A”.
-1%          # Reverse “A”.
&\           # Push “&” and swap it with “A”.
[            #
  {          # For each “j” in “A”:
    1$=.[]+  # Push “&[j] [&[j]]”.
    @^       # Rotate “&” on top of “[&[j]]” and take their symmetric difference.
  }/         #
]            # Collect the charcters into an array.

«D» можно определить следующим образом:

0&           # Push 0 (initial value of the accumulator “A”) and “&”.
@            # Rotate the encoded string on top of “&”.
{            # For each character “c” of the encoded string:
    @2$,*    # Rotate “A” on top of the stack and multiply it by the length of “&”.
    2$2$?+   # Get the index of “c” in “&” and add it to “A”.
    @@^      # Rotate “A” below “&” and “c” and take their symmetric difference.
}/;          # Discard “&”.
65base       # Convert “A” into the array of its digits in base 65.
{&=}%        # Replace each digit by the corresponding character in “&”.
''+          # Convert the resulting array into a string.

Финальный гольф:

  • Замените \.$[{}/]:&;0&@на, 0@.$[{}/]:&\чтобы сохранить два символа.

  • Определите функцию {;65base}:bдля сохранения одного символа.

  • Удалите все пробелы, кроме конечного LF и LF в строке.

пример

$ # Create GolfScript file using base64 to avoid encoding issues.
$ base64 > permute.gs -d <<< JzHg4jT/YVZvNUf5cFpCdGlYT/xyc/NO7k1tV+VLSGMwOUpk8frqeXrtRUPkWe9oRFUg4+FJRvU26TjyUuxqVHYyM/hudfBMd3hmU2v0YutBZWxx/S7n6FBRCvb7ZzcnezBALiRbe30vXTomXHtAMiQsKjIkMiQ/K0BAXn0vezs2NWJhc2V9OmJ+eyY9fSUnJytwdXRzJyIje2BoZWFkIC0xYH0iJ357Jj99JSliWzk0LHspMSQxJCVAQC99LztdLTElJlxbezEkPS5AXn0vXSInIi5AK1wrXCcufid9Ln4K
$
$ # Set locale to en_US (or any other where one character is one byte).
$ LANG=en_US
$
$ # Go back and forth between two different strings.
$ # Second and sixth line are user input, not output from the script.
$
$ golfscript permute.gs | tee >(tail -n+2 > tmp.gs) && golfscript tmp.gs && rm tmp.gs
This program from codegolf.stackexchange.com permutes itself to encode a string.
Permuting source code code points to encode a string is a certain quine variant.
'18äJoS3sgV9qdçëxm0ÿKMNe5íPî.Htn2ciâIuøbRZéð4AwB7áìUüöôWõèûfñåLàóDrhQlO6
pTaýzòkùYCyFêïãG júEvX'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
Permuting source code code points to encode a string is a certain quine variant.
This program from codegolf.stackexchange.com permutes itself to encode a string.
'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
$
$ # Sort all characters from the original source code and hash them.
$ fold -1 permute.gs | sort | md5sum
b5d978c81df5354fcda8662cf89a9784  -
$
$ # Sort all characters from the second output (modified source code) and hash them.
$ golfscript permute.gs | tail -n+2 | fold -1 | sort | md5sum
Permuting source code code points to encode a string is a certain quine variant.
b5d978c81df5354fcda8662cf89a9784  -
$
$ # The hashes match, so the characters of the modified source code are a permutation
$ # of the character of the original one.
Деннис
источник
224 минус 94 - 130.
mbomb007
Не могли бы вы уточнить?
Денис
1

Perl, 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 Code . Это одна Назначает строка 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) 

график с основанием по оси X, количество переставленных цифр по оси Y

Хотя база 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.

kernigh
источник
1
Использование двоичных кодов вместо восьмеричных цифр потребует «только» 960 перестановочных символов.
Денис
@Dennis Спасибо за совет! Я сделал переход на двоичный (сохранение 312 символов). Находясь здесь, я отыграл еще 17 персонажей.
Керни