C, 59 bytes
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
Números mágicos, números mágicos em todos os lugares!
(Além disso, C menor que Python, JS, PHP e Ruby? Inédito!)
Esta é uma função que recebe uma string como entrada e sai para STDOUT.
Passo a passo
A estrutura básica é:
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
Aqui, o "material interno" é um monte de código seguido por ,*s++, em que o operador de vírgula retorna apenas o valor do seu segundo argumento. Portanto, isso percorrerá a cadeia e definirá *stodos os caracteres, incluindo o byte NUL à direita (já que o postfix ++retorna o valor anterior), antes de sair.
Vamos dar uma olhada no resto:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
Retirando o circuito ternário e curto-circuito ||, isso pode ser expandido para
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
De onde vêm esses números mágicos? Aqui estão as representações binárias de todos os personagens envolvidos:
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
Primeiro, precisamos separar espaço e NUL do resto dos personagens. Da maneira como esse algoritmo funciona, ele mantém um acumulador do número "atual" e o imprime sempre que atinge um espaço ou o final da string (ou seja '\0'). Ao perceber que ' 'e '\0'são os únicos caracteres que não possuem nenhum dos dois bits menos significativos definidos, podemos AND bit a bit e 0b11obter o zero se o caractere for espaço ou NUL e diferente de zero.
Indo mais fundo, no primeiro ramo "se", agora temos um personagem que é um deles FBizu. Eu escolhi apenas atualizar o acumulador em Fs e Bs, então eu precisava de uma maneira de filtrar os izus. Convenientemente, Fe Bambos têm apenas o segundo, terceiro ou sétimo bits menos significativos definidos, e todos os outros números têm pelo menos um outro conjunto de bits. De fato, todos eles têm o primeiro ou o quarto bit menos significativo. Assim, podemos bit a bit E com 0b00001001, o qual é 9, o que vai originar 0 para Fe Be diferente de zero em contrário.
Depois de determinarmos que temos um Fou B, podemos mapeá-los para 0e 1respectivamente, tomando seu módulo 5, porque Fé 70e Bé 66. Então o trecho
i += i + *s % 5;
é apenas uma maneira de dizer golfe
i = (i * 2) + (*s % 5);
que também pode ser expresso como
i = (i << 1) | (*s % 5);
que insere o novo bit na posição menos significativa e muda todo o resto em 1.
"Mas espere!" você pode protestar. "Depois de imprimir i, quando é que ele é redefinido para 0?" Bem, putcharlança seu argumento para an unsigned char, que por acaso tem 8 bits de tamanho. Isso significa que tudo que passou do oitavo bit menos significativo (ou seja, o lixo das iterações anteriores) é jogado fora, e não precisamos nos preocupar com isso.
Agradecemos a @ETHproductions por sugerir a substituição 57por 9, salvando um byte!