Fueue , 423 bytes
Fueue es un esolang basado en cola en el que el programa en ejecución es la cola.
)$$4255%%1(~):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]](H-):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Pruébalo en línea!
Cómo funciona
Esta explicación puede o no haberse salido de control. Por otro lado, no sé cómo explicarlo mucho más brevemente de una manera que espero que la gente pueda seguir.
Fueue hoja de trucos
Consulte el artículo wiki de esolang para obtener detalles, incluidas las pocas funciones que no se utilizan en este programa.
El programa inicial es el estado inicial de la cola, que puede contener los siguientes elementos:
- Los literales enteros (solo no negativos en la fuente, pero se pueden calcular los negativos), al ejecutarlos se imprime un carácter.
- Bloques anidados delimitados por corchetes, inertes (conservados intactos a menos que alguna función actúe sobre ellos).
- Funciones, sus argumentos son los elementos que los siguen inmediatamente en la cola:
+*/-%
: aritmética de enteros ( -
es unario, %
negación lógica). Inerte si no se le dan argumentos numéricos.
()<
: coloca el elemento entre paréntesis, elimina los paréntesis del bloque, agrega el elemento final al bloque. Los dos últimos son inertes a menos que estén seguidos de un bloque.
~:
: intercambiar, duplicar.
$
: copia (toma número + elemento). Inerte antes del no número.
H
: detener el programa.
Tenga en cuenta que si bien []
anida, ()
no lo haga; estas últimas son simplemente funciones separadas.
Sintaxis de seguimiento de ejecución
El espacio en blanco es opcional en Fueue, excepto entre números. En las siguientes trazas de ejecución se utilizará para sugerir la estructura del programa, en particular:
- Cuando se ejecuta una función, ésta y sus argumentos se activarán a partir de los elementos circundantes con espacios. Si algunos de los argumentos son complicados, también puede haber un espacio entre ellos.
- Muchos rastros de ejecución se dividen en un "blob de retraso" a la izquierda, separado de una parte a la derecha que realiza la manipulación sustancial de datos. Ver la siguiente sección.
Las llaves {}
(no utilizadas en Fueue) se utilizan en las trazas para representar el resultado entero de las expresiones matemáticas. Esto incluye números negativos, ya que Fueue solo tiene literales no negativos: -
es la función de negación.
Varios nombres metavariables y ...
se utilizan para denotar valores y abreviaturas.
Tácticas dilatorias
Intuitivamente, la ejecución gira alrededor de la cola, modificando parcialmente lo que pasa. Los resultados de una función no se pueden volver a actuar hasta el próximo ciclo. Las diferentes partes del programa evolucionan efectivamente en paralelo siempre que no interactúen.
Como resultado, gran parte del código se dedica a la sincronización, en particular a retrasar la ejecución de partes del programa hasta el momento adecuado. Hay muchas opciones para jugar al golf, que tiende a convertir esas partes en gotas ilegibles que solo se pueden entender al rastrear su ejecución ciclo por ciclo.
Estas tácticas no siempre se mencionarán individualmente en lo siguiente:
)[A]
retrasos A
para un ciclo. (Probablemente el método más fácil y más legible).
~ef
intercambia los elementos e
y f
eso también retrasa su ejecución. (Probablemente el menos legible, pero a menudo el más corto para retrasos menores).
$1e
retrasa un solo elemento e
.
-
y %
son útiles para retrasar números (este último para 0
y 1
.)
- Al retrasar varios elementos iguales en una fila,
:
o $
puede usarse para crearlos desde uno solo.
(n
Envolturas n
entre paréntesis, que luego se pueden quitar a conveniencia. Esto es particularmente vital para los cálculos numéricos, ya que los números son demasiado inestables para ser copiados sin ponerlos primero en un bloque.
Estructura general
El resto de la explicación se divide en siete partes, cada una para una sección del programa en ejecución. Los ciclos más grandes después de los cuales la mayoría de ellos se repiten se denominarán "iteraciones" para distinguirlos de los "ciclos" de pasadas individuales en toda la cola.
Así es como se divide el programa inicial entre ellos:
A: )$$4255%%1(~
B: ):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
C:
D: (H-
E:
F:
G: ):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
El gran número al final del programa codifica el resto en reversa, dos dígitos por carácter, con 30 restados de cada valor ASCII (por ejemplo, 10
codifica a (
).
En un nivel superior, puede pensar que los datos en este programa (comenzando con el bignum) fluyen de derecha a izquierda, pero el control fluye de izquierda a derecha. Sin embargo, en un nivel inferior, Fueue confunde la distinción entre código y datos todo el tiempo.
- La sección G decodifica el bignum en dígitos ASCII (por ejemplo, un dígito
0
como número entero 48
), separando primero los dígitos menos significativos. Produce un dígito cada 15 ciclos.
- La sección F contiene los valores ASCII de dígitos producidos (cada uno dentro de un bloque) hasta que la sección E pueda consumirlos.
- La Sección E maneja los dígitos producidos de dos en dos, emparejándolos en bloques del formulario
[x[y]]
, también imprime el carácter codificado de cada par.
- La Sección D consiste en un bloque profundamente anidado construido gradualmente a partir de los
[x[y]]
bloques de tal manera que una vez que contiene todos los dígitos, se puede ejecutar para imprimirlos todos y luego detener todo el programa.
- La sección C maneja la construcción de la sección D, y también recrea la sección E.
- La sección B recrea la sección C, así como a sí misma, cada 30 ciclos.
- La sección A cuenta los ciclos hasta la última iteración de las otras secciones. Luego aborta la sección B y ejecuta la sección D.
Sección a
La Sección A maneja la programación del final del programa. Se requieren 4258 ciclos para reducir a una sola función de intercambio ~
, que luego realiza un ajuste en la sección B que detiene su bucle principal y comienza a ejecutar la sección D en su lugar.
)$ $4255% %1 (~
)$%%%...%% %0 [~]
)$%%%...% %1 [~]
⋮
)$ %0 [~]
) $1[~]
)[~]
~
- Una
$
función crea 4255 copias de lo siguiente%
mientras se (
envuelve ~
entre paréntesis.
- Cada ciclo el último
%
se usa para alternar el siguiente número entre 0
y 1
.
- Cuando todos los
%
s están agotados, el $1
crea 1 copia del[~]
(efectivamente un NOP), y en el siguiente ciclo, )
elimina los corchetes.
Sección B
La sección B maneja la regeneración de sí mismo, así como una nueva iteración de la sección C 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 el siguiente bloque grande (una copia abreviada como[BkB]
), luego )
elimina los corchetes de la primera copia.
$$24%%0
establece una cuenta regresiva similar a la de la sección A.
- Mientras esto cuenta atrás, se
:<
convierte en <<
y un~
cambia dos de los bloques, colocando el código para una nueva sección C al final.
- Las dos
<
funciones empaquetan los dos bloques finales en el primero; esto es redundante en las iteraciones normales, pero permitirá~
sección A haga su trabajo al final.
- (1) Cuando finaliza la cuenta regresiva,
)
elimina los corchetes externos. Luego se ~:)
convierte ):
y ~)
cambia un)
a al comienzo del código de la sección C.
- (2) La sección B ahora está de vuelta en su ciclo inicial, mientras que a
)
está a punto de eliminar los corchetes para comenzar a ejecutar una nueva iteración de la sección C.
En la iteración final, la ~
sección A aparece en el punto (1) anterior:
~ ) [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] (1)
[~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] )
Los ~
intercambios de)
de todo el bloque y en la sección C, la prevención de la sección B se ejecute de nuevo.
Sección C
La Sección C maneja la fusión de nuevos pares de caracteres de dígitos en el bloque de la sección D, y también crea nuevas iteraciones de la sección E.
A continuación se muestra una iteración típica con x
y que y
representa los códigos ASCII de los dígitos. En la primera iteración, los elementos entrantes "D" y "E" son los iniciales [H]
y -
, en cambio, como ninguna sección anterior E se ha ejecutado para producir ningún par 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)):])<~
- Esto usa un método diferente de sincronización que descubrí para esta respuesta. Cuando tiene varias funciones de intercambio
~
en una fila, la fila se reducirá a aproximadamente 2/3 cada ciclo (porque uno ~
intercambia dos siguientes), pero ocasionalmente con un resto de ~
s que causa estragos manipula cuidadosamente lo que sigue.
$11~
produce tal fila. El siguiente ~
intercambia a a <
través del siguiente bloque. Otro <
al final agrega un nuevo bloque de pares de dígitos (dígitos x e y como códigos ASCII) en el bloque de la sección D.
- El siguiente ciclo, la
~
fila tiene un ~~
resto, que intercambia un ~
sobre el siguiente )
. El otro <
agrega la sección D a un [)))~]
bloque.
- A continuación, el intercambiado
~
intercambia el siguiente bloque con el nuevo código de la sección E en el bloque de la sección D. Luego, un nuevo sobrante ~
intercambia una )
cruz y, finalmente, la última ~~
de la ~
fila intercambia una de ellas a la sección E justo cuando )
ha eliminado sus corchetes.
En la iteración final, la sección A ~
ha cambiado una )
sección B a la sección C. Sin embargo, la sección C es tan efímera que ya ha desaparecido, y el)
termina al principio de la sección D.
Sección D
La sección D se encarga de imprimir el número grande final y detener el programa. Durante la mayor parte de la ejecución del programa, es un bloque inerte que las secciones B – G cooperan en la construcción.
(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
- En el primer ciclo del programa, a
(
envuelve la función de detención H
entre paréntesis. UNA-
continuación, se utilizará como un elemento ficticio para la primera iteración en lugar de un par de dígitos.
- El primer par de dígitos real incorporado es el
[49[49]]
correspondiente al final 11
en el número.
- El último par de dígitos
[49[48]]
(que corresponde al 10
principio del número) no se incorpora realmente al bloque, pero esto no hace ninguna diferencia como )[A[B]]
y )[A][B]
son equivalentes, ambos se convierten en A[B]
.
Después de la iteración final, )
llega el intercambio hacia la derecha desde la sección B y se desbloquea el bloque de la sección D. El )))~
principio de cada subbloque asegura que todas las partes se ejecuten en el orden correcto. Finalmente, el bloque más interno contiene una H
detención del programa.
Sección E
La sección E maneja la combinación de pares de dígitos ASCII producidos por la sección G, y ambos imprimen el carácter codificado correspondiente y envían un bloque con el par combinado hacia la izquierda a las secciones C y D.
Nuevamente, a continuación se muestra una iteración típica con x
y que y
representa los códigos ASCII de los 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]]
- Los bloques de dígitos entrantes se intercambian, luego el bloque y se agrega al bloque x, y se copia todo el bloque de pares. Se dejará una copia hasta el final para las secciones C y D.
- La otra copia se desbloquea nuevamente, luego se aplica una secuencia de funciones aritméticas para calcular
10*x+y-498
el valor ASCII del carácter codificado. 498 = 10*48+48-30
, 48
s deshace la codificación ASCII de x
y y
mientras 30
cambia la codificación de 00–99
a 30–129
, que incluye todos los ASCII imprimibles.
- El número resultante se deja ejecutar, lo que imprime su carácter.
Seccion F
La sección F consta de bloques inertes que contienen códigos ASCII de dígitos. Para la mayor parte de la ejecución del programa, habrá como máximo dos aquí, ya que la sección E los consume a la misma velocidad con la que G los produce. Sin embargo, en la fase de impresión final 0
, aquí se acumularán algunos dígitos redundantes .
[y] [x] ...
Seccion G
La Sección G maneja la división del gran número al final del programa, los dígitos menos significativos primero, y el envío de bloques con sus códigos ASCII a la izquierda a las otras secciones.
Como no tiene verificación de detención, en realidad continuará produciendo 0
dígitos cuando el número se haya reducido a 0, hasta que la sección D detenga todo el programa con la H
función.
[BkG]
abrevia una copia del gran bloque de código de inicio, que se utiliza para la autorreplicación para iniciar nuevas iteraciones.
Inicialización en los primeros 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]
Iteración típica, N
denota el número para dividir:
) [):~[)~:~~([:~)*[):~[$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}] ....
- La gota de retraso aquí es particularmente peluda. Sin embargo, el único nuevo truco de demora es usar en
+:5
lugar de --10
retrasar 10
dos ciclos. Por desgracia, solo uno de los 10
s en el programa fue ayudado por esto.
- Los bloques
[N]
y [BkG]
se duplican, luego una copia de N
se divide por10
.
[{N/10}]
se duplica, luego se utilizan más funciones aritméticas para calcular el código ASCII del último dígito de N
as 48+((-10)*(N/10)+N)
. El bloque con este código ASCII se deja para la sección F.
- La otra copia de
[{N/10}]
se intercambia entre los [BkG]
bloques para configurar el inicio de una nueva iteración.
Bonus quine (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
Pruébalo en línea!
Como no estaba seguro de qué método sería el más corto, primero intenté codificar caracteres como números de dos dígitos separados por (
s. El código central es un poco más corto, pero la representación de datos un 50% más grande lo compensa. No tan golfizado como el otro, ya que me detuve cuando me di cuenta de que no lo superaría. Tiene una ventaja: no requiere una implementación con soporte bignum.
Su estructura general es algo similar a la principal. Falta la sección G ya que la representación de datos completa la sección F directamente. Sin embargo, la sección E debe hacer un cálculo divmod similar para reconstruir los dígitos de los números de dos dígitos.