Pensé en aprovechar esta oportunidad para mostrar una nueva función de Retina: bucles de varias etapas. Esto debería acortar considerablemente muchas tareas (especialmente el reemplazo condicional).
ii
-
+`(.)\1|0
(.)-|(\d)(\d)
-$1$3$2
12
i3
23
i1
31
i2
)`(\d)i
i$1
^\D*$
$&0
Retina es mi propio lenguaje de programación basado en expresiones regulares. El código fuente se puede agrupar en etapas: cada etapa consta de dos líneas donde la primera contiene la expresión regular (y potencialmente alguna configuración) y la segunda línea es la cadena de reemplazo. Las etapas se aplican a STDIN en orden y el resultado final se imprime a STDOUT.
Puede usar lo anterior directamente como un archivo fuente con el -s
interruptor de línea de comandos. Sin embargo, no estoy contando el cambio, porque también puede colocar cada línea en un archivo separado (luego pierde 15 bytes para las nuevas líneas, pero agrega +15 para los archivos adicionales).
Explicación
Lo nuevo de esta solución es )
la penúltima etapa. Esto cierra un ciclo de múltiples etapas. No hay coincidencia (
, lo que significa que el ciclo comienza implícitamente en la primera etapa. Por lo tanto, las primeras 7 etapas se repiten hasta que un pase completo a través de las 7 deja de cambiar el resultado. Estas 7 etapas simplemente realizan varias transformaciones que reducen gradualmente el número de matrices en la cadena y combinan fases. Una vez que alcanzamos el resultado final, ninguno de los siete patrones coincide más y el ciclo termina. Luego, agregamos un 0 si todavía no hay un dígito en el resultado (ya que las etapas anteriores simplemente eliminan todas las identidades, incluido el resultado).
Esto es lo que hacen las etapas individuales:
ii
-
Combina todos los pares de i
en -
para reducir los caracteres de fase.
+`(.)\1|0
<empty>
Ahora, si quedan dos caracteres idénticos consecutivos, es una --
o dos matrices idénticas. En cualquier caso, multiplicarlos da la identidad. Pero no necesitamos identidades, por lo que las eliminamos todas y también las identidades explícitas ( 0
s). Esta etapa se repite en sí misma +
hasta que el resultado deja de cambiar. Esto asegura que cosas como 123321
se resuelvan por completo, de modo que el siguiente paso pueda suponer que todos los pares de dígitos son distintos.
(.)-|(\d)(\d)
-$1$3$2
Esto es en realidad dos transformaciones separadas en una (para golfitude). Tenga en cuenta que si la primera alternativa coincide, $2
y $3
están vacías, y si la segunda coincide, $1
está vacía. Entonces esto se puede descomponer en estos dos pasos:
(\d)(\d)
-$2$1
Esto simplemente intercambia todos los pares de dígitos y agrega un signo menos. Desde que eliminó todas 0
s y todos los pares idénticos, esto sólo coincidirá 12
, 23
, 31
, 21
, 32
, 13
. Este paso puede parecer extraño, pero me permite verificar solo la mitad de estos casos más adelante, porque los que no puedo procesar se intercambiarán aquí en la próxima iteración.
La otra parte de la etapa anterior fue:
(.)-
-$1
Esto mueve gradualmente los -
signos hacia la izquierda (una posición por iteración). Hago esto de manera tal que, en última instancia, estén todos juntos y se resuelvan en el paso anterior.
12
i3
23
i1
31
i2
Estas tres etapas ahora simplemente resuelven los tres pares de productos. Como dije anteriormente, esto solo detectará la mitad de los casos relevantes, pero la otra mitad se resolverá en la próxima iteración, después de que el paso anterior intercambiara todos los pares.
)`(\d)i
i$1
Esta es la última etapa del ciclo. Es similar al que se desplaza -
hacia la izquierda, excepto i
. La principal diferencia es que este se intercambia i
solo con dígitos. Si lo usara (.)i
, en los casos en que obtenga uno -i
o i-
los dos se intercambiarían indefinidamente y el programa no terminaría. Entonces esto solo los cambia a la derecha de los -
signos. Esto es suficiente: siempre que todos -
y i
aparezcan juntos en algún momento, se pueden resolver correctamente.
^\D*$
$&0
El paso final (fuera del bucle). Recuerde que siempre eliminamos todas las identidades, por lo que si el resultado es en realidad la identidad (multiplicada por una fase), ya no tendremos el dígito requerido en la salida, así que lo volveremos a agregar.
Como ejemplo, aquí están todas las formas intermedias de 0223202330203313021301011023230323
(omitiendo etapas que no realizan ningún cambio):
0223202330203313021301011023230323
321321312 # Remove identities
-23-31-12-132 # Swap all pairs
-23-31-i3-132 # Resolve 12
-i1-31-i3-132 # Resolve 23
-i1-i2-i3-132 # Resolve 31
-i-1i-2i-3-312 # Move - to the left and swap pairs
-i-1i-2i-3-3i3 # Resolve 12
-i-i1-i2-3-i33 # Move i to the left
-i-i1-i2-3-i # Remove identities
--ii-1i-2-3i # Move - to the left
--ii-i1-2-i3 # Move i to the left
----i1-2-i3 # Resolve ii
i1-2-i3 # Remove identities
i-1-2i3 # Move - to the left
i-1-i23 # Move i to the left
-i-1i-32 # Move - to the left and swap pairs
-i-i1-32 # Move i to the left
--ii-1-23 # Move - to the left and swap pairs
--ii-1-i1 # Resolve 23
----1-i1 # Resolve ii
1-i1 # Remove identities
-1i1 # Move - to the left
-i11 # Move i to the left
-i # Remove identities. Now the loop can't change this any longer.
-i0 # Fix the result by adding in the 0.