Программа, которая переставляет себя, чтобы закодировать строку (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 ), ваша программа, а также все программы, которые она генерирует прямо или косвенно, должны использовать только одну из них (или, по крайней мере, все должны обрабатываться одинаково во всем коде). ).


Перечитав ваш вопрос, я не уверен, что мой ответ делает именно то, что вы имели в виду. Исправлена ​​ли передача новой строки в программу, или она должна запустить интерактивное приглашение?
Деннис

@ Денис: Это не то, почему ваш ответ не приемлем. Скорее, он читает ввод перед печатью «Эта программа из [...]».
Пожалуйста, встаньте

Вот что я имел в виду, я просто не очень хорошо это выразил. Интерпретатор 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.


1
Использование двоичных кодов вместо восьмеричных цифр потребует «только» 960 перестановочных символов.
Денис

@Dennis Спасибо за совет! Я сделал переход на двоичный (сохранение 312 символов). Находясь здесь, я отыграл еще 17 персонажей.
Керни
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.