Pensei em usar essa oportunidade para exibir um novo recurso Retina: loops de vários estágios. Isso deve reduzir consideravelmente muitas tarefas (especialmente a substituição condicional).
ii
-
+`(.)\1|0
(.)-|(\d)(\d)
-$1$3$2
12
i3
23
i1
31
i2
)`(\d)i
i$1
^\D*$
$&0
Retina é minha própria linguagem de programação baseada em regex. O código-fonte pode ser agrupado em estágios: cada estágio consiste em duas linhas em que o primeiro contém a regex (e potencialmente alguma configuração) e a segunda linha é a sequência de substituição. As etapas são aplicadas ao STDIN em ordem e o resultado final é impresso em STDOUT.
Você pode usar o acima diretamente como um arquivo de origem com a -s
opção de linha de comando. No entanto, não estou contando a opção, porque você também pode colocar cada linha em um arquivo separado (então você perde 15 bytes para as novas linhas, mas adiciona +15 para os arquivos adicionais).
Explicação
A novidade desta solução é )
a penúltima etapa. Isso fecha um loop de vários estágios. Não há correspondência (
, o que significa que o loop inicia implicitamente no primeiro estágio. Portanto, os sete primeiros estágios são repetidos até que uma passagem completa pelos sete pare de alterar o resultado. Esses 7 estágios simplesmente realizam várias transformações que reduzem gradualmente o número de matrizes na cadeia e combinam fases. Quando alcançamos o resultado final, nenhum dos sete padrões corresponde mais e o loop termina. Depois, adicionamos um 0 se ainda não houver um dígito no resultado (como os estágios acima simplesmente eliminam todas as identidades, incluindo o resultado).
Aqui está o que as etapas individuais fazem:
ii
-
Combina todos os pares de i
em -
para reduzir os caracteres da fase.
+`(.)\1|0
<empty>
Agora, se houver dois caracteres idênticos consecutivos restantes, são uma --
ou duas matrizes idênticas. Nos dois casos, multiplicá-los fornece a identidade. Mas como não precisamos de identidades, removemos todas elas e as identidades explícitas 0
também. Esta etapa é repetida em si mesma +
até que o resultado pare de mudar. Isso garante que coisas como 123321
sejam resolvidas completamente, de forma que a próxima etapa possa assumir que todos os pares de dígitos são distintos.
(.)-|(\d)(\d)
-$1$3$2
Na verdade, são duas transformações separadas em uma (para golfitude). Observe que se a primeira alternativa corresponder $2
e $3
estiver vazia, e se a segunda corresponder $1
estiver vazia. Portanto, isso pode ser decomposto nessas duas etapas:
(\d)(\d)
-$2$1
Isso apenas troca todos os pares de dígitos e adiciona um sinal de menos. Desde que removeu todos os 0
s e todos os pares idênticos, isto só irá corresponder 12
, 23
, 31
, 21
, 32
, 13
. Essa etapa pode parecer estranha, mas me permite verificar apenas metade desses casos mais tarde, porque os que não puderem ser processados serão trocados aqui na próxima iteração.
A outra parte do estágio acima foi:
(.)-
-$1
Isso gradualmente move os -
sinais para a esquerda (uma posição por iteração). Faço isso de modo que, em última análise, todos estejam próximos um do outro e sejam resolvidos na etapa anterior.
12
i3
23
i1
31
i2
Agora, esses três estágios simplesmente resolvem os três pares de produtos. Como eu disse acima, isso capturará apenas metade dos casos relevantes, mas a outra metade será tratada na próxima iteração, após a etapa anterior ter trocado todos os pares.
)`(\d)i
i$1
Este é o último estágio do loop. É semelhante ao que se desloca -
para a esquerda, exceto i
. A principal diferença é que este troca i
apenas com dígitos. Se eu usasse (.)i
, nos casos em que eu recebesse um -i
ou i-
os dois, seriam trocados indefinidamente e o programa não seria encerrado. Portanto, isso apenas os troca à direita dos -
sinais. Isso é suficiente - desde que todos -
e i
apareçam juntos em algum momento, eles possam ser resolvidos corretamente.
^\D*$
$&0
A etapa final (fora do loop). Lembre-se de que sempre excluímos todas as identidades; portanto, se o resultado for realmente a identidade (vezes uma fase), não teremos mais o dígito necessário na saída; por isso, o adicionamos novamente.
Como exemplo, aqui estão todas as formas intermediárias de 0223202330203313021301011023230323
(pulando estágios que não executam nenhuma alteração):
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.