Le nombre d'octets suppose un codage ISO 8859-1.
+%`\B
¶$`:
1
Essayez-le en ligne!
Solution alternative:
+1`\B
:$`:
1
Explication
Cela sera probablement plus facile à expliquer sur la base de mon ancienne version, moins golfée, puis en montrant comment je l'ai raccourcie. J'ai utilisé pour convertir le binaire en décimal comme ceci:
^
,
+`,(.)
$`$1,
1
La seule façon raisonnable de construire un nombre décimal dans Retina est de compter les choses (car Retina a quelques fonctionnalités qui lui permettent d'imprimer un nombre décimal représentant un montant). La seule approche possible est donc de convertir le binaire en unaire, puis de compter le nombre de chiffres unaires. La dernière ligne fait le comptage, donc les quatre premiers convertissent le binaire en unaire.
Comment fait-on cela? En général, pour convertir d'une liste de bits en un entier, nous initialisons le résultat en 0
puis parcourons les bits du plus grand au moins significatif, doublons la valeur que nous avons déjà et ajoutons le bit actuel. Par exemple, si le nombre binaire est 1011
, nous calculerions vraiment:
(((0 * 2 + 1) * 2 + 0) * 2 + 1) * 2 + 1 = 11
^ ^ ^ ^
Où j'ai marqué les bits individuels pour plus de clarté.
L'astuce pour le faire en unaire est a) que doubler signifie simplement répéter le nombre et b) puisque nous comptons les 1
s à la fin, nous n'avons même pas besoin de distinguer 0
s et 1
s dans le processus. Cela deviendra plus clair dans une seconde.
Ce que fait le programme, c'est qu'il ajoute d'abord une virgule au début comme marqueur de la quantité d'entrée que nous avons déjà traitée:
^
,
À gauche du marqueur, nous aurons la valeur que nous accumulons (qui est correctement initialisée à la représentation unaire de zéro), et à droite de la valeur sera le bit suivant à traiter. Maintenant, nous appliquons la substitution suivante dans une boucle:
,(.)
$`$1,
Il suffit de regarder ,(.)
et $1,
cela déplace le marqueur d'un bit vers la droite à chaque fois. Mais nous insérons également $`
, qui est tout ce qui se trouve devant le marqueur, c'est-à-dire la valeur actuelle, que nous doublons. Voici les étapes individuelles lors du traitement de l'entrée 1011
, où j'ai marqué le résultat de l'insertion $`
au-dessus de chaque ligne (il est vide pour la première étape):
,1011
1,011
_
110,11
___
1101101,1
_______
110110111011011,
Vous verrez que nous avons conservé et doublé le zéro avec tout le reste, mais comme nous les ignorons à la fin, peu importe la fréquence à laquelle nous les avons doublés, tant que le nombre de 1
s est correct. Si vous les comptez, il y a11
en a, exactement ce dont nous avons besoin.
Cela laisse donc la question de savoir comment jouer au golf à 12 octets. La partie la plus chère de la version 18 octets doit utiliser le marqueur. Le but est de s'en débarrasser. Nous voulons vraiment doubler le préfixe de chaque bit, donc une première idée pourrait être la suivante:
.
$`$&
Le problème est que ces substitutions se produisent simultanément, donc le premier bit n'est pas doublé pour chaque bit, mais il est copié une seule fois à chaque fois. Pour l'entrée, 1011
nous obtiendrions (marquant l'inséré $`
):
_ __ ___
1101011011
Nous devons toujours traiter l'entrée de manière récursive afin que le premier préfixe doublé soit à nouveau doublé par le second et ainsi de suite. Une idée est d'insérer des marqueurs partout et de les remplacer à plusieurs reprises par le préfixe:
\B
,
+%`,
¶$`
Après avoir remplacé chaque marqueur par le préfixe pour la première fois, nous devons nous rappeler où se trouvait le début de l'entrée.Nous insérons donc également les sauts de ligne et utilisons l' %
option pour nous assurer que le prochain $`
ne récupère que le saut de ligne le plus proche.
Cela fonctionne, mais c'est encore trop long (16 octets lors du comptage de 1
s à la fin). Et si on retournait les choses? Les endroits où nous voulons insérer des marqueurs sont identifiés par \B
(une position entre deux chiffres). Pourquoi ne pas simplement insérer des préfixes dans ces positions? Cela fonctionne presque, mais la différence est que dans la solution précédente, nous avons en fait supprimé un marqueur dans chaque substitution, et c'est important pour mettre fin au processus. Cependant, ce \B
ne sont pas des personnages mais seulement des positions, donc rien n'est supprimé. On peut cependant arrêter le\B
de la correspondance en insérant à la place un caractère non numérique à cet endroit. Cela transforme la frontière non mot en une frontière de mot, ce qui équivaut à supprimer le caractère marqueur plus tôt. Et c'est ce que fait la solution à 12 octets:
+%`\B
¶$`:
Juste pour être complet, voici les différentes étapes du traitement 1011
, avec une ligne vide après chaque étape:
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
Encore une fois, vous constaterez que le dernier résultat contient exactement 11 1
s.
Comme exercice pour le lecteur, pouvez-vous voir comment cela se généralise assez facilement à d'autres bases (pour quelques octets supplémentaires par incrément dans la base)?