Ho pensato di sfruttare questa opportunità per sfoggiare una nuova funzione Retina: loop multi-stage. Ciò dovrebbe abbreviare considerevolmente molte attività (in particolare la sostituzione condizionale).
ii
-
+`(.)\1|0
(.)-|(\d)(\d)
-$1$3$2
12
i3
23
i1
31
i2
)`(\d)i
i$1
^\D*$
$&0
Retina è il mio linguaggio di programmazione basato su regex. Il codice sorgente può essere raggruppato in fasi: ogni fase è composta da due righe in cui la prima contiene la regex (e potenzialmente una certa configurazione) e la seconda riga è la stringa di sostituzione. Le fasi vengono quindi applicate a STDIN in ordine e il risultato finale viene stampato su STDOUT.
È possibile utilizzare quanto sopra direttamente come file di origine con l' -s
opzione della riga di comando. Tuttavia, non sto contando lo switch, perché puoi anche solo mettere ogni riga in un file separato (quindi perdi 15 byte per le nuove righe, ma aggiungi +15 per i file aggiuntivi).
Spiegazione
La novità di questa soluzione è )
la penultima tappa. Questo chiude un loop a più stadi. Non c'è corrispondenza (
, il che significa che il ciclo inizia implicitamente al primo stadio. Quindi, i primi 7 stadi vengono ripetuti fino a quando un passaggio completo attraverso tutti e 7 smette di cambiare il risultato. Queste 7 fasi eseguono semplicemente varie trasformazioni che riducono gradualmente il numero di matrici nella stringa e combinano le fasi. Una volta raggiunto il risultato finale, nessuno dei sette modelli corrisponde più e il ciclo termina. Successivamente, aggiungiamo uno 0 se non ci sono ancora cifre nel risultato (poiché le fasi precedenti semplicemente eliminano tutte le identità, incluso il risultato).
Ecco cosa fanno le singole fasi:
ii
-
Combina tutte le coppie di i
in -
per ridurre i caratteri di fase.
+`(.)\1|0
<empty>
Ora, se rimangono due caratteri identici consecutivi, sono una --
o due matrici identiche. In entrambi i casi, moltiplicandoli si ottiene l'identità. Ma non abbiamo bisogno di identità, quindi le rimuoviamo tutte e anche le identità esplicite 0
. Questa fase si ripete da sola +
fino a quando il risultato non smette di cambiare. Ciò garantisce che cose come la 123321
risoluzione completa, in modo che il passaggio successivo possa presumere che tutte le coppie di cifre siano distinte.
(.)-|(\d)(\d)
-$1$3$2
In realtà si tratta di due trasformazioni separate in una (per golfitude). Nota che se la prima alternativa corrisponde $2
e $3
sono vuoti e se la seconda corrisponde $1
è vuota. Quindi questo può essere scomposto in questi due passaggi:
(\d)(\d)
-$2$1
Questo scambia solo tutte le coppie di cifre e aggiunge un segno meno. Poiché abbiamo rimosso tutti 0
s e tutte le coppie identiche, questo corrisponde solo 12
, 23
, 31
, 21
, 32
, 13
. Questo passaggio può sembrare strano, ma mi permette di verificare solo la metà di questi casi in seguito, perché quelli che non riesco a elaborare verranno scambiati qui nella prossima iterazione.
L'altra parte della fase precedente era:
(.)-
-$1
Questo sposta gradualmente i -
segni completamente a sinistra (una posizione per iterazione). Lo faccio in modo tale che alla fine siano tutti vicini e risolti nel passaggio precedente.
12
i3
23
i1
31
i2
Queste tre fasi ora risolvono semplicemente le tre coppie di prodotti. Come ho detto sopra, questo prenderà solo la metà dei casi rilevanti, ma l'altra metà verrà curata nella successiva iterazione, dopo che il passaggio precedente ha scambiato tutte le coppie.
)`(\d)i
i$1
Questo è l'ultimo stadio del ciclo. È simile a quello che si sposta -
a sinistra, tranne che per i
. La differenza principale è che questo scambia i
solo con cifre. Se lo usassi (.)i
allora nei casi in cui ottengo uno -i
o i-
due verrebbero scambiati a tempo indeterminato e il programma non terminerebbe. Quindi questo li scambia solo a destra dei -
segni. Questo è sufficiente - finché tutto -
e i
appaiono insieme ad un certo punto, possono essere risolti correttamente.
^\D*$
$&0
Il passaggio finale (al di fuori del ciclo). Ricorda che abbiamo sempre eliminato tutte le identità, quindi se il risultato è in realtà l'identità (volte una fase), allora non avremo più la cifra richiesta nell'output, quindi la aggiungiamo di nuovo.
Ad esempio, qui ci sono tutte le forme intermedie di 0223202330203313021301011023230323
(saltare le fasi che non eseguono alcuna modifica):
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.