<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
Po wprowadzeniu Nnastępuje ciąg oddzielony dowolnym znakiem nienumerycznym.
Wypróbuj online!
Zostało to napisane we współpracy ze Sp3000 (co oznacza, że nie mogłem sobie pozwolić na wymyślenie algorytmu, więc zaczął nad nim pracować, wymyślił rozwiązanie 118-bajtowe, ale nie przeszkadzało mu to w golfa, więc grałem w golfa. .. tak dla pracy zespołowej).
Wyjaśnienie
Zwykły podkład SP (jak zwykle nieznacznie zmodyfikowany):
- Labirynt to oparty na stosie język 2D z dwoma stosami, głównym i pomocniczym. Prawie wszystko dzieje się na głównym stosie, ale możesz przenieść wartości na inny, np. Aby je odwrócić lub zachować na później.
- Stosy są bez dna i wypełnione zerami, więc wyskakiwanie z pustego stosu nie jest błędem.
- Wykonanie rozpoczyna się od pierwszego ważnego znaku (tutaj w lewym górnym rogu). Na każdym skrzyżowaniu, gdzie istnieją dwie lub więcej możliwych ścieżek, które ma wziąć wskaźnik instrukcji (IP), sprawdzana jest góra stosu, aby określić, gdzie iść dalej. Negatyw to skręt w lewo, zero to przejście do przodu, a dodatnie to skręt w prawo. Chociaż miało to na celu to sprawić, że kod będzie wyglądał jak kręte, kręte przejścia, nic nie stoi na przeszkodzie, aby tworzyć „pokoje”, w których warunki sprawdzane są w każdej komórce. Mogą one dać dość nieprzewidziane zachowanie, ale świetnie nadają się do gry w golfa.
- Kod źródłowy (a zatem i układ labiryntu) można modyfikować w czasie wykonywania, za pomocą
<>^vktórego cyklicznie przesuwa się wiersz lub kolumna lub siatka.
" nie ma operacji.
No to ruszamy.
Kod zaczyna się od <, czyli sztuczki golfowej, której użyłem kilka razy, kiedy zaczynałem od długiego kawałka kodu liniowego. Przesuwa cyklicznie pierwszy rząd w lewo, podając adres IP , więc źródło wygląda następująco:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
Ale teraz IP nie może się nigdzie przenieść, więc wykonuje to <ponownie. Trwa to do momentu osiągnięcia tego stanu:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
W tym momencie adres IP może opuścić komórkę i rozpocząć wykonywanie drugiej linii, zaczynając od ?. Oto poniższy kod liniowy:
? # Read the first integer on STDIN, i.e. N.
:} # Duplicate it and move one copy over to the auxiliary stack.
, # Read the separator character.
,. # Read the first character of the input string and directly print it.
IP wchodzi teraz do tego pokoju 3x2, który jest właściwie dwiema ściśle ściśniętymi (nakładającymi się) 2x2 pętlami zgodnie z ruchem wskazówek zegara. Pierwsza pętla odczytuje i odrzuca N-1znaki ze STDIN.
; # Discard the top of the stack. On the first iteration, this is the
# separator we've already read. On subsequent iterations this will be
# one of the N-1 characters from the input string.
( # Decrement N. If this hits zero, we leave the loop, otherwise we continue.
, # Read the next character from STDIN to be discarded.
Teraz wchodzimy do drugiej pętli, która odczytuje resztę ciągu wejściowego. Możemy wykryć EOF, ponieważ w takim przypadku ,powróci -1, skręcając adres IP w lewo.
, # Read a character. Exit the loop if EOF.
( # Decrement it.
Ta redukcja nie jest w rzeczywistości przydatna, ale możemy ją później cofnąć za darmo, a tutaj pozwala nam nakładać się na dwie pętle.
Jeśli weźmiemy dane 5 ABCDEFGHIJKLMNOPwejściowe jako przykład, stos wygląda następująco:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' -1 | 5 ... ] Auxiliary
Zauważ, że faktycznie odpowiadają one wejściowym znakom FGHIJKLMNOP(ponieważ je zmniejszyliśmy) i że tak naprawdę nie chcemy wydrukować pierwszego z nich (tylko odrzuciliśmy N-1znaki, ale chcemy pominąćN ).
Teraz jest krótki bit liniowy, który przygotowuje stos do następnej pętli:
; # Discard the -1.
= # Swap the tops of the stacks, i.e. N with the last character.
# By putting the last character on the auxiliary stack, we ensure that
# it doesn't get discarded in the next loop.
} # Move N over to the auxiliary stack as well.
Stosy wyglądają teraz następująco:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' | 5 'O' ... ] Auxiliary
Wchodzimy w kolejną pętlę 2x2 zgodnie z ruchem wskazówek zegara. To odrzuca najlepsze Npostacie z głównego stosu:
; # Discard the top of the main stack.
{ # Pull N over from the auxiliary stack.
( # Decrement it. It it's 0 we leave the loop.
} # Push N back to the auxiliary stack.
Kiedy wychodzimy z pętli, =zamieniamy ją ponownie 0i ostatni znak ciągu wejściowego. Teraz stosy wyglądają tak:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'O' | ... ] Auxiliary
Chcemy wydrukować zawartość głównego stosu (oprócz dolnego elementu i wszystkich z przyrostem o 1), od lewej . Oznacza to, że musimy przenieść go na stos pomocniczy. Tak właśnie robi następna pętla 2x2 (zgodnie z ruchem wskazówek zegara):
{ # Pull an element over from the auxiliary stack. This is necessary so we
# have a 0 on top of the stack when entering the loop, to prevent the IP
# from turning right immediately.
} # Move the top of the main stack back to the auxiliary stack. If this was the
# bottom of the stack, exit the loop.
) # Increment the current character.
} # Move it over to the auxiliary stack.
Stosy teraz:
Main [ ... | 'F' 'G' 'H' 'I' 'J' 'P] ... ] Auxiliary
Pierwszy z nich (ten, którego nie chcemy drukować) przenosimy z powrotem do głównego stosu {. A teraz wchodzimy w końcową pętlę 2x2 ( przeciwnie do ruchu wskazówek zegara ), która wypisuje resztę:
{ # Pull another character over from the auxiliary stack. Exit the loop
# if that's the zero at the bottom of the stack.
. # Print the character.
Na koniec kończymy program za pomocą @.
'jak licząca postać? Na przykład''123321:?