Fueue , 423 bytes
Fueue é um esolang baseado em fila no qual o programa em execução é a fila.
)$$4255%%1(~):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]](H-):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Experimente online!
Como funciona
Esta explicação pode ou não ter saído do controle. Por outro lado, não sei como explicar isso de maneira muito mais curta, de maneira que espero que as pessoas possam seguir.
Folha de dicas para Fueue
Consulte o artigo wiki da esolang para obter detalhes, incluindo os poucos recursos não utilizados neste programa.
O programa inicial é o estado inicial da fila, que pode conter os seguintes elementos:
- Literais inteiros (somente não negativos na fonte, mas negativos podem ser calculados), executá-los imprime um caractere.
- Blocos aninhados delimitados por colchetes, inertes (preservados intactos, a menos que alguma função atue sobre eles).
- Funções, seus argumentos são os elementos que os seguem imediatamente na fila:
+*/-%
: aritmético inteiro ( -
é unário, %
negação lógica). Inertes se não forem fornecidos argumentos numéricos.
()<
: coloque o elemento entre colchetes, remova os colchetes do bloco e adicione o elemento final ao bloco. Os dois últimos são inertes, a menos que sejam seguidos por um bloco.
~:
: troca, duplicado.
$
: copiar (leva número + elemento). Inerte antes do não número.
H
: interromper o programa.
Note que enquanto []
ninho, ()
não - estas últimas são simplesmente funções separadas.
Sintaxe de rastreamento de execução
O espaço em branco é opcional no Fueue, exceto entre números. Nos seguintes rastreamentos de execução, será usado para sugerir a estrutura do programa, em particular:
- Quando uma função é executada, ela e seus argumentos são destacados dos elementos circundantes com espaços. Se alguns dos argumentos forem complicados, também pode haver um espaço entre eles.
- Muitos rastreamentos de execução são divididos em um "blob de atraso" à esquerda, separado de uma parte à direita que faz a manipulação substancial de dados. Veja a próxima seção.
Os colchetes {}
(não usados no Fueue) são usados nos rastreamentos para representar o resultado inteiro de expressões matemáticas. Isso inclui números negativos, pois o Fueue possui apenas literais não negativos - -
é a função de negação.
Vários nomes meta-variáveis e ...
são usados para denotar valores e abreviações.
Táticas de atraso
Intuitivamente, a execução percorre a fila, modificando parcialmente o que ela passa. Os resultados de uma função não podem ser acionados novamente até o próximo ciclo. Diferentes partes do programa evoluem efetivamente em paralelo, desde que não interajam.
Como resultado, grande parte do código é dedicada à sincronização, em particular para atrasar a execução de partes do programa até o momento certo. Existem muitas opções para jogar golfe, o que tende a transformar essas partes em blobs ilegíveis que só podem ser entendidos rastreando seu ciclo de execução por ciclo.
Essas táticas nem sempre serão mencionadas individualmente no abaixo:
)[A]
atrasos A
para um ciclo. (Provavelmente, o método mais fácil e mais legível.)
~ef
troca os elementos e
e f
também atrasa sua execução. (Provavelmente o menos legível, mas geralmente o mais curto para pequenos atrasos.)
$1e
atrasa um único elemento e
.
-
e %
são úteis para atrasar números (este último para 0
e 1
.)
- Ao atrasar vários elementos iguais em uma linha,
:
ou $
pode ser usado para criá-los a partir de um único.
(n
envoltórios n
entre parênteses, que podem ser removidos posteriormente por conveniência. Isso é particularmente vital para cálculos numéricos, já que os números são instáveis demais para serem copiados sem antes colocá-los em um bloco.
Estrutura geral
O restante da explicação é dividido em sete partes, cada uma para uma seção do programa em execução. Os ciclos maiores, após os quais a maioria deles se repete, serão chamados de "iterações" para distingui-los dos "ciclos" de passagens únicas por toda a fila.
Aqui está como o programa inicial é dividido entre eles:
A: )$$4255%%1(~
B: ):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
C:
D: (H-
E:
F:
G: ):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
O grande número no final do programa codifica o restante na ordem inversa, dois dígitos por caractere, com 30 subtraídos de cada valor ASCII (por exemplo, 10
codifica a (
.)
Em um nível superior, você pode pensar nos dados deste programa (começando com o bignum) como fluindo da direita para a esquerda, mas controlando a fluência da esquerda para a direita. No entanto, em um nível inferior, o Fueue atrapalha a distinção entre código e dados o tempo todo.
- A Seção G decodifica o bignum em dígitos ASCII (por exemplo, dígito
0
como número inteiro 48
), dividindo primeiro os dígitos menos significativos. Produz um dígito a cada 15 ciclos.
- A seção F contém os valores ASCII de dígitos produzidos (cada um dentro de um bloco) até que a seção E possa consumi-los.
- A Seção E lida com os dígitos produzidos dois de cada vez, combinando-os em blocos do formulário
[x[y]]
, imprimindo também o caractere codificado de cada par.
- A Seção D consiste em um bloco profundamente aninhado, gradualmente construído a partir dos
[x[y]]
blocos, de forma que, uma vez que contenha todos os dígitos, ele possa ser executado para imprimir todos eles e interromper o programa inteiro.
- A seção C lida com a construção da seção D e também recria a seção E.
- A seção B recria a seção C e a si mesma a cada 30 ciclos.
- A seção A faz uma contagem regressiva dos ciclos até a última iteração das outras seções. Em seguida, aborta a seção B e executa a seção D.
Seção a
A seção A lida com a programação do final do programa. São necessários 4258 ciclos para reduzir a uma única função de troca ~
, que faz um ajuste na seção B que interrompe seu loop principal e inicia a execução da seção D.
)$ $4255% %1 (~
)$%%%...%% %0 [~]
)$%%%...% %1 [~]
⋮
)$ %0 [~]
) $1[~]
)[~]
~
- Uma
$
função cria 4255 cópias do seguinte, %
enquanto a (
coloca ~
entre colchetes.
- Cada ciclo o último
%
é usado para alternar o seguinte número entre 0
e 1
.
- Quando todos os
%
s são usados, ele $1
cria 1 cópia do [~]
(efetivamente um NOP) e, no próximo ciclo, )
remove os colchetes.
Seção B
A Seção B lida com a regeneração, bem como uma nova iteração da seção C a cada 30 ciclos.
) : [)$$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)):])<~][)))~]<
- A
:
duplica o bloco grande a seguir (uma cópia abreviada como [BkB]
) e )
remove os colchetes da primeira cópia.
$$24%%0
configura uma contagem regressiva semelhante à da seção A.
- Enquanto isso conta,
:<
se transforma <<
e ~
troca dois dos blocos, colocando o código para uma nova seção C por último.
- As duas
<
funções agrupam os dois blocos finais no primeiro - isso é redundante nas iterações normais, mas permitirá que a ~
seção A faça seu trabalho no final.
- (1) Quando a contagem regressiva termina, os
)
colchetes externos são removidos. Em seguida, ~:)
vira ):
e ~)
troca a )
para o início do código da seção C.
- (2) A Seção B agora está de volta ao seu ciclo inicial, enquanto a
)
está prestes a remover os colchetes para começar a executar uma nova iteração da seção C.
Na iteração final, a ~
seção A aparece no ponto (1) acima:
~ ) [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] (1)
[~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] )
O ~
swaps )
atravessa o bloco e entra na seção C, impedindo que a seção B seja executada novamente.
Seção C
A Seção C trata da fusão de novos pares de caracteres de dígitos no bloco da seção D e também da criação de novas iterações da seção E.
O abaixo mostra uma iteração típica com x
e y
representando os códigos ASCII dos dígitos. Na primeira iteração, os elementos "D" e "E" recebidos são os iniciais [H]
e -
, em vez disso, como nenhuma seção anterior E foi executada para produzir pares de caracteres de dígitos.
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)):])<~
- Isso usa um método diferente de sincronização que eu descobri para esta resposta. Quando você tem várias funções de troca
~
em uma linha, a linha diminui para aproximadamente 2/3 de cada ciclo (porque um ~
troca dois a seguir), mas ocasionalmente com um restante de ~
s que causa danos manipula cuidadosamente o que se segue.
$11~
produz essa linha. O próximo ~
troca um <
pelo bloco a seguir. Outro <
no final anexa um novo bloco de pares de dígitos (dígitos x e y como códigos ASCII) ao bloco da seção D.
- No próximo ciclo, a
~
linha tem um ~~
restante, que troca um ao ~
longo do seguinte )
. O outro <
anexa a seção D a um [)))~]
bloco.
- Em seguida, o
~
próprio swap trocou o seguinte bloco com o novo código da seção E no bloco da seção D. Em seguida, uma nova sobra ~
troca uma )
e, finalmente, a última ~~
da ~
linha troca uma delas pela seção E, assim como a chave )
foi removida.
Na iteração final, as seções A ~
trocaram um )
entre a seção B e a seção C. No entanto, a seção C é tão curta que já desapareceu e )
termina no início da seção D.
Seção D
A seção D trata da impressão do grande número final e da interrupção do programa. Durante a maior parte da execução do programa, é um bloco inerte que as seções B – G cooperam na construção.
(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
- No primeiro ciclo do programa, a
(
envolve a função de parada H
entre colchetes. A -
seguir, ele será usado como um elemento fictício para a primeira iteração, em vez de um par de dígitos.
- O primeiro par de dígitos reais incorporado é
[49[49]]
correspondente à final 11
do numeral.
- O último par de dígitos
[49[48]]
(correspondente ao 10
início do número) não é realmente incorporado ao bloco, mas isso não faz diferença )[A[B]]
e )[A][B]
é equivalente, ambos se transformando em A[B]
.
Após a iteração final, o )
trocado para a direita da seção B chega e o bloco da seção D é desbloqueado. O )))~
início de cada sub-bloco garante que todas as partes sejam executadas na ordem correta. Finalmente, o bloco mais interno contém a H
interrupção do programa.
Seção E
A Seção E lida com a combinação de pares de dígitos ASCII produzidos pela seção G, e ambos imprimem o caractere codificado correspondente e enviam um bloco com o par combinado à esquerda para as seções C e D.
Novamente, o abaixo mostra uma iteração típica com x
e y
representando os códigos ASCII dos dígitos.
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]]
- Os blocos de dígitos recebidos são trocados, o bloco y é anexado ao bloco x e todo o bloco de pares é copiado. Uma cópia será deixada até o final das seções C e D.
- A outra cópia é desbloqueada novamente e, em seguida, uma sequência de funções aritméticas é aplicada para calcular
10*x+y-498
o valor ASCII do caractere codificado. 498 = 10*48+48-30
, 48
desfaz a codificação ASCII de x
e y
enquanto 30
muda a codificação de 00–99
para para 30–129
, o que inclui todos os ASCII imprimíveis.
- O número resultante é então deixado para executar, que imprime seu caractere.
Seção F
A seção F consiste em blocos inertes contendo códigos de dígitos ASCII. Para a maior parte do programa executado, haverá no máximo dois aqui, pois a seção E os consome na mesma velocidade que G os produz. No entanto, na fase final de impressão, alguns 0
dígitos redundantes serão coletados aqui.
[y] [x] ...
Seção G
A Seção G lida com a divisão do grande número no final do programa, primeiro com os dígitos menos significativos, e com o envio de blocos com seus códigos ASCII para as demais seções.
Como não tem verificação de parada, ele continuará produzindo 0
dígitos quando o número for reduzido a 0, até que a seção D interrompa o programa inteiro com a H
função.
[BkG]
abrevia uma cópia do grande bloco de código inicial, que é usado para auto-replicação para iniciar novas iterações.
Inicialização nos primeiros ciclos:
) :~ : [)[):~[)~:~~([:~)*[):~[$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]
A iteração típica N
indica o número a ser dividido:
) [):~[)~:~~([:~)*[):~[$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}] ....
- O atraso aqui é particularmente cabeludo. No entanto, o único novo truque de atraso é usar em
+:5
vez de --10
atrasar 10
dois ciclos. Infelizmente, apenas um dos 10
s no programa foi ajudado por isso.
- Os blocos
[N]
e [BkG]
são duplicados e, em seguida, uma cópia N
é dividida por 10
.
[{N/10}]
é duplicado, mais funções aritméticas são usadas para calcular o código ASCII do último dígito de N
as 48+((-10)*(N/10)+N)
. O bloco com este código ASCII é deixado para a seção F.
- A outra cópia de
[{N/10}]
é trocada entre os [BkG]
blocos para configurar o início de uma nova iteração.
Quine de bônus (540 bytes)
)$$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
Experimente online!
Como não tinha certeza de qual método seria o mais curto, tentei codificar caracteres como números de dois dígitos separados por (
s. O código principal é um pouco menor, mas a representação de dados 50% maior o compensa. Não é tão jogado como o outro, pois parei quando percebi que não venceria. Ele tem uma vantagem: não requer uma implementação com suporte a bignum.
Sua estrutura geral é um pouco semelhante à principal. A seção G está ausente, pois a representação de dados preenche a seção F diretamente. No entanto, a seção E deve fazer um cálculo divmod semelhante para reconstruir os dígitos dos números de dois dígitos.