Die Anzahl der Bytes setzt die Kodierung nach ISO 8859-1 voraus.
+%`\B
¶$`:
1
Probieren Sie es online!
Alternative Lösung:
+1`\B
:$`:
1
Erläuterung
Dies wird wahrscheinlich einfacher zu erklären sein, basierend auf meiner alten, weniger golfenen Version, und dann zu zeigen, wie ich es verkürzt habe. Früher habe ich Binär in Dezimal konvertiert:
^
,
+`,(.)
$`$1,
1
Der einzig sinnvolle Weg, eine Dezimalzahl in Retina zu erstellen, ist das Zählen von Dingen (da Retina über einige Funktionen verfügt, mit denen eine Dezimalzahl ausgegeben werden kann, die einen Betrag darstellt). Der einzig mögliche Ansatz besteht also darin, die Binärzahl in eine unäre Zahl umzuwandeln und dann die Anzahl der unären Stellen zu zählen. Die letzte Zeile zählt, also wandeln die ersten vier Binär in Unär um.
Wie machen wir das? Um von einer Liste von Bits in eine Ganzzahl zu konvertieren, initialisieren wir das Ergebnis auf 0
und gehen dann die Bits von der höchsten bis zur niedrigsten Wertigkeit durch, verdoppeln den bereits vorhandenen Wert und addieren das aktuelle Bit. Wenn zum Beispiel die Binärzahl ist 1011
, würden wir wirklich berechnen:
(((0 * 2 + 1) * 2 + 0) * 2 + 1) * 2 + 1 = 11
^ ^ ^ ^
Wo ich die einzelnen Bits der Übersichtlichkeit halber markiert habe.
Der Trick dabei ist a) dass das Verdoppeln einfach das Wiederholen der Zahl bedeutet und b) da wir das 1
s am Ende zählen, brauchen wir nicht einmal zwischen 0
s und 1
s zu unterscheiden . Dies wird in einer Sekunde klarer.
Was das Programm macht, ist, dass es zuerst ein Komma an den Anfang fügt, um zu markieren, wie viel von der Eingabe wir bereits verarbeitet haben:
^
,
Links vom Marker wird der Wert angezeigt, den wir akkumulieren (der korrekt auf die unäre Darstellung von Null initialisiert ist), und rechts vom Wert wird das nächste zu verarbeitende Bit angezeigt. Jetzt wenden wir die folgende Substitution in einer Schleife an:
,(.)
$`$1,
Wenn Sie nur auf ,(.)
und schauen $1,
, wird der Marker jedes Mal ein Stück nach rechts verschoben. Wir fügen aber auch ein $`
, was alles vor dem Marker ist, dh den aktuellen Wert, den wir verdoppeln. Hier sind die einzelnen Schritte bei der Verarbeitung von Eingaben 1011
, bei denen ich das Ergebnis des Einfügens $`
über jeder Zeile markiert habe (für den ersten Schritt ist es leer):
,1011
1,011
_
110,11
___
1101101,1
_______
110110111011011,
Sie werden sehen, dass wir die Null beibehalten und zusammen mit allem anderen verdoppelt haben, aber da wir sie am Ende ignorieren, spielt es keine Rolle, wie oft wir sie verdoppelt haben, solange die Anzahl der 1
s beträgt richtig. Wenn Sie sie zählen, gibt es 11
von ihnen genau das, was wir brauchen.
Damit bleibt die Frage, wie dies auf 12 Bytes reduziert werden kann. Der teuerste Teil der 18-Byte-Version ist die Verwendung des Markers. Das Ziel ist es, das loszuwerden. Wir wollen wirklich das Präfix jedes Bits verdoppeln, daher könnte eine erste Idee sein:
.
$`$&
Das Problem ist, dass diese Ersetzungen gleichzeitig stattfinden, sodass das erste Bit nicht für jedes Bit verdoppelt wird , sondern jedes Mal nur einmal kopiert wird. Für die Eingabe würden 1011
wir erhalten (Markierung der eingefügten $`
):
_ __ ___
1101011011
Wir müssen die Eingabe immer noch rekursiv verarbeiten, sodass das verdoppelte erste Präfix erneut durch das zweite Präfix verdoppelt wird und so weiter. Eine Idee ist, Marker überall einzufügen und sie wiederholt durch das Präfix zu ersetzen:
\B
,
+%`,
¶$`
Nachdem wir zum ersten Mal jeden Marker durch das Präfix ersetzt haben, müssen wir uns merken, wo der Anfang der Eingabe war, damit wir auch Zeilenvorschübe einfügen und die %
Option verwenden, um sicherzustellen, dass der nächste $`
nur die Dinge aufnimmt, die dem nächsten Zeilenvorschub am nächsten sind.
Dies funktioniert, ist aber immer noch zu lang (16 Bytes beim Zählen von 1
s am Ende). Wie wäre es, wenn wir die Dinge umdrehen? Die Stellen, an denen wir Marker einfügen möchten, sind durch \B
(eine Position zwischen zwei Ziffern) gekennzeichnet. Warum fügen wir nicht einfach Präfixe in diese Positionen ein? Das funktioniert fast, aber der Unterschied besteht darin, dass wir in der vorherigen Lösung tatsächlich einen Marker in jeder Ersetzung entfernt haben. Dies ist wichtig, damit der Prozess beendet wird. Es \B
sind jedoch nicht die Charaktere, sondern nur Positionen, sodass nichts entfernt wird. Wir können das aber aufhalten\B
durch stattdessen Einfügen eines nicht-stelligen Zeichens an dieser Stelle. Das verwandelt die Nicht-Wortgrenze in eine Wortgrenze, was dem Entfernen des Markierungszeichens früher entspricht. Und genau das leistet die 12-Byte-Lösung:
+%`\B
¶$`:
Der Vollständigkeit halber sind hier die einzelnen Verarbeitungsschritte 1011
mit einer leeren Zeile nach jedem Schritt:
1
1:0
10:1
101:1
1
1:0
1
1:0:1
1
1:0
10:1:1
1
1:0
1
1:0:1
1
1:0
1
1:0:1:1
Auch hier werden Sie feststellen, dass das letzte Ergebnis genau 11 1
s enthält .
Können Sie als Übung für den Leser sehen, wie sich dies auf andere Basen verallgemeinern lässt (für ein paar zusätzliche Bytes pro Inkrement in der Basis)?