JavaScript (ES7), 121 117 bajtów
x=>(a=b=0,[for(c of x)for(d of'1234')(e=c.charCodeAt()/26|0)==d?a^=1<<d:b^=(a>>d&1)<<d*4+e],f=y=>y&&y%2+f(y>>1))(b)/2
Łał. To było zabawne. Naszkicowałem pomysł na odpowiedź, kiedy to wyzwanie się pojawiło, ale miało ponad 150 bajtów i nie chciałem w to grać. Wczoraj natknąłem się na ten pomysł w zeszycie i zdecydowałem, że nie przestanę o nim myśleć, dopóki go w pełni nie zagram. Skończyło się na napisaniu dwóch zupełnie nowych algorytmów, z których pierwszy skończył kilka bajtów krócej po graniu w golfa około 25 bajtów z mnóstwem hackowania bitów.
Jak to działa
Najpierw musimy ustawić zmienne a
i b
do 0
. a
to 4-bitowa tablica binarna, w której aktualnie znajdują się pary nawiasów, oraz b
16-bitowa tablica binarna, której pary nawiasów są ze sobą połączone.
Następnie, pętla przez każdego znaku c
w x
, i każdego char d
w '0123'
. Najpierw określamy, jakiego rodzaju c
jest nawias e=c.charCodeAt()/26-1|0
. Kody dziesiętne dla każdego typu nawiasów są następujące:
() => 40,41
<> => 60,62
[] => 91,93
{} => 123,125
Dzieląc przez 26, odejmując 1 i podłogę, mapujemy je odpowiednio na 0, 1, 2 i 3.
Następnie sprawdzamy, czy liczba ta jest równa bieżącej wartości d
. Jeśli tak, to wchodzimy lub wychodzimy z d
nawiasów typu th, więc włączamy d
th za a
pomocą a^=1<<d
. Jeśli tak nie jest, ale są wewnątrz d
-tego wspornika, musimy odwrócić e
nieco th w d
XX sekcji 4-bitowej b
. Odbywa się to w następujący sposób:
b^=(a>>d&1)<<d*4+e
(a>>d&1)
Zwraca d
th th a
. Jeśli jesteśmy wewnątrz d
typu nawiasów, zwraca 1; w przeciwnym razie zwraca 0. Następnie przesuwamy to w lewo o d*4+e
bity, a XOR b
o wynik. Jeśli jesteśmy wewnątrz d
typu nawiasów klamrowych, to XOR jest d*4+e
tym kawałkiem b
; w przeciwnym razie nic nie robi.
Na końcu całego zapętlenia b
będzie zawierać liczbę 1 bitów równą dwukrotności pożądanej wartości zwrotnej. Ale nadal musimy dowiedzieć się, ile to jest bitów. Właśnie tutaj f
pojawia się podfunkcja :
f=y=>y&&y%2+f(y>>1)
Jeśli y
ma wartość 0, to po prostu zwraca 0. W przeciwnym razie bierze ostatni bit y
z y%2
, a następnie dodaje wynik y
ponownego uruchomienia funkcji za wyjątkiem bitu ostatniego . Na przykład:
f(y) => y && y%2 + f(y>>1)
f(0b1001101) => 1 + f(0b100110) = 4
f(0b100110) => 0 + f(0b10011) = 3
f(0b10011) => 1 + f(0b1001) = 3
f(0b1001) => 1 + f(0b100) = 2
f(0b100) => 0 + f(0b10) = 1
f(0b10) => 0 + f(0b1) = 1
f(0b1) => 1 + f(0b0) = 1
f(0b0) => 0 = 0
Przeglądamy b
tę funkcję i dzielimy wynik przez 2, i jest nasza odpowiedź.