Hexagony , 920 722 271 bytes
¿Seis tipos diferentes de bucles de fruta, dices? Para eso fue hecha Hexagony.
){r''o{{y\p''b{{g''<.{</"&~"&~"&<_.>/{.\.....~..&.>}<.._...=.>\<=..}.|>'%<}|\.._\..>....\.}.><.|\{{*<.>,<.>/.\}/.>...\'/../==.|....|./".<_>){{<\....._>\'=.|.....>{>)<._\....<..\..=.._/}\~><.|.....>e''\.<.}\{{\|./<../e;*\.@=_.~><.>{}<><;.(~.__..>\._..>'"n{{<>{<...="<.>../
De acuerdo, no lo fue. Oh dios, que me hice a mi mismo ...
Este código ahora es un hexágono de longitud lateral 10 (comenzó en 19). Probablemente podría jugar un poco más, tal vez incluso hasta el tamaño 9, pero creo que mi trabajo se hace aquí ... Como referencia, hay 175 comandos reales en la fuente, muchos de los cuales son espejos potencialmente innecesarios (o se agregaron para cancelar un comando desde un cruce).
A pesar de la aparente linealidad, el código es en realidad bidimensional: Hexagony lo reorganizará en un hexágono regular (que también es un código válido, pero todo el espacio en blanco es opcional en Hexagony). Aquí está el código desplegado en todos sus ... bueno, no quiero decir "belleza":
) { r ' ' o { { y \
p ' ' b { { g ' ' < .
{ < / " & ~ " & ~ " & <
_ . > / { . \ . . . . . ~
. . & . > } < . . _ . . . =
. > \ < = . . } . | > ' % < }
| \ . . _ \ . . > . . . . \ . }
. > < . | \ { { * < . > , < . > /
. \ } / . > . . . \ ' / . . / = = .
| . . . . | . / " . < _ > ) { { < \ .
. . . . _ > \ ' = . | . . . . . > {
> ) < . _ \ . . . . < . . \ . . =
. . _ / } \ ~ > < . | . . . . .
> e ' ' \ . < . } \ { { \ | .
/ < . . / e ; * \ . @ = _ .
~ > < . > { } < > < ; . (
~ . _ _ . . > \ . _ . .
> ' " n { { < > { < .
. . = " < . > . . /
Explicación
Ni siquiera intentaré comenzar a explicar todas las rutas de ejecución complicadas en esta versión de golf, pero el algoritmo y el flujo de control general son idénticos a esta versión sin golf que podría ser más fácil de estudiar para los realmente curiosos después de haber explicado el algoritmo:
) { r ' ' o { { \ / ' ' p { . . .
. . . . . . . . y . b . . . . . . .
. . . . . . . . ' . . { . . . . . . .
. . . . . . . . \ ' g { / . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . > . . . . < . . . . . . . . .
. . . . . . . . . . . . . . > . . ) < . . . . .
. . . . . . . . . . / = { { < . . . . ( . . . . .
. . . . . . . . . . . ; . . . > . . . . . . . . . <
. . . . . . . . . . . . > < . / e ; * \ . . . . . . .
. . . . . . . . . . . . @ . } . > { } < . . | . . . . .
. . . . . / } \ . . . . . . . > < . . . > { < . . . . . .
. . . . . . > < . . . . . . . . . . . . . . . | . . . . . .
. . . . . . . . _ . . > . . \ \ " ' / . . . . . . . . . . . .
. . . . . . \ { { \ . . . > < . . > . . . . \ . . . . . . . . .
. < . . . . . . . * . . . { . > { } n = { { < . . . / { . \ . . |
. > { { ) < . . ' . . . { . \ ' < . . . . . _ . . . > } < . . .
| . . . . > , < . . . e . . . . . . . . . . . . . = . . } . .
. . . . . . . > ' % < . . . . . . . . . . . . . & . . . | .
. . . . _ . . } . . > } } = ~ & " ~ & " ~ & " < . . . . .
. . . \ . . < . . . . . . . . . . . . . . . . } . . . .
. \ . . . . . . . . . . . . . . . . . . . . . . . < .
. . . . | . . . . . . . . . . . . . . . . . . = . .
. . . . . . \ . . . . . . . . . . . . . . . . / .
. . . . . . > . . . . . . . . . . . . . . . . <
. . . . . . . . . . . . . . . . . . . . . . .
_ . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
Honestamente, en el primer párrafo solo bromeaba a medias. El hecho de que estemos lidiando con un ciclo de seis elementos fue realmente una gran ayuda. El modelo de memoria de Hexagony es una cuadrícula hexagonal infinita donde cada borde de la cuadrícula contiene un entero de precisión arbitraria con signo, inicializado a cero.
Aquí hay un diagrama del diseño de la memoria que he usado en este programa:
El bit recto largo de la izquierda se usa como una cadena terminada en 0 a
de tamaño arbitrario que está asociada con la letra r . Las líneas discontinuas en las otras letras representan el mismo tipo de estructura, cada una rotada 60 grados. Inicialmente, el puntero de memoria apunta al borde con la etiqueta 1 , hacia el norte.
El primer bit lineal del código establece la "estrella" interna de los bordes en las letras roygbp
y establece el borde inicial en 1
, de modo que sepamos dónde termina / comienza el ciclo (entre p
y r
):
){r''o{{y''g{{b''p{
Después de esto, volvemos al borde etiquetado como 1 .
Ahora la idea general del algoritmo es esta:
- Para cada letra del ciclo, siga leyendo las letras de STDIN y, si son diferentes de la letra actual, agréguelas a la cadena asociada con esa letra.
- Cuando leemos la carta que estamos buscando actualmente, almacenamos una
e
en el borde con la etiqueta ? , porque mientras el ciclo no esté completo, debemos suponer que también tendremos que comer este personaje. Luego, nos moveremos alrededor del anillo hasta el siguiente personaje del ciclo.
- Hay dos formas de interrumpir este proceso:
- O hemos completado el ciclo. En este caso, hacemos otra ronda rápida a través del ciclo, reemplazando todos esos
e
s en el ? bordes con n
s, porque ahora queremos que ese ciclo permanezca en el collar. Luego pasamos a imprimir código.
- O presionamos EOF (que reconocemos como un código de carácter negativo). En este caso, escribimos un valor negativo en el ? borde del carácter actual (para que podamos distinguirlo fácilmente de ambos
e
y n
). Luego buscamos el borde 1 (para omitir el resto de un ciclo potencialmente incompleto) antes de pasar también al código de impresión.
- El código de impresión vuelve a pasar por el ciclo: para cada carácter del ciclo, borra la cadena almacenada mientras imprime un
e
para cada carácter. Entonces se mueve a la ? borde asociado con el personaje. Si es negativo, simplemente terminamos el programa. Si es positivo, simplemente lo imprimimos y pasamos al siguiente personaje. Una vez que completamos el ciclo, volvemos al paso 2.
Otra cosa que puede ser interesante es cómo he implementado las cadenas de tamaño arbitrario (porque es la primera vez que uso memoria sin límites en Hexagony).
Imagine que estamos en algún punto en el que todavía estamos leyendo caracteres para r (para que podamos usar el diagrama tal como está) y un [0] y un 1 ya se han llenado de caracteres (todo el noroeste de ellos sigue siendo cero) ) Por ejemplo, quizás acabamos de leer los dos primeros caracteres og
de la entrada en esos bordes y ahora estamos leyendo a y
.
El nuevo carácter se lee en el en el borde. Usamos el ? borde para verificar si este carácter es igual a r
. (Aquí hay un truco ingenioso: la hexagonía solo puede distinguir entre positivo y no positivo fácilmente, por lo que verificar la igualdad por sustracción es molesto y requiere al menos dos ramas. Pero todas las letras son menos que un factor de 2 entre sí, por lo que podemos comparar los valores tomando el módulo, que solo dará cero si son iguales).
Debido a que y
es diferente de r
, movemos el borde (sin marcar) a la izquierda de adentro y copiamos y
allí. Ahora nos movemos más alrededor del hexágono, copiando el personaje un borde más cada vez, hasta que tengamos y
el borde opuesto a in . Pero ahora ya hay un carácter en un [0] que no queremos sobrescribir. En cambio, "arrastramos" y
alrededor del siguiente hexágono y verificamos un 1 . Pero también hay un personaje allí, así que vamos a otro hexágono más lejos. Ahora un [2] sigue siendo cero, así que copiamos ely
en ello. El puntero de memoria ahora retrocede a lo largo de la cuerda hacia el anillo interno. Sabemos cuándo hemos llegado al comienzo de la cadena, porque los bordes (no marcados) entre a a [i] son todos cero, mientras que ? es positivo.
Probablemente sea una técnica útil para escribir código no trivial en Hexagony en general.