APL (158 символов, оценка = 4)
'''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0
Я использую Dyalog APL здесь. Количество циклов можно увеличить на один, добавив 0
(0 с последующим пробелом) в конец выражения и в конец строки (перед '''
). Длина цикла равна (# 0's) + 1
, а длина выражения равна 150 + 4*(cycle length))
. Предположим , что мы продолжаем добавлять нули навсегда, счет Limit[(150 + 4*n)/(n - 1), n -> Infinity] = 4
, где n
длина цикла.
Вот пример с длиной цикла = 6:
'''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0
0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0
0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0
0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0
0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0
0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0
0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0
0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0
0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0
0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1
0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1
'''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0
192 персонажа, оценка = 2
'''{2≠⍴⍺:¯3⌽(2×1+⍴⍺)⍴(1+⍴⍺)⍴⍺ ⋄ a←⊃2⌷⍺ ⋄ ⍵=0:¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a⋄(-4+⌊10⍟⊃⍺)⌽(2×1+⍴a)⍴(1+⍴a)⍴a}01'''{2≠⍴⍺:¯3⌽(2×1+⍴⍺)⍴(1+⍴⍺)⍴⍺⋄a←⊃2⌷⍺⋄⍵=0:¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a⋄(-4+⌊10⍟⊃⍺)⌽(2×1+⍴a)⍴(1+⍴a)⍴a}01
В зависимости от реализации одной из точек сбоя может быть случай, когда целое число с префиксом строки слишком велико. Тем не менее, теоретически мы можем добавить цикл, добавив два символа - a 1
в конце строки (перед '''
) и a 1
в конце всей строки.
200 символов, оценка = 1
'''{a←{2=⍴⍵:⊃2⌷⍵⋄⍵}⍺⋄(⍺{⍵=9:⍬⋄⍕1+{2=⍴⍵:10×⊃⍵⋄0}⍺}⍵),(¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a),⍺{⍵=9:(⍕9),⍕⊃⍺⋄⍕⌊⍵÷10}⍵}'''{a←{2=⍴⍵:⊃2⌷⍵⋄⍵}⍺⋄(⍺{⍵=9:⍬⋄⍕1+{2=⍴⍵:10×⊃⍵⋄0}⍺}⍵),(¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a),⍺{⍵=9:(⍕9),⍕⊃⍺⋄⍕⌊⍵÷10}⍵}91
Моя реализация APL не имеет целочисленных значений неограниченной точности по умолчанию, поэтому целое число преобразуется в число с плавающей точкой, когда оно становится слишком большим, что приводит к неправильному выводу. Так что это самый привередливый, но теоретически (либо вручную, либо с другим интерпретатором APL) он должен иметь оценку 1. Просто добавьте a 1
в конец выражения, и вы получите еще один цикл.
Обзор (с более короткой формой)
Я собираюсь дать обзор первой версии, потому что я думаю, что это, вероятно, легче всего понять. Однако, прежде чем заняться этой версией, мы рассмотрим простую форму в APL :
1⌽22⍴11⍴'''1⌽22⍴11⍴'''
Я обнаружил, что один из лучших способов понять некоторые выражения APL - это посмотреть на результат в каскаде операторов / функций. Все операторы и функции в APL являются ассоциативными справа и имеют одинаковый приоритет, так что вот, справа налево:
'''1⌽22⍴11⍴'''
Это просто строковый литерал (список символов). ''
APL способ избежать одиночных кавычек. Выход: '1⌽22⍴11⍴'
.
11⍴'''1⌽22⍴11⍴'''
: Здесь мы изменяем ( ⍴
) строку, чтобы иметь длину 11
. Поскольку длина строки меньше 11, она повторяется (т. 5⍴'abc'
Е. Дает результат 'abcab'
). Выход: '1⌽22⍴11⍴''
. Итак, теперь у нас есть две кавычки в конце - мы добираемся куда-то!
22⍴11⍴'''1⌽22⍴11⍴'''
Точно так же мы теперь изменили наш предыдущий вывод, чтобы иметь длину 22
. Выход: '1⌽22⍴11⍴'''1⌽22⍴11⍴''
. Мы почти на месте - нам просто нужно переместить первую одинарную кавычку до конца.
1⌽22⍴11⍴'''1⌽22⍴11⍴'''
: Здесь мы вращаем ( ⌽
) список символов на 1
. Это перемещает первый символ строки в конец. В качестве другого примера, 2⌽'abcdef'
возвращает 'cdefab'
. Выход: 1⌽22⍴11⍴'''1⌽22⍴11⍴'''
.
Вращающаяся квинна
Эта короткая квинна является основной основой нашей вращающейся квинны. Теперь, имея это в виду, давайте посмотрим на нашу квинну:
'''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0
{ ... }
определяет безымянную функцию, в которой мы будем работать. Обратите внимание, что функции в APL принимают правый аргумент, обозначаемый как ⍵
, и необязательный левый аргумент, обозначаемый ⍺
(думаю, infix). Мы хотим передать эту функцию как нашей строке quine, так и чему-то, что поможет нам в создании произвольного числа циклов. Чтобы упростить себе задачу (и всем, кто хочет добавить циклы), мы делаем строку quine левым аргументом. Правильный аргумент - это то, где мы помещаем наш список циклов. 2 или более элементов, разделенных пробелом, создают список, поэтому в этом примере у нас есть 2-элементный список, состоящий из a 1
и a 0
.
Мы можем видеть, что функция выглядит аналогично предыдущей. У нас та же ...⌽...⍴...⍴...
форма, что и раньше. Так что это хорошо - по крайней мере, мы это понимаем! Давайте углубимся в эллипсы, начиная со всем после последнего ⍴
: ⊃,/(~^/¨⍺=0)/⍺
.
- Как вы можете видеть, посмотрев на приведенный выше пример, мы добавляем в строку префикс 0 с правой стороны, добавляя один к каждой итерации; но нас это сейчас не волнует. Мы просто хотим строку!
- Сначала рассмотрим, что в скобках. (Кстати, они группируются, как и в большинстве других языков.)
⍺=0
возвращает список, в данном случае, такой же формы, что ⍺
и каждый элемент в ⍺
, заменяется на a, 1
если он равен 0
, и на a 0
иначе. Это выполняется рекурсивно; так что если у нас есть список из списка символов, отдельные символы будут проверены на 0, и вы получите список из списка списка двоичных значений.
- Так что, если
⍺
состоит только из нашей строки, мы получим список из 0. В противном случае, наш левый аргумент имеет префикс 0 (например, 0 0 0 'quinestring'
), так что это список, состоящий из 0 и другого списка, нашей строки. Тогда наш вывод выглядит так 1 1 1 <sub-list of zeros>
.
^/¨⍺=0
: Мы применяем производную функцию ^/
, которая уменьшает ( /
) с помощью логической функции AND ( ^
), к каждому ¨
элементу ( ) ⍺=0
. Это сделано для того, чтобы сгладить подсписок нулей, чтобы мы могли рассматривать строку quine как одно двоичное значение. Учитывая предыдущий пример, результат будет 1 1 1 0
.
~
: Мы бинарное НЕ каждое из значений до (например, возвращая 0 0 0 1
).
(~^/¨⍺=0)/⍺
: Для каждого элемента в ⍺
мы реплицируем ( /
) его количество раз, указанное соответствующим элементом в левом аргументе. Это исключает все 0, оставляя нас только с нашей строкой квин.
⊃,/
это некоторая необходимая документация, чтобы мы могли получить сплющенный список символов, уменьшив результат с помощью функции конкатенации ( ,
). Если входные данные уже являются сплюснутым списком (т. Е. Левый аргумент нашей главной функции - только строка), мы получаем 1-элементный список, содержащий этот список. В другом случае, когда у нас есть список, состоящий из подсписка для строки, мы получаем то же самое обратно (список с подсписком). Затем мы распаковываем this ( ⊃
), давая нам только первый элемент списка (то есть подсписок символов). Это может показаться ненужным, но в противном случае мы бы попытались изменить список из 1 элемента!
Далее мы рассмотрим длину, указанную для первого изменения формы, в скобках:
⍺,⍵
: Мы соединяем правильный аргумент с первым аргументом
⊃,/⍺,⍵
: То же, что и раньше - сгладить список.
+/0=⊃,/⍺,⍵
: Добавьте количество нулей в списке, уменьшив ( /
) с помощью функции дополнения ( +
).
2×+/0=⊃,/⍺,⍵
: Умножьте это число на два.
z←2×+/0=⊃,/⍺,⍵
: Присвоить ( ←
) результат переменной, z
. Напомним, z
теперь в два раза больше нулей, найденных в левом и правом аргументах.
77+z←2×+/0=⊃,/⍺,⍵
Затем мы добавляем 77
для символов в строке quine игнорирование всего, что следует после пробела 1
. Как и в первоначальном примере с квине, мы добавляем 1 к длине строки, чтобы получить еще одну одинарную кавычку.
- Выход этого изменения в этом примере:
'{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 ''
Аргумент к изменению формы, который следует, прост и отражает короткую квинну (в 2 раза больше длины первого преобразования). Наш вывод сейчас:
'{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 ''
Теперь для последнего шага, где мы вычисляем, сколько нужно повернуть выходную строку:
- Как вы можете видеть, посмотрев на предыдущий вывод, мы хотим повернуть его назад (отрицательное значение), чтобы привести 2 заключительные кавычки в начало. Поскольку мы хотим, чтобы
0
(и другой пробел) также переместились в начало, мы хотим повернуть его еще на 3 символа назад.
+/+/¨⍺=0
: Сложите количество нулей в левом аргументе. Первый (справа) +/¨
суммирует количество каждого элемента (т. Е. Подсписок или просто целое число), а второй +/
дает нам сумму этого результирующего списка.
5+2×+/+/¨⍺=0
: Умножьте на два (чтобы повернуть и пробелы), и добавьте 5 (результат, который мы получили раньше).
- Теперь мы вычитаем предыдущее значение из левого аргумента,
-
чтобы обработать случай, когда мы достигли конца нашего цикла:
(3+z)×^/⍵
: И все элементы в правильном аргументе вместе, чтобы увидеть, достигли ли мы нашего конца ( 1
), и умножить это на 3+z
.
И мы сделали!