Programmation Brainfuck/Comment effectuer les opérations courantes

Hello World!

modifier

Un programme qui affiche "Hello World!" sur l'écran est :

++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.
>.+++.------.--------.>+.>.

Brainfuck est intéressant dans ce cas, un programme "Hello World!" n'est pas facile à écrire ! Et à lire !

Avec un commentaire :

Hello world
++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.
>.+++.------.--------.>+.>.

Ou avec des commentaires expliquant le code, en anglais :

[ This program prints "Hello World!" and a newline to the screen, its
  length is 106 active command characters. [It is not the shortest.]

  This loop is an "initial comment loop", a simple way of adding a comment
  to a BF program such that you don't have to worry about any command
  characters. Any ".", ",", "+", "-", "<" and ">" characters are simply
  ignored, the "[" and "]" characters just have to be balanced. This
  loop and the commands it contains are ignored because the current cell
  defaults to a value of 0; the 0 value causes this loop to be skipped.
]
++++++++               Set Cell #0 to 8
[
    >++++               Add 4 to Cell #1; this will always set Cell #1 to 4
    [                   as the cell will be cleared by the loop
        >++             Add 2 to Cell #2
        >+++            Add 3 to Cell #3
        >+++            Add 3 to Cell #4
        >+              Add 1 to Cell #5
        <<<<-           Decrement the loop counter in Cell #1
    ]                   Loop until Cell #1 is zero; number of iterations is 4
    >+                  Add 1 to Cell #2
    >+                  Add 1 to Cell #3
    >-                  Subtract 1 from Cell #4
    >>+                 Add 1 to Cell #6
    [<]                 Move back to the first zero cell you find; this will
                        be Cell #1 which was cleared by the previous loop
    <-                  Decrement the loop Counter in Cell #0
]                       Loop until Cell #0 is zero; number of iterations is 8

The result of this is:
Cell no :   0   1   2   3   4   5   6
Contents:   0   0  72 104  88  32   8
Pointer :   ^

>>.                     Cell #2 has value 72 which is 'H'
>---.                   Subtract 3 from Cell #3 to get 101 which is 'e'
+++++++..+++.           Likewise for 'llo' from Cell #3
>>.                     Cell #5 is 32 for the space
<-.                     Subtract 1 from Cell #4 for 87 to give a 'W'
<.                      Cell #3 was set to 'o' from the end of 'Hello'
+++.------.--------.    Cell #3 for 'rl' and 'd'
>>+.                    Add 1 to Cell #5 gives us an exclamation point
>++.                    And finally a newline from Cell #6

Remise à zéro de l'octet pointé

modifier
[-]

Tant que l'octet est différent de 0, on le décrémente. On arrête donc la boucle ([]) quand il est à 0.

Entrée/Sortie d'un caractère

modifier
,.

Prend un caractère du clavier pour l'afficher à l'écran.

Boucle simple

modifier
,[.,]

Une boucle qui prend une entrée du clavier et l'affiche à l'écran. Notez qu'on s'attend à avoir un 0 pour marquer la fin de l'entrée (les implémentations peuvent être différentes à ce niveau là).

Manipulation de pointeur

modifier
>,[.>,]

Une version améliorée de la boucle précédente dans laquelle on stocke les caractères entrés dans le tableau pour une future utilisation, en déplaçant le pointeur à chaque fois.

Addition

modifier

Ce code ajoute l'octet courant (en le détruisant, il sera à 0 à la fin) à l'octet suivant.

[->+<]

Soit Tableau[0] = 2 et Tableau[1] = 8, "[" débute la boucle, "-" et Tableau[0] = 1, ">" on pointe sur l'octet 1, "+" et Tableau[1] = 9, "]" on recommence. À la fin, on aura bien Tableau[0] = 0 ce qui arrête la boucle, et Tableau[1] = 10.

Instructions conditionnelles

modifier
,----------[----------------------.,----------]

Ce programme prend un caractère minuscule en entrée et le met en majuscule. Pour arrêter, on tape la touche entrée (code 10 en Brainfuck dans la plupart des compilos).

Au début, on récupère le premier caractère (,) et on lui soustrait immédiatement 10 (10 fois -). Si l'utilisateur a tapé entrée, on a 0 dans l'octet pointé et l'instruction de boucle ([) sautera à la fin du programme. Si le caractère entré n'est pas 10, on assume qu'il est en minuscule et on entre dans la boucle, où on va lui soustraire le nombre 22 (22 fois -), ce qui va faire 32 en tout, et 32 est la différence en ASCII entre la lettre minuscule et la même lettre en majuscule.

On va donc l'afficher, puis on en récupère une nouvelle, et à nouveau on lui soustrait 10. Et on repart au début de la boucle. Si le caractère entrée est un Entrée (10), la boucle s'arrêtera comme on l'a déjà vu, sinon on continue.

Addition

modifier
,>++++++[<-------->-],,[<+>-],<.>.

Ce programme additionne 2 nombres à un seul chiffre et affiche le résultat si celui-ci n'a aussi qu'un seul chiffre :

4+3

7

(Maintenant les choses vont être un peu plus compliquées. Nous allons nous référer aux octets du tableau ainsi : [0], [1], [2], etc.)

Le premier nombre est entré dans [0], et on lui soustrait 48 pour avoir sa valeur décimale (les codes ASCII pour les chiffres 0-9 sont 48-57). Cela est fait en mettant 6 dans [1] et en utilisant une boucle pour soustraire 8 de [0] autant de fois que dans [1], soit 6 x 8 = 48. C'est une méthode plus commode pour ajouter ou soustraire des grands nombres que de mettre 48 fois "-" dans le programme. Le code qui fait cela est :

>++++++[<-------->-]

>++++++ pour mettre 6 dans [1], puis on attaque la boucle, "<" pour revenir sur [0], on soustrait 8, ">" on repasse sur [1], qu'on décrémente et on retourne dans la boucle. On va bien l'exécuter 6 fois, jusqu'à ce que [1] soit à 0.

Ensuite, on récupère le signe plus qu'on met dans [1] ; puis le second chiffre qui va écraser le signe plus.

La boucle suivante [<+>-] fait le vrai boulot, ajoutant le second nombre dans le premier et remettant à zéro [1]. À chaque boucle, il ajoute 1 dans [0] et retire 1 de [1]  ainsi [1] va finir par être à 0 tout ce qui a été ajouté à [0] a été retiré de [1]. Ensuite la touche entrée est mise dans [1]. (Note : il n'y a eu aucun contrôle des entrées.)

Puis le pointeur est remis sur [0], qui est affiché ([0] est maintenant a + (b + 48), puisqu'on n'a pas corrigé b ; ce qui est identique à (a + b) + 48, qui est ce que l'on veut). Maintenant, le pointeur est ramené sur [1], qui contient la touche entrée ; que l'on affiche, et le boulot est fait.

Multiplication

modifier
,>,,>++++++++[<------<------>>-]
<<[>[>+>+<<-]>>[<<+>>-]<<<-]
>>>++++++[<++++++++>-],<.>.

Comme le précédent, mais effectue une multiplication, pas une addition.

Le premier nombre est entré dans [0], l'astérisque et le deuxième nombre dans [1] et les 2 nombres sont corrigés en leur soustrayant 48 (notez qu'il n'y a qu'une seule boucle de 8 itérations pour soustraire 6 à chaque itération aux 2 nombres !).

Ensuite on entre dans la boucle de multiplication principale. L'idée de base est qu'à chaque boucle on soustrait 1 de [0] et on ajoute [1] dans le total cumulé gardé en [2] (3 * 2 = 2 + 2 + 2). En particulier : la première boucle cumule [1] dans [2] et [3], tout en remettant [1] à 0 (C'est la manière basique de dupliquer un nombre). La deuxième boucle remet [3] dans [1], en remettant à 0 [3]. Puis on décrémente [0] et on est à la fin de la boucle principale. À la sortie de cette boucle, [0] contient 0, [1] a encore le 2e nombre, et [2] a le produit des 2 nombres. (Si on veut garder le premier nombre, on peut l'ajouter dans [4] à chaque itération de la boucle principale, puis à la fin de déplacer la valeur de [4] dans [0].)

Exemple : 3 * 2

[0] [1] [2] [3]
3 2 0 0
1re boucle : >[>+>+<<-]
3 1 1 1
3 0 2 2
2e boucle : >>[<<+>>-]
3 1 2 1
3 2 2 0
Fin boucle princ : <<<-]
2 2 2 0
1re boucle : >[>+>+<<-]
2 1 3 1
2 0 4 2
2e boucle : >>[<<+>>-]
2 1 4 1
2 2 4 0
Fin boucle princ : <<<-]
1 2 4 0
1re boucle : >[>+>+<<-]
1 1 5 1
1 0 6 2
2e boucle : >>[<<+>>-]
1 1 6 1
1 2 6 0
Fin boucle princ : <<<-]
0 2 6 0

Ensuite, il ne reste plus qu'à ajouter 48 au produit, récupérer la touche entrée dans [3], et afficher le produit ASCII et l'entrée qu'on vient juste de stocker.