JavaScript (ES7), 121 117 bytes
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
Uau. Foi divertido. Esbocei uma ideia de resposta quando esse desafio foi lançado, mas ele tinha mais de 150 bytes e não queria me esforçar para jogá-lo. Encontrei essa idéia no meu notebook ontem e decidi que não iria parar de pensar nela até que eu tivesse jogado o golfe completamente. Acabei escrevendo dois algoritmos inteiramente novos, o primeiro dos quais acabou vários bytes mais curto depois de jogar cerca de 25 bytes com toneladas de hackers de bits.
Como funciona
Primeiro, definimos variáveis a
e b
como 0
. a
é uma matriz binária de 4 bits cujos pares de colchetes estamos atualmente no interior e b
é uma matriz binária de 16 bits cujos pares de colchetes estão vinculados.
Em seguida, vamos percorrer cada personagem c
em x
, e cada caractere d
em '0123'
. Primeiro, determinar que tipo de suporte c
é com e=c.charCodeAt()/26-1|0
. Os códigos de caracteres decimais de cada tipo de colchete são os seguintes:
() => 40,41
<> => 60,62
[] => 91,93
{} => 123,125
Dividindo por 26, subtraindo 1 e revestimento, nós os mapeamos para 0, 1, 2 e 3, respectivamente.
Em seguida, verificamos se esse número é igual ao valor atual de d
. Se for, estamos entrando ou saindo do d
tipo de parêntese, então trocamos o d
th a
com a^=1<<d
. Se não é, mas nós estão dentro do d
suporte tipo th, precisamos virar o e
th pouco na d
seção de 4 bits th b
. Isso é feito da seguinte maneira:
b^=(a>>d&1)<<d*4+e
(a>>d&1)
Retorna o d
th bit a
. Se estivermos dentro do d
tipo de colchete, isso retornará 1; caso contrário, ele retornará 0. Em seguida, mudamos isso para a esquerda por d*4+e
bits e XOR b
pelo resultado. Se estivermos dentro do d
tipo de colchete, este XOR será o d*4+e
th bit b
; caso contrário, não faz nada.
No final de todo o loop, b
conterá um número de 1 bits igual ao dobro do valor de retorno desejado. Mas ainda precisamos descobrir quantos bits são esses. É aí que f
entra a sub-função :
f=y=>y&&y%2+f(y>>1)
Se y
for 0, isso simplesmente retorna 0. Caso contrário, ele leva o último bit de y
com y%2
e adiciona o resultado da execução de todos, exceto o último bit, y
através da função novamente. Por exemplo:
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
Executamos b
essa função e dividimos o resultado por 2, e aqui está a nossa resposta.