APL (158 caracteres, puntaje = 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
Estoy usando Dyalog APL aquí. El número de ciclos se puede aumentar en uno agregando 0
(0 seguido de un espacio) al final de la expresión y al final de la cadena (antes '''
). La longitud del ciclo es (# 0's) + 1
y la longitud de la expresión es 150 + 4*(cycle length))
. Suponiendo que seguimos agregando ceros para siempre, el puntaje es Limit[(150 + 4*n)/(n - 1), n -> Infinity] = 4
dónde n
está la duración del ciclo.
Aquí hay un ejemplo con la duración del ciclo = 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 caracteres, puntuación = 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
Dependiendo de la implementación, un punto de falla podría ser cuando el entero prefijado a la cadena es demasiado grande. Sin embargo, en teoría, podemos agregar un ciclo agregando dos caracteres: 1
a al final de la cadena (antes '''
) y 1
a al final de toda la línea.
200 caracteres, puntuación = 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
Mi implementación APL no tiene enteros de precisión ilimitados de manera predeterminada, por lo que el entero se convierte en flotante cuando se vuelve demasiado grande, lo que hace que la salida sea incorrecta. Entonces este es el más meticuloso, pero teóricamente (ya sea a mano o con un intérprete APL diferente), debe tener una puntuación de 1. Simplemente agregue un 1
al final de la expresión y obtendrá otro ciclo.
Descripción general (con una quine más corta)
Voy a dar una visión general de la primera versión, porque creo que es probablemente la más fácil de comprender. Sin embargo, antes de abordar esa versión, vamos a considerar una quine simple en APL :
1⌽22⍴11⍴'''1⌽22⍴11⍴'''
Descubrí que una de las mejores maneras de comprender algunas expresiones APL es mirar la salida en toda la cascada de operadores / funciones. Todos los operadores y funciones en APL son asociativos a la derecha y tienen la misma precedencia, así que aquí está, de derecha a izquierda:
'''1⌽22⍴11⍴'''
: Esto es solo un literal de cadena (una lista de caracteres). ''
es la forma APL de escapar de las comillas simples. Salida: '1⌽22⍴11⍴'
.
11⍴'''1⌽22⍴11⍴'''
: Aquí, rediseñamos ( ⍴
) la cadena para que sea de longitud 11
. Debido a que la longitud de la cadena es inferior a 11, se repite (es decir, 5⍴'abc'
produciría 'abcab'
). Salida: '1⌽22⍴11⍴''
. Así que ahora tenemos dos comillas al final: ¡estamos llegando a alguna parte!
22⍴11⍴'''1⌽22⍴11⍴'''
: Del mismo modo, ahora rediseñamos nuestra salida anterior para que sea de longitud 22
. Salida: '1⌽22⍴11⍴'''1⌽22⍴11⍴''
. Ya casi llegamos, solo necesitamos mover la primera cita al final.
1⌽22⍴11⍴'''1⌽22⍴11⍴'''
: Aquí, rotamos ( ⌽
) la lista de caracteres por 1
. Esto mueve el primer carácter de la cadena al final. Como otro ejemplo, 2⌽'abcdef'
regresa 'cdefab'
. Salida: 1⌽22⍴11⍴'''1⌽22⍴11⍴'''
.
La quine giratoria
Esa quine corta es la base principal de nuestra quine giratoria. Ahora, con eso en mente, echemos un vistazo a nuestra quine:
'''{(((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
{ ... }
define una función sin nombre, que es donde haremos el trabajo. Tenga en cuenta que las funciones en APL toman un argumento derecho, denotado por ⍵
, y un argumento izquierdo opcional, denotado por ⍺
(think infix). Queremos alimentar esta función tanto con nuestra cadena de quine como con algo que nos ayude a crear un número arbitrario de ciclos. Para hacer las cosas más fáciles para nosotros (y para cualquiera que quiera agregar ciclos), hacemos que la cadena de quine sea el argumento izquierdo. El argumento correcto, entonces, es donde ponemos nuestra lista de ciclos. 2 o más elementos separados por un espacio crean una lista, por lo que en este ejemplo, tenemos una lista de 2 elementos que consiste en ay 1
a 0
.
Podemos ver que la función se parece a la quine de antes. Tenemos la misma ...⌽...⍴...⍴...
forma de antes. Así que eso es bueno, ¡al menos lo entendemos! Vamos a profundizar más en las elipses, a partir de todo lo que después de la última ⍴
: ⊃,/(~^/¨⍺=0)/⍺
.
- Como puede ver al ver el ejemplo anterior, prefijamos la cadena con los 0 del lado derecho, agregando uno con cada iteración; pero no nos importan esos en este momento. ¡Solo queremos la cuerda!
- Primero, considere lo que hay entre paréntesis. (Por cierto, se agrupan como en la mayoría de los otros idiomas).
⍺=0
devuelve una lista, en este caso, con la misma forma que ⍺
, donde cada elemento ⍺
se reemplaza por a 1
si es igual a 0
, y a de lo 0
contrario. Esto se realiza de forma recursiva; así que si tenemos una lista de una lista de una lista de caracteres, los caracteres individuales se probarán contra 0, y obtendrá una lista de una lista de una lista de valores binarios.
- Entonces, si
⍺
consiste solo en nuestra cadena, recuperamos una lista de 0. De lo contrario, nuestro argumento izquierdo tiene algunos 0 prefijados (por ejemplo, 0 0 0 'quinestring'
), por lo que es una lista que consta de 0 y otra lista, nuestra cadena. Entonces nuestra salida se ve así 1 1 1 <sub-list of zeros>
.
^/¨⍺=0
: Aplicamos la función derivada ^/
, que reduce ( /
) usando la función lógica AND ( ^
), a cada ¨
elemento ( ) de ⍺=0
. Esto es para aplanar la sublista de ceros para que podamos considerar la cadena de quine como un valor binario. Considerando el ejemplo anterior, la salida sería 1 1 1 0
.
~
: Binarios NO cada uno de los valores de antes (por ejemplo, volver 0 0 0 1
).
(~^/¨⍺=0)/⍺
: Para cada elemento en ⍺
, lo replicamos ( /
) el número de veces dado por el elemento correspondiente en el argumento izquierdo. Esto elimina todos los 0, dejándonos solo con nuestra cadena de quine.
⊃,/
es una documentación necesaria para garantizar que recuperemos una lista de caracteres aplanada, reduciendo el resultado con la función de concatenación ( ,
). Si la entrada ya es una lista aplanada (es decir, el argumento izquierdo de nuestra función principal es solo la cadena), obtenemos una lista de 1 elemento que contiene esa lista. En el otro caso, cuando tenemos una lista que consiste en una sublista para la cadena, recuperamos lo mismo (una lista con una sublista). Luego desempaquetamos esto ( ⊃
), dándonos solo el primer elemento de la lista (es decir, la sublista de caracteres). Esto puede parecer innecesario, pero de lo contrario estaríamos tratando de remodelar una lista de 1 elemento.
A continuación, observamos la longitud dada para la primera remodelación, entre paréntesis:
⍺,⍵
: Concatenamos el argumento correcto con el primer argumento
⊃,/⍺,⍵
: Igual que antes: aplanar la lista.
+/0=⊃,/⍺,⍵
: Suma el número de ceros en la lista reduciendo ( /
) usando la función suma ( +
).
2×+/0=⊃,/⍺,⍵
: Multiplica ese número por dos.
z←2×+/0=⊃,/⍺,⍵
: Asignar ( ←
) el resultado a una variable, z
. En resumen, z
ahora es el doble del número de ceros encontrados en los argumentos izquierdo y derecho.
77+z←2×+/0=⊃,/⍺,⍵
: Luego agregamos 77
, para los caracteres en la cadena de quine, ignorando todo después del espacio siguiente 1
. Como en el ejemplo de quine inicial, agregamos 1 a la longitud de la cadena para obtener otra comilla simple.
- La salida de esta remodelación, en este ejemplo, es:
'{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 ''
El argumento para la remodelación que sigue es simple y refleja la quine corta (2 veces la longitud de la primera remodelación). Nuestra salida ahora es:
'{(((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 ''
Ahora para el paso final, donde calculamos cuánto girar la cadena de salida:
- Como puede ver mirando el resultado anterior, queremos rotarlo (una cantidad negativa) para llevar las 2 citas finales al principio. Debido a que queremos que un
0
(y otro espacio) se mueva al principio también, queremos rotarlo 3 caracteres adicionales hacia atrás.
+/+/¨⍺=0
: Sume el número de ceros en el argumento izquierdo . El primero (desde la derecha) +/¨
suma el recuento de cada elemento (es decir, una sublista o solo un número entero), y el segundo +/
nos da la suma de esa lista resultante.
5+2×+/+/¨⍺=0
: Multiplique por dos (para rotar los espacios también) y agregue 5 (el resultado que obtuvimos antes).
- Ahora, restamos el valor anterior del argumento izquierdo
-
para manejar el caso cuando llegamos al final de nuestro ciclo:
(3+z)×^/⍵
: Y todos los elementos en el argumento correcto juntos para ver si hemos llegado a nuestro final ( 1
), y multiplicar eso por 3+z
.
¡Y hemos terminado!