C 59 Bytes
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
Magische Zahlen, magische Zahlen überall!
(Auch C kürzer als Python, JS, PHP und Ruby? Unbekannt!)
Dies ist eine Funktion, die eine Zeichenfolge als Eingabe und Ausgabe für STDOUT verwendet.
Komplettlösung
Die Grundstruktur ist:
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
Hier ist "stuff inside" eine Reihe von Code, gefolgt von einem ,*s++
Kommaoperator, der nur den Wert seines zweiten Arguments zurückgibt. Daher durchläuft dies die Zeichenfolge und setzt sie *s
auf jedes Zeichen, einschließlich des nachfolgenden NUL-Bytes (da postfix ++
den vorherigen Wert zurückgibt), bevor es beendet wird.
Werfen wir einen Blick auf den Rest:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
Das Abschälen des Ternär- und Kurzschlusses ||
kann erweitert werden
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
Woher kommen diese magischen Zahlen? Hier sind die binären Darstellungen aller beteiligten Zeichen:
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
Zuerst müssen wir Leerzeichen und NUL vom Rest der Zeichen trennen. So wie dieser Algorithmus funktioniert, speichert er einen Akkumulator der "aktuellen" Zahl und gibt ihn immer dann aus, wenn er ein Leerzeichen oder das Ende der Zeichenfolge erreicht (dh '\0'
). Wenn wir das bemerken ' '
und '\0'
die einzigen Zeichen sind, bei denen keines der beiden niedrigstwertigen Bits gesetzt ist, können wir das Zeichen bitweise UND mit 0b11
Null verknüpfen, wenn das Zeichen ein Leerzeichen oder NUL ist und ansonsten ungleich Null.
Wenn wir tiefer graben, haben wir im ersten "Wenn" -Zweig jetzt einen Charakter, von dem einer ist FBizu
. Ich entschied mich nur, den Akku auf F
s und B
s zu aktualisieren , also brauchte ich eine Möglichkeit, die izu
s herauszufiltern . Praktischerweise F
und B
beide haben nur das zweite, dritte oder siebtniedrigste gesetzte Bit, und alle anderen Zahlen haben mindestens ein anderes gesetztes Bit. Tatsächlich haben sie alle entweder das erste oder das viertniedrigstwertige Bit. Daher können wir bitweise UND mit 0b00001001
, was 9 ist, was andernfalls 0 für F
und B
und ungleich Null ergibt .
Nachdem wir festgestellt haben , dass wir ein F
oder B
können wir sie kartieren 0
und die 1
jeweils durch ihre Modul 5 zu nehmen, weil F
ist 70
und B
ist 66
. Dann das Snippet
i += i + *s % 5;
ist nur eine golferische Art zu sagen
i = (i * 2) + (*s % 5);
was auch ausgedrückt werden kann als
i = (i << 1) | (*s % 5);
Dadurch wird das neue Bit an der niedrigstwertigen Position eingefügt und alles andere um 1 verschoben.
"Aber warte!" du könntest protestieren. " i
Wann wird der Wert nach dem Drucken wieder auf 0 zurückgesetzt?" Nun, putchar
wirft sein Argument auf ein unsigned char
, das gerade mal 8 Bit groß ist. Das bedeutet, dass alles, was nach dem 8. Bit mit der geringsten Signifikanz liegt (dh der Müll aus früheren Iterationen), weggeworfen wird, und wir müssen uns keine Sorgen machen.
Dank @ETHproductions für das Vorschlagen ersetzen 57
mit 9
, Speichern eines Byte!