Fueue , 423 байта
Fueue - основанный на очереди esolang, в котором запущенная программа является очередью.
)$$4255%%1(~):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]](H-):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Попробуйте онлайн!
Как это устроено
Это объяснение может или не может выйти из-под контроля. С другой стороны, я не знаю, как объяснить это намного короче, как я надеюсь, что люди могут следовать.
Fueue шпаргалка
Смотрите статью esolang wiki для подробностей, включая некоторые функции, не используемые в этой программе.
Начальная программа - это начальное состояние очереди, которое может содержать следующие элементы:
- Целочисленные литералы (могут быть вычислены только неотрицательные в источнике, но отрицательные), при их выполнении печатается символ.
- Квадратные скобки, разделенные вложенными блоками, инертны (сохраняются, если на них не действует какая-либо функция).
- Функции, их аргументы - это элементы, следующие непосредственно за ними в очереди:
+*/-%
: целочисленная арифметика ( -
унарно, %
логическое отрицание). Инертен, если не дано число аргументов.
()<
: поместить элемент в скобки, убрать скобки из блока, добавить последний элемент в блок. Последние два являются инертными, если за ними не следует блок.
~:
: swap, дублировать
$
: копия (занимает число + элемент). Инертен перед не номером.
H
: остановить программу.
Обратите внимание, что в то время как []
гнездо,()
не надо - последние просто отдельные функции.
Синтаксис трассировки выполнения
Пробел необязателен в Fueue, кроме цифр. В следующих трассах выполнения он будет использоваться, чтобы предложить структуру программы, в частности:
- Когда функция выполняется, она и ее аргументы будут выделяться из окружающих элементов пробелами. Если некоторые аргументы сложны, между ними также может быть пробел.
- Многие следы выполнения разделены на «задержку» слева, отделенную от части справа, которая выполняет существенные манипуляции с данными. Смотрите следующий раздел.
Фигурные скобки {}
(не используются в Fueue) используются в трассировках для представления целочисленного результата математических выражений. Это включает в себя отрицательные числа, так как Fueue имеет только неотрицательные литералы --
это функция отрицания.
Различные мета-переменные имена и ...
используются для обозначения значений и сокращений.
Задержка тактики
Интуитивно понятно, что выполнение циклически повторяется вокруг очереди, частично изменяя то, через что она проходит. На результаты функции нельзя воздействовать снова до следующего цикла. Различные части программы эффективно развиваются параллельно, если они не взаимодействуют.
В результате большая часть кода посвящена синхронизации, в частности задержке выполнения частей программы до нужного времени. Существует множество вариантов игры в гольф, что превращает эти части в нечитаемые капли, которые можно понять, только проследив за их циклом выполнения.
Эта тактика не всегда будет индивидуально упомянута ниже:
)[A]
задержки A
на цикл. (Вероятно, самый простой и читаемый метод.)
~ef
переставляет элементы e
и f
который также задерживает их выполнение. (Вероятно, наименее читаемый, но часто самый короткий для незначительных задержек.)
$1e
задерживает один элемент e
.
-
и %
полезны для задержки чисел (последний для 0
и 1
.)
- При задержке нескольких равных элементов подряд,
:
или $
может быть использовано для их создания из одного.
(n
Заворачивает n
в скобки, которые впоследствии могут быть удалены по желанию. Это особенно важно для числовых вычислений, поскольку числа слишком нестабильны, чтобы их можно было скопировать без предварительного помещения их в блок.
Общая структура
Остальная часть объяснения разделена на семь частей, каждая для части работающей программы. Большие циклы, после которых большинство из них повторяются, будут называться «итерациями», чтобы отличать их от «циклов» одиночных проходов по всей очереди.
Вот как исходная программа делится между ними:
A: )$$4255%%1(~
B: ):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
C:
D: (H-
E:
F:
G: ):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Большая цифра в конце программы кодирует остаток в обратном порядке, две цифры на символ, причем 30 вычитается из каждого значения ASCII (например, 10
кодирует(
.)
На более высоком уровне вы можете думать о данных в этой программе (начиная с bignum) как о потоках справа налево, а о контроле - слева направо. Однако на более низком уровне Fueue постоянно запутывает различие между кодом и данными.
- Секция G декодирует bignum в ASCII-цифры (например, цифра
0
в качестве целого числа 48
), сначала выделяя младшие значащие цифры. Он производит одну цифру каждые 15 циклов.
- Раздел F содержит произведенные цифры ASCII-значений (каждое внутри блока), пока раздел E не сможет их использовать.
- Секция E обрабатывает полученные цифры по две за раз, объединяя их в блоки формы
[x[y]]
, а также печатая закодированный символ каждой пары.
- Раздел D состоит из глубоко вложенного блока, постепенно построенного из
[x[y]]
блоков таким образом, что после того, как он содержит все цифры, его можно запустить, чтобы распечатать все из них, а затем остановить всю программу.
- Раздел C обрабатывает построение раздела D, а также воссоздает раздел E.
- Раздел B воссоздает раздел C, а также сам каждые 30 циклов.
- Секция A ведет обратный отсчет циклов до последней итерации других секций. Затем он прерывает раздел B и запускает раздел D.
Раздел А
Раздел A управляет планированием конца программы. Требуется 4258 циклов, чтобы перейти к одной функции подкачки ~
, которая затем выполняет настройку секции B, которая останавливает свой основной цикл и вместо этого начинает работу секции D.
)$ $4255% %1 (~
)$%%%...%% %0 [~]
)$%%%...% %1 [~]
⋮
)$ %0 [~]
) $1[~]
)[~]
~
$
Функция создает 4255 копии следующих в %
то время как (
оборачивает ~
в скобках.
- Каждый последний цикл
%
используется для переключения следующего числа между 0
и 1
.
- Когда все
%
s израсходованы, $1
создается 1 копия [~]
(фактически NOP), а в следующем цикле )
удаляются скобки.
Раздел Б
Раздел B обрабатывает сам себя, а также новую итерацию раздела C каждые 30 циклов.
) : [)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
) [)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] [BkB]
)$ $24% %0 :< [~:)~)] ~ [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<] [BkB]
)$ %...%%% %1 < < [~:)~)] [BkB] [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]
)$ %...%% %0 < [~:)~)[BkB]] [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]
)$ %...% %1 [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
⋮
) $1 [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
) [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] (1)
~:) ~)[BkB] [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]
) : [BkB] ) [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<] (2)
) [BkB] [BkB] $11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<
:
Дублирует большой блок следующий (один экземпляр сокращенно [BkB]
), а затем )
удаляет скобку из первой копии.
$$24%%0
устанавливает обратный отсчет, аналогичный тому, который указан в разделе А.
- Пока идет обратный отсчет, он
:<
превращается в два блока <<
и ~
меняет их местами, последний размещает код для нового раздела C.
- Эти две
<
функции упаковывают два последних блока в первый - это избыточно в обычных итерациях, но позволит ~
разделу А выполнить свою работу в конце.
- (1) Когда обратный отсчет закончен,
)
удаляются внешние скобки. Далее ~:)
превращается в ):
и ~)
меняет местами )
на начало раздела C кода.
- (2) Раздел B теперь вернулся к своему начальному циклу, в то время как a
)
собирается снять скобки, чтобы начать новую итерацию раздела C.
На заключительной итерации ~
секция A появляется в точке (1) выше:
~ ) [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] (1)
[~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] )
В ~
свопы )
через блок и в секции С, предотвращая раздел В от быть снова запустить.
Раздел С
Секция C обрабатывает слияние новых пар цифровых символов в блок секции D, а также создает новые итерации секции E.
Ниже показана типичная итерация с кодами ASCII цифр x
и их y
представление. На самой первой итерации входящие элементы «D» и «E» являются начальными [H]
и -
вместо этого, так как ни один из предыдущих разделов E не выполнялся, чтобы создать какие-либо пары цифр.
C D E
$11~ ) ~<[[+$4--498+*-:~-10)):])<~] [)))~] < [)))~[...]] [x[y]]
~~~ ~~~ ~~~ ~~) [[+$4--498+*-:~-10)):])<~] < [)))~] [)))~[...][x[y]]]
~~~ ~~~ ) ~ [[+$4--498+*-:~-10)):])<~] [)))~[)))~[...][x[y]]]]
~~~ ~ ) [)))~[....]] [[+$4--498+*-:~-10)):])<~]
~~[)))~[....]] )[[+$4--498+*-:~-10)):])<~]
[)))~[....]] ~[+$4--498+*-:~-10)):])<~
- При этом используется другой метод синхронизации, который я обнаружил для этого ответа. Когда у вас есть несколько функций подкачки
~
в строке, строка будет уменьшаться примерно до 2/3 каждого цикла (потому что один ~
меняет местами два следующих), но иногда с остатком ~
s, который наносит ущерб тщательным манипуляциям с последующим.
$11~
производит такой ряд. Следующий ~
меняет местами <
следующий блок. Другой <
в конце добавляет новый блок пары цифр (цифры x и y как коды ASCII) в блок секции D.
- В следующем цикле у
~
строки есть ~~
остаток, который заменяет ~
следующий )
. Другой <
добавляет раздел D в [)))~]
блок.
- Затем сам поменял
~
местами следующий блок с новым кодом раздела E в блоке раздела D. Тогда новый остаток ~
обменивает )
поперек, и , наконец, последний ~~
в ~
ряду своп один из них через к секции Е так же , как )
снял свои квадратные скобки.
В последней итерации секция A ~
поменялась местами )
через секцию B и секцию C. Однако секция C настолько недолговечна, что уже исчезла, и )
заканчивается в начале секции D.
Раздел D
В разделе D распечатывается последняя большая цифра и останавливается программа. На протяжении большей части работы программы это инертный блок, в котором секции B – G взаимодействуют при сборке.
(H -
[H]-
⋮
[)))~[H-]] After one iteration of section C
⋮
[)))~[)))~[H-][49[49]]]] Second iteration, after E has also run
⋮
) [)))~[...]] [49[48]] Final printing starts as ) is swapped in
))) ~[...][49[48]]
)) )[49[48]] [...]
)) 49 [48][...] Print first 1
) )[48] [...]
) 48 [...] Print 0
)[...] Recurse to inner block
...
⋮
)[H-] Innermost block reached
H - Program halts
- В первом цикле программы
(
функция остановки заключает H
в скобки. -
Следующим образом , он будет использоваться как фиктивный элемент для первой итерации вместо цифр пары.
- Первая введенная пара вещественных цифр
[49[49]]
соответствует последней 11
цифре.
- Очень последняя цифра пара
[49[48]]
(соответствующая 10
в начале цифры) на самом деле не включена в блок, но это не имеет никакого значения , как )[A[B]]
и )[A][B]
эквивалентны, и превращается в A[B]
.
После последней итерации происходит )
переключение вправо из секции B, и блок секции D деблокируется. В )))~
начале каждого подблока убедитесь, что все части выполнены в правильном порядке. Наконец, самый внутренний блок содержит H
остановку программы.
Раздел Е
В разделе E обрабатываются пары пар цифр ASCII, создаваемых секцией G, и оба печатают соответствующий кодированный символ и отправляют блок с объединенной парой влево в секции C и D.
Снова ниже показана типичная итерация с x
и y
представляющая коды ASCII цифр.
E F
~ [+$4--498+*-:~-10)):] ) < ~ [y] [x]
) [+$4--498+*-:~-10)):] < [x] [y]
+ $4- - 498 +*- :~ -10 ) ) : [x[y]]
+--- -{-498} +*- ~~{-10} ) ) [x[y]] [x[y]]
+-- - 498 +* -{-10} ~ ) x [y] [x[y]]
+- -{-498} + * 10 x )[y] [x[y]]
+ - 498 + {10*x} y [x[y]]
+ {-498} {10*x+y} [x[y]]
{10*x+y-498} [x[y]]
[x[y]]
- Поступающие блоки цифр меняются местами, затем блок y добавляется к блоку x, и весь блок пары копируется. Один экземпляр останется до конца для разделов C и D.
- Другая копия снова разблокируется, затем применяется последовательность арифметических функций для вычисления
10*x+y-498
значения ASCII закодированного символа. 498 = 10*48+48-30
, То 48
s отменить ASCII кодировку x
и в y
то время как 30
сдвигает кодирование от 00–99
до30–129
, которая включает в себя все печатаемые ASCII.
- Полученное число затем оставляется для выполнения, что печатает его символ.
Раздел F
Раздел F состоит из инертных блоков, содержащих ASCII-коды цифр. Для большей части запуска программы здесь будет не более двух, поскольку секция E потребляет их с той же скоростью, с которой их производит G. Однако на заключительном этапе печати 0
здесь будут собираться лишние цифры.
[y] [x] ...
Раздел G
Раздел G обрабатывает разбиение большого числа в конце программы, сначала младшие значащие цифры, и отправку блоков с их кодами ASCII влево в другие разделы.
Так как у него нет проверки остановки, он фактически продолжит 0
генерировать цифры, когда число будет уменьшено до 0, пока секция D не остановит всю программу с помощью H
функции.
[BkG]
сокращает копию большого блока начального кода, который используется для саморепликации для запуска новых итераций.
Инициализация в первых циклах:
) :~ : [)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:] ( 106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
) ~ ~ [)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:] [BkG] [10...11]
) [)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:] ~ [BkG] [10...11]
) [):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):] ~ : [10...11] [BkG]
Типичная итерация, N
обозначает число для разделения:
) [):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):] ~ : [N] [BkG]
) :~ [)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+ :5 ) : [N] : [BkG]
) ~ ~ [)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/] +5 5 ) [N] [N] [BkG] [BkG]
) [)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/] ~ 10 N [N] [BkG] [BkG]
) ~:~ ~ ( [:~)*[):~[$1(+48]):~+]-:~~)10)~~] / N 10 [N] [BkG] [BkG]
) ~ : [:~)*[):~[$1(+48]):~+]-:~~)10)~~] ( {N/10} [N] [BkG] [BkG]
) [:~)*[):~[$1(+48]):~+]-:~~)10)~~] : [{N/10}] [N] [BkG] [BkG]
:~ )*[):~[$1(+48]):~+]- :~ ~)10 ) ~ ~ [{N/10}] [{N/10}] [N] [BkG] [BkG]
~~) *[):~[$1(+48]):~+]- ~~10 ) ) [{N/10}] ~ [{N/10}] [N] [BkG] [BkG]
) ~ * [):~[$1(+48]):~+] -10 ~ ) {N/10} [N] [{N/10}] [BkG] [BkG]
) [):~[$1(+48]):~+] * {-10} {N/10} ) [N] [{N/10}] [BkG] [BkG]
) :~ [$1(+48]) :~ + {-10*(N/10)} N [{N/10}] [BkG] [BkG]
) ~ ~ [$1(+48] ) ~ ~ {N%10} [{N/10}] [BkG] [BkG]
) [$1(+48] ~ ) {N%10} ~ [{N/10}] [BkG] [BkG]
$1( + 48 {N%10} ) [BkG] [{N/10}] [BkG]
( {48+N%10} BkG [{N/10}] [BkG] New iteration starts
[{48+N%10}] ....
- Капля задержки здесь особенно волосатая. Тем не менее, единственный новый трюк с задержкой - использовать
+:5
вместо --10
задержки 10
два цикла. Увы 10
, этому помог только один из участников программы.
[N]
И [BkG]
блоки дублируются, то один экземпляр N
делится 10
.
[{N/10}]
дублируется, тогда для вычисления кода ASCII последней цифры N
as используется больше арифметических функций 48+((-10)*(N/10)+N)
. Блок с этим кодом ASCII оставлен для секции F.
- Другая копия
[{N/10}]
обменивается между [BkG]
блоками, чтобы установить начало новой итерации.
Bonus Quine (540 байт)
)$$3371%%1[~!~~!)!]):[)$$20%%0[):]~)~~[)$$12%%0[<$$7%~~0):~[+----48+*-~~10))]<]<~!:~)~~[40~[:~))~:~[)~(~~/[+--48):]~10]+30])):]]][)[H]](11(06(06(21(21(25(19(07(07(19(61(96(03(96(96(03(11(03(63(11(28(61(11(06(06(20(18(07(07(18(61(11(28(63(96(11(96(96(61(11(06(06(19(20(07(07(18(61(30(06(06(25(07(96(96(18(11(28(96(61(13(15(15(15(15(22(26(13(12(15(96(96(19(18(11(11(63(30(63(30(96(03(28(96(11(96(96(61(22(18(96(61(28(96(11(11(96(28(96(61(11(96(10(96(96(17(61(13(15(15(22(26(11(28(63(96(19(18(63(13(21(18(63(11(11(28(63(63(63(61(11(61(42(63(63
Попробуйте онлайн!
Поскольку я не был уверен, какой метод будет самым коротким, я сначала попытался кодировать символы в виде двузначных чисел, разделенных символом (
s. Базовый код немного короче, но более полное представление данных на 50% компенсирует это. Не так хорошо, как в других, потому что я остановился, когда понял, что это не победит. У него есть одно преимущество: оно не требует реализации с поддержкой bignum.
Его общая структура чем-то похожа на основную. Раздел G отсутствует, поскольку представление данных заполняется непосредственно в разделе F. Однако в разделе E необходимо выполнить аналогичный расчет divmod для восстановления цифр двузначных чисел.