Pomyślałem, że wykorzystam tę okazję, aby pochwalić się nową funkcją Retina: pętle wieloetapowe. Powinno to znacznie skrócić wiele zadań (zwłaszcza zastępowanie warunkowe).
ii
-
+`(.)\1|0
(.)-|(\d)(\d)
-$1$3$2
12
i3
23
i1
31
i2
)`(\d)i
i$1
^\D*$
$&0
Retina jest moim własnym językiem programowania opartym na wyrażeniach regularnych. Kod źródłowy można pogrupować w etapy: każdy etap składa się z dwóch wierszy, w których pierwszy zawiera wyrażenie regularne (i potencjalnie pewną konfigurację), a drugi wiersz to ciąg zastępujący. Etapy są następnie nakładane na STDIN w kolejności, a wynik końcowy jest drukowany na STDOUT.
Możesz użyć powyższego bezpośrednio jako pliku źródłowego za pomocą -s
przełącznika wiersza poleceń. Jednak nie liczę przełącznika, ponieważ możesz również po prostu umieścić każdą linię w osobnym pliku (wtedy tracisz 15 bajtów dla nowych linii, ale dodajesz +15 dla dodatkowych plików).
Wyjaśnienie
Nowością w tym rozwiązaniu jest )
etap przedostatni. To zamyka wieloetapową pętlę. Brak dopasowania (
, co oznacza, że pętla domyślnie rozpoczyna się na pierwszym etapie. Dlatego pierwsze 7 etapów powtarza się, aż pełne przejście przez wszystkie 7 z nich przestanie zmieniać wynik. Te 7 etapów po prostu wykonuje różne transformacje, które stopniowo zmniejszają liczbę matryc w łańcuchu i łączą fazy. Po osiągnięciu ostatecznego wyniku żaden z siedmiu wzorów już się nie zgadza i pętla się kończy. Następnie dodajemy 0, jeśli w wyniku nie ma jeszcze cyfry (ponieważ powyższe etapy po prostu usuwają wszystkie tożsamości, w tym wynik).
Oto, co robią poszczególne etapy:
ii
-
Łączy wszystkie pary i
w, -
aby zmniejszyć znaki fazy.
+`(.)\1|0
<empty>
Teraz, jeśli pozostały dwa kolejne identyczne znaki, jest to jedna --
lub dwie identyczne macierze. W obu przypadkach pomnożenie ich daje tożsamość. Ale nie potrzebujemy tożsamości, więc po prostu usuwamy je wszystkie, a także tożsamości jawne 0
. Ten etap powtarza się sam z, +
aż wynik przestanie się zmieniać. Zapewnia to 123321
całkowite rozwiązanie takich problemów , że w następnym kroku można założyć, że wszystkie pary cyfr są różne.
(.)-|(\d)(\d)
-$1$3$2
To właściwie dwie osobne transformacje w jednym (dla golfitude). Zauważ, że jeśli pierwsza alternatywa pasuje $2
i $3
są puste, a jeśli druga pasuje, $1
jest pusta. Można to rozłożyć na następujące dwa kroki:
(\d)(\d)
-$2$1
To po prostu zamienia wszystkie pary cyfr i dodaje znak minus. Ponieważ usunęliśmy wszystkie 0
s i wszystkie identyczne pary, to będzie tylko dopasować 12
, 23
, 31
, 21
, 32
, 13
. Ten krok może wydawać się dziwny, ale pozwala mi później sprawdzić tylko połowę tych przypadków, ponieważ te, których nie mogę przetworzyć, zostaną zamienione tutaj w następnej iteracji.
Drugą częścią powyższego etapu było:
(.)-
-$1
Powoduje to stopniowe przesuwanie -
znaków do końca w lewo (jedna pozycja na iterację). Robię to tak, aby ostatecznie wszyscy byli obok siebie i zostali rozwiązani na wcześniejszym etapie.
12
i3
23
i1
31
i2
Te trzy etapy rozwiązują teraz po prostu trzy pary produktów. Jak powiedziałem powyżej, będzie to obejmować tylko połowę odpowiednich przypadków, ale druga połowa zostanie załatwiona w następnej iteracji, po tym, jak poprzedni krok zamienił wszystkie pary.
)`(\d)i
i$1
To ostatni etap pętli. Jest podobny do tego, który przesuwa -
się w lewo, z wyjątkiem i
. Główną różnicą jest to, że zamienia się i
tylko cyframi. Gdybym używał, (.)i
to w przypadkach, w których dostaję jeden -i
lub i-
dwa, zostałyby zamienione na czas nieokreślony, a program nie zakończyłby się. To zamienia je tylko na prawo od -
znaków. Jest to wystarczające - tak długo, jak wszyscy -
i i
pojawiają się razem w pewnym momencie, mogą zostać rozwiązane poprawnie.
^\D*$
$&0
Ostatni krok (poza pętlą). Pamiętaj, że zawsze usuwaliśmy wszystkie tożsamości, więc jeśli wynikiem jest tożsamość (razy faza), to nie będziemy już mieć wymaganej cyfry na wyjściu, więc dodajemy ją z powrotem.
Na przykład tutaj są wszystkie pośrednie formy 0223202330203313021301011023230323
(pomijanie etapów, które nie powodują żadnych zmian):
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.