BrainF ** k, 396 391 octets
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
Je n'ai pas pu résister à la tentation de faire celle-ci. Au moins, le triangle est pointu vers le bas.
L'entrée se présente sous la forme d'une chaîne de caractères numériques suivie d'une seule nouvelle ligne.
La sortie contiendra un seul espace de fin sur chaque ligne.
Exemples:
$ bf sd.bf
010
0 1 0
1 1
2
$ bf sd.bf
123456
1 2 3 4 5 6
3 5 7 9 1
8 2 6 0
0 8 6
8 4
2
$ bf sd.bf
9245322
9 2 4 5 3 2 2
1 6 9 8 5 4
7 5 7 3 9
2 2 0 2
4 2 2
6 4
0
Explication
Comme il est assez difficile d'expliquer le code d'un point de vue fonctionnel, nous pouvons plutôt le regarder du point de vue de l'état de la bande à différents moments. L'idée centrale ici est que le triangle que nous générons est initialisé comme un tableau compact (pour BF, de toute façon) qui diminue de taille de 1 à chaque itération d'une boucle. Une autre pensée importante est que nous utilisons 255
pour indiquer un "espace réservé" que nous pouvons rechercher sur la bande.
Initialisation
C'est l'étape la plus simple. Au début du programme, nous exécutons ce qui suit:
>+>>++++[-<++++++++>]->
Cela force la bande dans l'état suivant (où >N<
indique l'emplacement du pointeur sur la bande)
[ 0 1 32 255 >0< 0 0 ...]
Le premier numéro ici est un emplacement "tampon". Nous n'allons pas l'utiliser à long terme, mais il est utile de simplifier les petites opérations et de copier les données.
Le deuxième nombre est le nombre d'espaces que nous afficherons au début de chaque ligne, en commençant après la première ligne. La première ligne n'aura pas d'espaces de tête.
Le troisième nombre est le caractère d'espace que nous générons.
Le quatrième nombre est un espace réservé 255, afin que nous puissions revenir à cette position relativement facilement.
Contribution
De cette position, nous lirons tous les caractères. Au terme de cette étape, nous espérons être dans la situation suivante:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
Où a b c d e f ...
indique la chaîne de caractères numériques qui a été entrée (pas la nouvelle ligne).
Nous accomplissons cela avec les éléments suivants:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
Il y a quelques nuances à cela. Tout d'abord, nous afficherons chaque caractère au fur et à mesure que nous les obtiendrons, puis afficherons un espace après. Deuxièmement, nous ne voulons pas copier la valeur ASCII sur la bande, nous voulons copier le chiffre numérique réel. Troisièmement, nous voulons arrêter lorsque nous atteignons une nouvelle ligne et nous laisser à la bonne place à ce moment-là.
Disons que notre contribution est 6723
. Ensuite, à la lecture du premier 6
, notre bande ressemble à ceci:
[ 0 1 32 255 >54< 0 0 ...]
Nous vérifions que cette valeur n'est pas égale à 10
(une nouvelle ligne ASCII) avec ,----------[++++++++++
. Nous imprimons ensuite la valeur et continuons en soustrayant simultanément 48 de la valeur d'entrée et en ajoutant 32 à la valeur à côté ( >>++++++++[-<++++<------>>]<
), nous laissant ici:
[ 0 1 32 255 6 >32< 0 ...]
Remarquez comment tout au long de ce processus, nous pouvons supposer que tous les chiffres à droite de notre entrée sont 0 - cela signifie que nous ne risquons pas de ruiner un état précédent si nous utilisons des valeurs à droite pour calculer 6 * 8
et 4 * 8
.
Maintenant, nous sortons le caractère d'espace que nous venons de générer et prenons une nouvelle entrée, supprimant l'espace que nous avons calculé là-bas. Finalement, l'entrée sera terminée par une nouvelle ligne et la boucle se terminera, laissant un 255
où la nouvelle ligne aurait été ( ,----------]-
). Il s'agit du deuxième caractère d'espace réservé que nous utiliserons pour parcourir la bande. À ce stade de notre scénario, notre bande est exactement la suivante:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
Calcul
La façon dont cela fonctionne est que la liste des chiffres entre nos 255
espaces réservés va se réduire d'une unité à chaque itération de la boucle. Quand il ne reste plus qu'un chiffre, nous avons terminé et nous devons nous arrêter immédiatement (notez qu'à ce stade, chaque chiffre de cette liste a déjà été sorti, nous n'avons donc pas à nous soucier de le sortir à nouveau).
Nous utilisons maintenant cette astuce pour naviguer vers le premier 255
espace réservé: <+[-<+]-
. Cela recherche efficacement une bande sur la gauche pour 255
ne rien changer entre les deux. Maintenant que nous avons déplacé le pointeur, nous pouvons vérifier notre condition de sortie: s'il n'y a qu'un seul chiffre dans la liste, alors la cellule deux espaces à droite tiendra 255
. Ainsi, nous vérifions cela et commençons une boucle:>>+[-<<
La première étape de notre boucle consiste à sortir une nouvelle ligne. Nous passons donc à la première cellule (notre cellule tampon), y ajoutons 10 et sortons. L'étape suivante consiste à sortir tous les premiers caractères de l'espace. Après leur sortie, nous incrémentons notre comptage pour le nombre d'espaces de tête. Ces étapes sont accomplies comme suit:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
Ce qui nous laisse dans cet état:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
Notre prochaine étape consiste à copier la première valeur de la liste, au-delà du deuxième espace réservé 255
:
[[->+]->>+<<<+[-<+]->]
Nous le faisons essentiellement en faisant des allers-retours entre nos espaces réservés 255
, nous laissant ici:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
Nous commençons maintenant une boucle, itérant dans le reste de la liste, s'arrêtant lorsque nous frappons 255
:>+[-<
À ce stade, le chiffre à notre gauche immédiate est toujours 0. Donc, parce que nous les aimons, nous y ajoutons un espace réservé 255
afin de pouvoir revenir à notre place dans la liste. L'étape suivante consiste à déplacer la deuxième place de la liste vers des emplacements autour desquels nous avons déplacé la première place, après le deuxième espace réservé 255
. Ces étapes sont accomplies comme suit:
->
[[->+]->+>>+<<<<+[-<+]->]
Nous laissant ici: [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
Maintenant, les deux 6
et 7
ont été déplacés vers un emplacement où le calcul peut avoir lieu. Nous avons besoin de deux copies du 7
car le prochain numéro de la liste en aura également besoin. Le 7
immédiatement après le 255
sert à cet effet, tandis que l'autre 7
sera consommé par le calcul.
Tout d'abord, nous ajoutons les deux chiffres:
<+>->+[->+]->>
[->+<]>
Nous laissant ici:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
La prochaine combinaison d'étapes est la plus compliquée. Nous devons voir si le nombre que nous pointons est supérieur à 10, et si c'est le cas, nous soustrayons 10
. En réalité, ce que nous faisons, c'est que nous en soustrayons 10 et voyons s'il frappe 0
à un moment quelconque de la soustraction. Si c'est le cas, nous ajoutons10
plus tard. À la fin de cela, nous devrions avoir la somme modulo 10.
Prepare a 10 to the right
+>++++++++++
Leave yet another 255 for a loop condition later
>>-<<
If the number is greater than 10 end up one space to the left
else one space to the right
[-<-[>>]<]<->
Check if the previous 255 is two spaces to the right and if it is
add 10 back to our sum--we've subtracted too much
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
À ce stade, nous avons atteint l'objectif. Nous avons la somme modulo 10! Aussi, que le nombre soit supérieur ou non à 10, nous nous retrouverons ici:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
Nos prochains objectifs sont de produire cette nouvelle somme, de la suivre avec un espace et de la réinjecter dans notre liste. Nous faisons tout cela avec nos techniques précédentes de 255
sauts et d'ajout 48
à notre somme, donc je ne le couvrirai pas en détail.
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
Et nous y sommes: [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
remarquez comment nous mettons un 255
espace réservé supplémentaire après notre nouvelle injection 3
afin de ne pas perdre de place dans la liste. À ce stade, nous avons sorti notre somme et son espace, nous devons donc nettoyer et revenir à un état où la prochaine itération de cette boucle va fonctionner. Nous devons effacer nos cellules 51
et 32
, déplacer 7
une fois vers la droite et naviguer vers notre espace réservé de liste afin de pouvoir recommencer.
[-]<[-]<<<[->+<]<<+[-<+]
Maintenant, nous sommes ici: [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
qui est exactement où nous voulons être pour notre prochaine itération. Alors vérifiez 255 et continuez! ( >+]
)
Lorsque nous serons retirés de la boucle, nous aurons une toute nouvelle liste - composée des sommes de la liste précédente. La première fois, cela ressemblera à ceci:
[ 0 2 32 255 3 9 5 0 >0< ]
Maintenant, nous voulons répéter tout ce processus sur notre nouvelle liste, nous avons donc plop un 255
vers la gauche et tout recommencer! Nous devons faire un peu de nettoyage avec >>[-]<<
, puis supprimer notre espace réservé avec <-
. Après cela, nous sommes exactement au même endroit que nous étions après l'entrée, nous pouvons donc nous en sortir en faisant les mêmes vérifications <+[-<+]->>+
:, et boum! Nous avons notre boucle complète! Nous avons tous besoin est le support de fermeture, et quand il se termine , nous avons déjà tout sortie, donc nous avons terminé: ]
.