Comment fonctionne le Brainfuck Hello World?

118

Quelqu'un m'a envoyé ça et a prétendu que c'était un bon monde dans Brainfuck (et je l'espère ...)

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

Je connais les bases que cela fonctionne en déplaçant un pointeur et en incrémentant et en décrémentant des trucs ...

Pourtant, je veux toujours savoir, comment ça marche réellement? Comment imprime-t-il quoi que ce soit à l'écran en premier lieu? Comment encode-t-il le texte? Je ne comprends pas du tout...

speeder
la source
31
Doit être assez difficile de maintenir une application écrite dans cette langue ..
e2-e4
17
@ ring0: non, c'est un langage en écriture seule.
LetMeSOThat4U
quelle est son utilisation pratique?
Yash Kumar Verma
10
@YashVerma il n'en a pas besoin d'un ..
Insane
49
@YashVerma C'est clairement spécifié dans le nom de la langue.
Mateen Ulhaq

Réponses:

255

1. Bases

Pour comprendre Brainfuck, vous devez imaginer un tableau infini de cellules initialisées par 0chacune.

...[0][0][0][0][0]...

Lorsque le programme brainfuck démarre, il pointe vers n'importe quelle cellule.

...[0][0][*0*][0][0]...

Si vous déplacez le pointeur vers la droite, >vous déplacez le pointeur de la cellule X vers la cellule X + 1

...[0][0][0][*0*][0]...

Si vous augmentez la valeur de la cellule, +vous obtenez:

...[0][0][0][*1*][0]...

Si vous augmentez à nouveau la valeur de la cellule, +vous obtenez:

...[0][0][0][*2*][0]...

Si vous diminuez la valeur de la cellule, -vous obtenez:

...[0][0][0][*1*][0]...

Si vous déplacez le pointeur vers la gauche, <vous déplacez le pointeur de la cellule X vers la cellule X-1

...[0][0][*0*][1][0]...

2. Entrée

Pour lire le caractère, vous utilisez une virgule ,. Ce qu'il fait est: Lire le caractère de l'entrée standard et écrire son code ASCII décimal dans la cellule réelle.

Jetez un œil à la table ASCII . Par exemple, le code décimal de !est 33, tandis que aest 97.

Eh bien, imaginons que la mémoire de votre programme BF ressemble à:

...[0][0][*0*][0][0]...

En supposant que l'entrée standard signifie a, si vous utilisez l' ,opérateur virgule , ce que fait BF est de lire ale code ASCII décimal 97en mémoire:

...[0][0][*97*][0][0]...

Vous voulez généralement penser de cette façon, mais la vérité est un peu plus complexe. La vérité est que BF ne lit pas un caractère mais un octet (quel que soit cet octet). Laissez-moi vous montrer un exemple:

Sous Linux

$ printf ł

imprime:

ł

qui est un caractère polonais spécifique. Ce caractère n'est pas encodé par encodage ASCII. Dans ce cas, il s'agit d'un codage UTF-8, il prenait donc plus d'un octet dans la mémoire de l'ordinateur. Nous pouvons le prouver en effectuant un vidage hexadécimal:

$ printf ł | hd

qui montre:

00000000  c5 82                                             |..|

Les zéros sont décalés. 82est le premier et c5est le deuxième octet représentant ł(dans l'ordre nous les lirons). |..|est une représentation graphique qui n'est pas possible dans ce cas.

Eh bien, si vous passez łcomme entrée à votre programme BF qui lit un octet, la mémoire du programme ressemblera à:

...[0][0][*197*][0][0]...

Pourquoi 197? Eh bien, la 197décimale est c5hexadécimale. Cela vous semble familier? Bien sûr. C'est le premier octet de ł!

3. Sortie

Pour imprimer le caractère, vous utilisez le point .Ce qu'il fait est: En supposant que nous traitons la valeur réelle de la cellule comme du code ASCII décimal, imprimez le caractère correspondant sur la sortie standard.

Eh bien, imaginons que la mémoire de votre programme BF ressemble à:

...[0][0][*97*][0][0]...

Si vous utilisez maintenant l'opérateur point (.), Ce que fait BF est d'imprimer:

une

Parce que ale code décimal en ASCII est 97.

Par exemple, un programme BF comme celui-ci (97 plus 2 points):

++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++ ..

Augmentera la valeur de la cellule pointée jusqu'à 97 et l'imprimera 2 fois.

aa

4. Boucles

Dans BF, la boucle comprend le début [et la fin de la boucle ]. Vous pouvez penser que c'est comme en C / C ++ où la condition est la valeur réelle de la cellule.

Jetez un œil au programme BF ci-dessous:

++[]

++ incrémente deux fois la valeur réelle de la cellule:

...[0][0][*2*][0][0]...

Et []c'est comme while(2) {}, donc c'est une boucle infinie.

Disons que nous ne voulons pas que cette boucle soit infinie. On peut faire par exemple:

++[-]

Ainsi, chaque fois qu'une boucle boucle, elle décrémente la valeur réelle de la cellule. Une fois que la valeur réelle de la cellule est 0terminée, la boucle:

...[0][0][*2*][0][0]...        loop starts
...[0][0][*1*][0][0]...        after first iteration
...[0][0][*0*][0][0]...        after second iteration (loop ends)

Considérons encore un autre exemple de boucle finie:

++[>]

Cet exemple montre que nous n'avons pas à terminer la boucle à la cellule sur laquelle la boucle a commencé:

...[0][0][*2*][0][0]...        loop starts
...[0][0][2][*0*][0]...        after first iteration (loop ends)

Cependant, il est bon de terminer là où nous avons commencé. Pourquoi ? Parce que si la boucle termine une autre cellule qu'elle a commencée, nous ne pouvons pas supposer où sera le pointeur de cellule. Pour être honnête, cette pratique rend le brainfuck moins brainfuck.

Scony
la source
4
Cool, maintenant je l'ai compris :)
speeder
25
C'était une solution parfaite pour le novice essayant de comprendre cette idéologie linguistique. Félicitations et excellent message.
Casey
4
Meilleure intro Brainfuck que j'ai vue. Honnêtement, vous annulez un peu BF par votre message
Boyang
3
Je suppose que si vous avez besoin d'un projet pour votre temps libre, vous pouvez toujours ajouter le support Unicode à Brainfuck.
Álvaro González
3
Après votre message, BF est! BF plus!
thanos.a
52

Wikipédia a une version commentée du code.

+++++ +++++             initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 70/100/30/10
    > +++++ ++              add  7 to cell #1
    > +++++ +++++           add 10 to cell #2 
    > +++                   add  3 to cell #3
    > +                     add  1 to cell #4
    <<<< -                  decrement counter (cell #0)
]                   
> ++ .                  print 'H'
> + .                   print 'e'
+++++ ++ .              print 'l'
.                       print 'l'
+++ .                   print 'o'
> ++ .                  print ' '
<< +++++ +++++ +++++ .  print 'W'
> .                     print 'o'
+++ .                   print 'r'
----- - .               print 'l'
----- --- .             print 'd'
> + .                   print '!'
> .                     print '\n'

Pour répondre à vos questions, les caractères ,et .sont utilisés pour les E / S. Le texte est ASCII.

L' article Wikipédia est également approfondi.

La première ligne s'initialise a[0] = 10en incrémentant simplement dix fois à partir de 0. La boucle de la ligne 2 définit effectivement les valeurs initiales du tableau: a[1] = 70(proche de 72, le code ASCII pour le caractère 'H'), a[2] = 100(proche de 101 ou 'e' ), a[3] = 30(proche de 32, le code de l'espace) et a[4] = 10(nouvelle ligne). La boucle fonctionne en ajoutant 7, 10, 3 et 1, à des cellules a[1], a[2], a[3]et a[4]respectivement à chaque fois à travers la boucle - 10 additions pour chaque cellule au total (donnant a[1]=70etc.). Une fois la boucle terminée, a[0]vaut zéro. >++.puis déplace le pointeur vers a[1], qui contient 70, en ajoute deux (produisant 72, qui est le code de caractère ASCII d'un H majuscule), et le sort.

La ligne suivante déplace le pointeur de tableau vers a[2]et y ajoute un, produisant 101, un «e» minuscule, qui est ensuite sorti.

Comme «l» se trouve être la septième lettre après «e», pour afficher «ll», sept autres sont ajoutés ( +++++++) a[2]et le résultat est affiché deux fois.

«o» est la troisième lettre après «l», il a[2]est donc incrémenté trois fois de plus et affiche le résultat.

Le reste du programme se déroule de la même manière. Pour l'espace et les lettres majuscules, différentes cellules du tableau sont sélectionnées et incrémentées ou décrémentées selon les besoins.

Ken
la source
Mais POURQUOI ça imprime? ou comment? Les commentaires m'expliquent l'intention de la ligne, maintenant ce qu'elle fait.
speeder
8
Il imprime parce que le compilateur le sait ,et .est utilisé pour les E / S, un peu comme C imprime en utilisant putchar. Il s'agit d'un détail d'implémentation géré par le compilateur.
ken
1
Et aussi parce qu'il définit les cellules requises sur les valeurs entières pour les caractères ASCII dans "Hello World"
slugonamission
Je m'attendais à une explication plus approfondie ... mais: /
speeder
1
@speeder - J'ai ajouté l'explication détaillée du code de Wikipedia à la réponse. Vous pouvez consulter l'article lié pour plus d'informations.
ken
9

Pour répondre à la question de savoir comment il sait quoi imprimer, j'ai ajouté le calcul des valeurs ASCII à droite du code où l'impression a lieu:

> just means move to the next cell
< just means move to the previous cell
+ and - are used for increment and decrement respectively. The value of the cell is updated when the increment/decrement happens

+++++ +++++             initialize counter (cell #0) to 10

[                       use loop to set the next four cells to 70/100/30/10

> +++++ ++              add  7 to cell #1

> +++++ +++++           add 10 to cell #2 

> +++                   add  3 to cell #3

> +                     add  1 to cell #4

<<<< -                  decrement counter (cell #0)

]            

> ++ .                  print 'H' (ascii: 70+2 = 72) //70 is value in current cell. The two +s increment the value of the current cell by 2

> + .                   print 'e' (ascii: 100+1 = 101)

+++++ ++ .              print 'l' (ascii: 101+7 = 108)

.                       print 'l' dot prints same thing again

+++ .                   print 'o' (ascii: 108+3 = 111)

> ++ .                  print ' ' (ascii: 30+2 = 32)

<< +++++ +++++ +++++ .  print 'W' (ascii: 72+15 = 87)

> .                     print 'o' (ascii: 111)

+++ .                   print 'r' (ascii: 111+3 = 114)

----- - .               print 'l' (ascii: 114-6 = 108)

----- --- .             print 'd' (ascii: 108-8 = 100)

> + .                   print '!' (ascii: 32+1 = 33)

> .                     print '\n'(ascii: 10)
Rehana Mahfuz
la source
9

Brainfuck identique à son nom. Il n'utilise que 8 caractères, > [ . ] , - +ce qui en fait le langage de programmation le plus rapide à apprendre mais le plus difficile à implémenter et à comprendre. … Et vous fait finalement finir par baiser votre cerveau.

Il stocke les valeurs dans le tableau: [72] [101] [108] [111]

let, initialement pointeur pointant vers la cellule 1 du tableau:

  1. > déplacer le pointeur vers la droite de 1

  2. < déplacer le pointeur vers la gauche de 1

  3. + incrémenter la valeur de la cellule de 1

  4. - incrémenter la valeur de l'élément de 1

  5. . affiche la valeur de la cellule actuelle.

  6. , prendre l'entrée à la cellule actuelle.

  7. [ ] boucle, +++ [-] compteur de 3 comptes bcz il a 3 ′ + 'devant lui, et - décrémente la variable de comptage de 1 valeur.

les valeurs stockées dans les cellules sont des valeurs ascii:

donc en se référant au tableau ci-dessus: [72] [101] [108] [108] [111] si vous correspondez aux valeurs ascii, vous constaterez que c'est Hello writtern

Félicitations! vous avez appris la syntaxe de BF

——- Quelque chose de plus ———

laissez-nous faire notre premier programme, à savoir Hello World , après quoi vous pourrez écrire votre nom dans cette langue.

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

briser en morceaux:

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

Crée un tableau de 4 cellules (nombre de>) et définit un compteur de 10 quelque chose comme: —-psuedo code—-

array =[7,10,3,1]
i=10
while i>0:
 element +=element
 i-=1

car la valeur du compteur est stockée dans la cellule 0 et> se déplace vers la cellule 1 met à jour sa valeur de + 7> se déplace vers la cellule 2 incrémente 10 à sa valeur précédente et ainsi de suite….

<<< retourne à la cellule 0 et décrémente sa valeur de 1

par conséquent, après la fin de la boucle, nous avons le tableau: [70,100,30,10]

>++. 

passe au 1er élément et incrémente sa valeur de 2 (deux '+') puis imprime le caractère ('.') avec cette valeur ascii. ie par exemple en python: chr (70 + 2) # affiche 'H'

>+.

passe à la 2ème cellule incrément 1 à sa valeur 100 + 1 et affiche ('.') sa valeur ie chr (101) chr (101) # imprime 'e' maintenant il n'y a pas de> ou <dans la pièce suivante donc il prend la valeur actuelle du dernier élément et incrémenter uniquement

+++++ ++..

dernier élément = 101 donc, 101 + 7 et l'imprime deux fois (car il y a deux '..') chr (108) #prints l deux fois peut être utilisé comme

for i in array:
    for j in range(i.count(‘.’)):
           print_value

——— Où est-il utilisé? ——-

C'est juste un langage de plaisanterie conçu pour défier les programmeurs et n'est utilisé pratiquement nulle part.

DARK_C0D3R
la source
4

Toutes les réponses sont complètes, mais il leur manque un petit détail: l'impression. En construisant votre traducteur brainfuck, vous considérez également le personnage ., c'est en fait à quoi ressemble une déclaration d'impression dans brainfuck. Donc, ce que votre traducteur brainfuck devrait faire, c'est qu'à chaque fois qu'il rencontre un .caractère, il imprime l'octet actuellement pointé.

Exemple:

supposons que vous ayez -> char *ptr = [0] [0] [0] [97] [0]... s'il s'agit d'une déclaration brainfuck: >>>.votre pointeur doit être déplacé de 3 espaces vers la droite pour atterrir à:, [97]alors maintenant *ptr = 97, après avoir fait cela, votre traducteur rencontre a ., il devrait alors appeler

write(1, ptr, 1)

ou toute instruction d'impression équivalente pour imprimer l'octet actuellement pointé, qui a la valeur 97 et la lettre asera alors imprimée sur le std_output.

rapdean
la source
1

Je pense que ce que vous demandez, c'est comment Brainfuck sait quoi faire avec tout le code. Il existe un analyseur écrit dans un langage de niveau supérieur tel que Python pour interpréter ce que signifie un point ou ce que signifie un signe d'addition dans le code.

Ainsi, l'analyseur lira votre code ligne par ligne, et dira ok il y a un symbole> donc je dois avancer l'emplacement de la mémoire, le code est simplement, if (contenu dans cet emplacement de mémoire) ==>, memlocation = + memlocation qui est écrit dans un langage de niveau supérieur, de même si (contenu de l'emplacement mémoire) == ".", puis print (contenu de l'emplacement mémoire).

J'espère que cela clarifie les choses. tc

Rahul
la source