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 ai bdo 0. ato 4-bitowa tablica binarna, w której aktualnie znajdują się pary nawiasów, oraz b16-bitowa tablica binarna, której pary nawiasów są ze sobą połączone.
Następnie, pętla przez każdego znaku cw x, i każdego char dw '0123'. Najpierw określamy, jakiego rodzaju cjest 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 dnawiasów typu th, więc włączamy dth za apomocą a^=1<<d. Jeśli tak nie jest, ale są wewnątrz d-tego wspornika, musimy odwrócić enieco th w dXX sekcji 4-bitowej b. Odbywa się to w następujący sposób:
b^=(a>>d&1)<<d*4+e
(a>>d&1)Zwraca dth th a. Jeśli jesteśmy wewnątrz dtypu nawiasów, zwraca 1; w przeciwnym razie zwraca 0. Następnie przesuwamy to w lewo o d*4+ebity, a XOR bo wynik. Jeśli jesteśmy wewnątrz dtypu nawiasów klamrowych, to XOR jest d*4+etym kawałkiem b; w przeciwnym razie nic nie robi.
Na końcu całego zapętlenia bbę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 fpojawia się podfunkcja :
f=y=>y&&y%2+f(y>>1)
Jeśli yma wartość 0, to po prostu zwraca 0. W przeciwnym razie bierze ostatni bit yz y%2, a następnie dodaje wynik yponownego 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 btę funkcję i dzielimy wynik przez 2, i jest nasza odpowiedź.