C, 59 bajtów
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
Magiczne liczby, magiczne liczby wszędzie!
(Również C jest krótszy niż Python, JS, PHP i Ruby? Niespotykane!)
Jest to funkcja, która pobiera ciąg jako dane wejściowe i wyjściowe do STDOUT.
Przewodnik
Podstawowa struktura to:
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
Tutaj „rzeczy w środku” to wiązka kodu, po ,*s++której operator przecinka zwraca tylko wartość drugiego argumentu. Dlatego też przejdzie przez ciąg i ustawi *skażdy znak, w tym końcowy bajt NUL (ponieważ postfix ++zwraca poprzednią wartość) przed wyjściem.
Rzućmy okiem na resztę:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
Odrywając trójskładnikowe i zwarciowe ||, można to rozszerzyć do
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
Skąd pochodzą te magiczne liczby? Oto reprezentacje binarne wszystkich zaangażowanych postaci:
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
Najpierw musimy oddzielić spację i NUL od reszty postaci. Sposób działania tego algorytmu utrzymuje akumulator o numerze „bieżącym” i wypisuje go, gdy tylko dojdzie do spacji lub końca łańcucha (tj '\0'.). Zauważając to ' 'i '\0'jesteśmy jedynymi znakami, które nie mają ustawionego żadnego z dwóch najmniej znaczących bitów, możemy bitowo ORAZ znak za pomocą, 0b11aby uzyskać zero, jeśli znak jest spacją lub NUL i w przeciwnym razie jest niezerowy.
Kopiąc głębiej, w pierwszej gałęzi „jeśli” mamy teraz jedną z postaci FBizu. Zdecydowałem się tylko zaktualizować akumulator na Fsi Bs, więc potrzebowałem jakiegoś sposobu, aby odfiltrować izus. Dogodnie Fi Boba mają tylko drugi, trzeci lub siódmy najmniej znaczący zestaw bitów, a wszystkie pozostałe liczby mają co najmniej jeden inny zestaw bitów. W rzeczywistości wszystkie mają pierwszy lub czwarty najmniej znaczący bit. Stąd możemy bitowo ORAZ z 0b00001001, która wynosi 9, co da 0 dla Fi, w Bprzeciwnym razie, zero.
Po ustaleniu, że mamy Flub B, możemy zmapować je odpowiednio na 0i 1, biorąc ich moduł 5, ponieważ Fjest 70i Bjest 66. Następnie fragment kodu
i += i + *s % 5;
to po prostu golfowy sposób na powiedzenie
i = (i * 2) + (*s % 5);
co można również wyrazić jako
i = (i << 1) | (*s % 5);
który wstawia nowy bit w co najmniej znaczącej pozycji i przesuwa wszystko inne o 1.
"Ale poczekaj!" możesz protestować. „Po wydrukowaniu i, kiedy w ogóle resetuje się do 0?” Cóż, putcharrzuca swój argument na an unsigned char, który akurat ma 8 bitów. Oznacza to, że wszystko po 8. najmniej znaczącym bicie (tj. Śmieci z poprzednich iteracji) jest wyrzucane i nie musimy się tym martwić.
Dzięki @ETHproductions za sugerowanie zastąpić 57z 9, oszczędzając bajt!