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. Просто додайте а 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 беруть правий аргумент, позначений ⍵
і, необов'язковий лівий аргумент, позначений ⍺
(think infix). Ми хочемо подати цю функцію і нашим рядком quine, і чимось, щоб допомогти нам у створенні довільної кількості циклів. Щоб полегшити ситуацію на собі (і кожному, хто хоче додати цикли), ми робимо рядок quine лівим аргументом. Тож правильний аргумент - це те, де ми помістимо наш список циклів. 2 або більше елементів, розділених пробілом, створює список, тому в цьому прикладі у нас є 2-елементний список, що складається з a 1
і a0
.
Ми можемо бачити, що функція схожа на квінку раніше. У нас однакова ...⌽...⍴...⍴...
форма і раніше. Так це добре - ми принаймні так багато розуміємо! Давайте заглибимося в еліпси, починаючи з усім після останнього ⍴
: ⊃,/(~^/¨⍺=0)/⍺
.
- Як ви бачите, подивившись на приклад вище, ми додаємо рядок до 0 з правого боку, додаючи по одному з кожною ітерацією; але нас зараз це не хвилює. Ми просто хочемо рядок!
- Спочатку розглянемо, що є в дужках. (До речі, вони групуються, як і в більшості інших мов.)
⍺=0
повертає список у цьому випадку з тією ж формою, що і тоді ⍺
, коли кожен елемент у ⍺
замінюється символом a, 1
якщо він дорівнює 0
, і 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, залишаючи нас лише з нашим рядком quine.
⊃,/
- це деяка необхідна документація для того, щоб ми отримали повернути сплющений список символів, зменшуючи результат за допомогою функції конкатенації ( ,
). Якщо вхід є вже сплющеним списком (тобто лівим аргументом нашої основної функції є лише рядок), ми отримуємо 1-елементний список, що містить цей список. В іншому випадку, коли у нас є список, що складається з підсписку для рядка, ми отримуємо те саме, що повертається назад (список із підсписком). Потім ми розпаковуємо це ( ⊃
), надаючи нам лише перший елемент списку (тобто підсписок символів). Це може здатися непотрібним, але в іншому випадку ми б намагалися переробити 1-елементний список!
Далі ми розглянемо довжину, задану для першої зміни в межах дужок:
⍺,⍵
: Ми сполучаємо правильний аргумент з першим аргументом
⊃,/⍺,⍵
: Те саме, що і раніше - вирівняти список.
+/0=⊃,/⍺,⍵
: Додайте кількість нулів у списку шляхом зменшення ( /
) за допомогою функції add ( +
).
2×+/0=⊃,/⍺,⍵
: Помножте це число на два.
z←2×+/0=⊃,/⍺,⍵
Присвоїти ( ←
) результат змінної, z
. Для повторного підрахунку, z
зараз удвічі більше нулів, знайдених як у лівому, так і в правому аргументах.
77+z←2×+/0=⊃,/⍺,⍵
: Потім ми додаємо 77
символи в рядку quine, ігноруючи все після пробілу 1
. Як і в початковому прикладі quine, ми додаємо 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
.
І ми закінчили!