D,g,@~~,L2_|*;;*|_2L,@,g,D
D,ff,@^^,BG€gBF;;FBg€GB,@D1:?:
xx:?
aa:1
`bb
Bxx;;B
Waa*bb,`yy,$ff>xx,`aa,xx|yy,`bb,Byy,xx:yy
O;;O:,B,`,|,`,>$,`,*W`
Wypróbuj online!
Ciekawostka: na długo przed uruchomieniem wyjaśnienia było 272 bajty, teraz pokonuje Javę.
Wyjścia True
dla idealnie zbalansowanych ciągów znaków i False
nie tylko
Ku mojej wielkiej satysfakcji pokonuje nudną wersję palindromize o 2 bajty, aby zapobiec dwukrotnemu wydrukowaniu wyniku. Starałem się również mieć jak najmniej martwego kodu, ale wciąż jest kilka skomentowanych sekcji, a kod wychodzi z kodem błędu 1 , po wydrukowaniu poprawnej wartości.
NB : błąd z BF
poleceniami została ustalona podczas gdy ta odpowiedź była w rozwoju.
Jak to działa
Kod zaczyna się od zdefiniowania dwóch kluczowych funkcji, f f i sol. These two functions are used to calculate the next step in the process of removing pairs, and work entirely from ff i.e. only ff is called from the main program, never g. If we define the input string as S, ff(S) modifies S in the following way:
First, identical adjacent characters in S are grouped together. For an example of abbbaabacc, this yields the array [[a],[bbb],[aa],[b],[a],[cc]]. Over each of the sublists (i.e. the identical groups), we run the function g, and replace the sublists with the result of the function.
g starts by unpacking the group, splatting the characters onto the stack. It then pushes the number of characters on the stack and takes the absolute difference with 2 and that number. We'll call this difference x. Lets see how this transforms the respective inputs of [a], [ b b ] i [ c c c ]:
[ a ] ⇒ [ a , 1 ]
[ b b ] ⇒ [ b , b , 0 ]
[ c c c ] ⇒ [ c , c , c , 1 ]
Jak widzisz xwskazuje, ile kolejnych znaków chcemy zachować. W przypadku prostych par usuwamy je całkowicie (uzyskując 0 następnego znaku), w przypadku samotnych postaci pozostawiamy je nietknięte lub dajemy 1 z nich, a dla grup, w którychx>2, we want x−2 of the character. In order to generate x of the character, we repeat the character with *
, and the function naturally returns the top element of the stack: the repeated string.
After g(s) has been mapped over each group s, we splat the array to the stack to get each individual result with BF
. Finally, the ^
flag at the function definition (D,ff,@^^,
) tells the return function to concatenate the strings in the stack and return them as a single string. For pairs, which yielded the empty string from g, this essentially removes them, as the empty string concatenated with any string r results in r. Anything after the two ;;
is a comment, and is thus ignored.
Pierwsze dwa wiersze definiują dwie funkcje, f f i sol, ale nie wykonuj f fjeszcze Następnie pobieramy dane wejściowe i przechowujemy je w pierwszej z naszych 4 zmiennych. Te zmienne to:
- x x : Wstępne dane wejściowe i poprzedni wynik zastosowania f f
- y y : Aktualny wynik zastosowania f f
- aa : Warunek pętli
- b b : Czy y y jest prawdą
Jak widać, wszystkie zmienne i funkcje (oprócz sol) mają nazwy dwuliterowe, co pozwala dość szybko usunąć je z kodu źródłowego, zamiast komentarza ze znaczną ilością x y a b. sol nie robi tego z jednego głównego powodu:
Jeśli operator, taki jak €
, zostanie przejechany przez funkcję zdefiniowaną przez użytkownikaa b c, należy zawrzeć nazwę funkcji {...}
, aby operator mógł pobrać całą nazwę. Jeśli jednak nazwa jest pojedynczym znakiem, takim jaksol, {...}
można pominąć. W takim przypadku, jeśli nazwa funkcji tog g, kod dlaf f i sol musiałby zmienić na
D,gg,@~~,L2_|*;;*|_2L,@D (NB: -2 bytes)
D,ff,@^^,BG€{gg}BF;;FB}gg{€GB,@D?: (NB: +6 bytes)
który jest 4 bajty dłuższy.
Ważnym terminem, który należy teraz wprowadzić, jest zmienna aktywna . Wszystkie polecenia oprócz przypisania przypisują swoją nową wartość do zmiennej aktywnej, a jeśli aktywna jest zmienna aktywna, można ją pominąć w argumentach funkcji. Na przykład, jeśli aktywną zmienną jestx = 5, a następnie możemy ustawić x = 15 przez
x+10 ; Explicit argument
+10 ; Implicit argument, as x is active
Aktywna zmienna to xdomyślnie, ale można to zmienić za pomocą `
polecenia. Podczas zmiany aktywnej zmiennej należy pamiętać, że nowa aktywna zmienna nie musi wcześniej istnieć i jest automatycznie przypisywana jako 0.
Po zdefiniowaniu f f i sol, przypisujemy dane wejściowe do x xz xx:?
. Następnie musimy bardzo nieznacznie manipulować warunkami pętli. Po pierwsze, chcemy się upewnić, że wejdziemy w pętlę while, chyba żex xjest pusty. Dlatego przypisujemy prawdziwą wartośćaaz aa:1
najkrótszą taką wartością1. Następnie przypisujemy prawdziwośćx x do b b z dwiema liniami
`bb
Bxx
Który pierwszy robi b b aktywna zmienna, a następnie uruchamia komendę boolean x x. Odpowiednie wyborya a : = 1 i b b : = ¬¬ x x materia, jak pokażemy później.
Następnie wchodzimy do naszej pętli while:
Waa*bb,`yy,$ff>xx,`aa,xx|yy,`bb,Byy,xx:yy
Pętla while jest konstrukcją w Add ++: działa bezpośrednio na kodzie, a nie na zmiennych. Konstrukty pobierają szereg instrukcji kodu, oddzielonych za pomocą ,
których działają. Instrukcje while i if przyjmują również warunek bezpośrednio przed pierwszym, ,
który składa się z jednej poprawnej instrukcji, takiej jak polecenie infiksowe ze zmiennymi. Należy zauważyć: aktywnej zmiennej nie można pominąć w warunku.
Pętla while składa się z warunku aa*bb
. Oznacza to zapętlenie podczas gdy obaaa i b bsą prawdomówni. Najpierw tworzy treść koduy y aktywna zmienna w celu przechowywania wyniku f f (x). Odbywa się to za pomocą
`yy,$ff>xx
Następnie aktywujemy warunek pętli aa. Mamy dwa warunki do ciągłego zapętlania:
- 1) Nowa wartość nie jest równa starej wartości (pętla jest unikalna)
- 2) Nowa wartość nie jest pustym ciągiem
Jedną z największych wad Add ++ jest brak instrukcji złożonych, co wymaga posiadania drugiej zmiennej pętli. Przypisujemy dwie zmienne:
a a : = x x ≠ y y
b b : = ¬¬( y y )
Z kodem
`aa,xx|yy,`bb,Byy
Gdzie |
jest operatorem nierówności i B
konwertuje na wartość logiczną . Następnie aktualizujemyx x zmienna ma być y yzmienna z xx:yy
, w przygotowaniu do następnej pętli.
Ta pętla while ostatecznie redukuje dane wejściowe do jednego z dwóch stanów: pustego ciągu lub stałego ciągu, nawet gdy jest zastosowany f f. Kiedy tak się stanieaa lub b b skutkują False, wyłamując się z pętli.
Po przerwaniu pętli może ona zostać zerwana z jednego z dwóch powodów, jak wspomniano powyżej. Następnie wyprowadzamy wartośćaa. Jeśli pętla została przerwana z powodux = y, a następnie zarówno dane wyjściowe, jak i aasą fałszywe. Jeśli pętla została przerwana, ponieważy y był więc równy pustemu ciągowi znaków b b jest falsy i aa a wyniki są zgodne z prawdą.
We then reach our final statement:
O
Program może teraz znajdować się w jednym z trzech stanów, w których znajduje się aktywna zmienna b b:
- 1) Dane wejściowe były puste. W tym przypadku pętla nie uruchomiła się,a a =1 i b b = Fa l s e. Prawidłowe wyjście toF a l s e.
- 2) Wejście było idealnie zbalansowane. Jeśli tak, pętla biegnie,= T R U e i b b = F a l s e. Prawidłowe wyjście toF a l s e
- 3) Wejście nie było idealnie zbalansowane. Jeśli tak, pętla biegnie,a a = F a l s e i b b = T r u e. Prawidłowe wyjście toT R U e
Jak widzisz, b bjest równy oczekiwanemu wynikowi (aczkolwiek odwrócony od logicznej odpowiedzi), więc po prostu go wysyłamy. Ostatnie bajty, które pomagają nam pokonać Javę, pochodzą właśnie z tegob b jest aktywną zmienną, więc można ją pominąć w argumencie, pozostawiając nam wyjście T R U e lub F a l s e, w zależności od tego, czy sygnał wejściowy jest idealnie zbalansowany, czy nie.