Le livre "The Pragmatic Programmer" (si vous ne l'avez pas lu, arrêtez de lire cet article et faites-le maintenant !) dit que chaque année nous devrions apprendre un nouveau langage de programmation.
Même si certains diront que c'est trop d'efforts, nous sommes tous d'accord pour dire que c'est une bonne idée. Choisir une nouvelle langue à apprendre n'est pas si facile. Nous ne voulons pas consacrer notre temps à quelque chose que nous n'utiliserons peut-être jamais en pratique, n'est-ce pas ? Mais peut-être devrions-nous parfois faire une exception et apprendre quelque chose juste pour le plaisir ? J'aimerais vous présenter le langage Brainfuck. Il s'agit d'un langage que vous pouvez apprendre en quelques minutes, ce qui vous évite d'investir trop de temps en vain. De plus, je peux vous promettre que résoudre n'importe quel problème avec Brainfuck stimulera votre cerveau (tous les f*cks ne sont qu'un bonus ;)). Commençons ! Selon Wikipedia :
Casse-tête est un langage de programmation ésotérique créé en 1993 par Urban Müller. Le langage se compose de huit commandes simples et d'un pointeur d'instructions. Bien qu'il soit totalement Turing-complet, il n'est pas destiné à une utilisation pratique, mais à défier et à amuser les programmeurs.
Aperçu des langues
Imaginez un ruban (ou une bande) infiniment long composé de cellules, chacune initialisée à 0. Il existe également un pointeur de données mobile qui pointe initialement sur la première cellule. Il y a également deux flux d'octets pour l'entrée et la sortie. Les instructions sont exécutées séquentiellement, une par une. La machine s'arrête après avoir exécuté la dernière.
Commandement
Qu'est-ce qu'il fait ?
>
déplacer le pointeur de données vers la cellule suivante à droite
<
déplacer le pointeur de données vers la cellule suivante à gauche
+
incrémenter la valeur de la cellule courante
–
décrémenter la valeur de la cellule courante
.
sort l'octet d'une cellule actuellement pointée en ASCII code
,
lire un octet à partir de stdin et stocker sa valeur dans la cellule actuelle
[
si la cellule actuelle est 0, sauter à la cellule correspondante ]
]
sauter à l'élément correspondant [
Tous les caractères autres que ><+-.,[] sont ignorées.
Prenons un exemple simple :
,+.
Il sera interprété comme suit :
lire un octet et le stocker dans la cellule courante (cell0)
incrémenter la valeur de la cellule courante (cell0 = cell0 + 1)
écrire le contenu de la cellule actuelle sur la sortie
En conséquence, un caractère sera lu à partir de l'entrée et le caractère suivant sera imprimé à partir de la table ASCII.
Interprète / Compilateur
Avant d'écrire des programmes utiles ( ?) dans Brainfuck, nous avons besoin d'un interpréteur ou d'un compilateur. AFAIK, il n'y en a pas d'officiel, mais ce n'est pas un problème. Il y en a des dizaines non officiels sur Internet. Je peux vous recommander ces deux-là :
"Hello World" devrait être le premier programme que nous écrivons lorsque nous apprenons une nouvelle langue. Cependant, l'écrire dans Brainfuck est un peu plus difficile que dans d'autres langages. Commençons par quelque chose de plus facile... Ecrivons un programme qui imprimera une seule lettre "H" sur l'écran (c'est tellement excitant :D) :
Comment cela fonctionne-t-il ? Il fixe la valeur de la cellule courante à 72 (en effectuant des incréments de 72) et l'imprime à l'écran en utilisant "." (H a le code 72 en ASCII). Vous savez maintenant ce qu'il faut faire pour imprimer "Hello World !" à l'écran, mais avant cela, nous allons procéder à un petit remaniement. L'écriture de tous ces '+' nécessite trop de saisie et de comptage. Nous pouvons les raccourcir en utilisant [ et ] pour le bouclage. Pour fixer la valeur à 72, nous pouvons par exemple faire une boucle qui augmente la valeur 7 fois par 10. Nous obtenons ainsi 70. En ajoutant 2, on obtient 72. Voici à quoi cela ressemble :
++++++++++ # set cell0 to 10
[# boucle jusqu'à ce que cell0 soit 0
- # diminue cell0
> # déplace le pointeur de données vers la droite (cellule1)
+++++++ # augmente la cellule1 de 7
# déplacer le pointeur de données vers la droite (cell1)
++ # augmente de 2
. # imprimer le résultat
J'ai inclus des commentaires pour expliquer clairement comment tout fonctionne. Le même programme sans commentaires :
++++++++++[->+++++++++.
N'est-ce pas magnifique ? 🙂 .
Bonjour le monde !
Revenons à notre programme "Hello World ! Nous pourrions fixer la valeur de la première cellule à 72 (H) et l'imprimer, fixer la valeur de la deuxième cellule à 101 (e) et l'imprimer, fixer la valeur de la troisième cellule à 108 et l'imprimer, et ainsi de suite. Voici l'implémentation de cet algorithme :
Comme je ne suis pas assez fou pour l'écrire signe par signe, j'ai un peu triché et généré ce programme avec Ruby :
met "Hello World !".chars.map { |c| c.ord.times.map { "+" }.join + ".>" }.join("n")`
Oui, seulement 1120 octets pour imprimer "Hello World !"... Mais nous pouvons faire mieux ! Au lieu d'utiliser une nouvelle cellule pour chaque caractère, n'en utilisons qu'une seule. Pour imprimer la lettre "e" (101), nous pouvons réutiliser la valeur de la cellule 0 (72). Nous pouvons l'augmenter d'une unité 29 fois (101 - 72). Le résultat est le suivant :
Nous avons fait de grands progrès. 377 octets au lieu de 1120 octets. Cependant, il y a encore de la place pour des améliorations. Je vais vous donner quelques idées :
utiliser 3 (ou plus) cellules pour les caractères qui sont plus proches les uns des autres dans l'ASCII (lettres minuscules, lettres majuscules, espace et exclamation)
utiliser des boucles au lieu de répétitions + et -
Voici la version de Wikipédia qui reprend ces idées :
Il ne fait que 106 octets et il imprime une nouvelle ligne à la fin ! C'est incroyable.
Inverser une chaîne
Nous sommes maintenant prêts à écrire quelque chose de plus difficile. Ecrivons un programme qui lira une ligne en entrée et l'imprimera dans l'ordre inverse. Le premier problème est de lire les caractères et de s'arrêter sur le caractère de la nouvelle ligne. Rappelez-vous qu'il n'y a pas de pause, si ou d'autres déclarations similaires. Nous devons utiliser [ et ]. Commençons par un programme qui lit tous les caractères de l'entrée et les place dans des cellules successives :
,[>,]
Elle commence par la lecture du premier caractère et se poursuit jusqu'au dernier. , retour d'opération 0. Cependant, il bouclera indéfiniment dans l'implémentation qui renvoie autre chose que O pour EOF (le langage ne spécifie pas ce comportement). Alors comment s'arrêter sur le caractère de la nouvelle ligne ? Voici l'astuce :
+[++++++++++>,----------]
Nous commençons avec la cellule 0 fixée à 1 pour nous assurer que notre boucle est exécutée au moins une fois. Dans une boucle, nous augmentons la valeur de la cellule actuelle de 10, déplaçons le pointeur de données vers la cellule suivante, lisons un caractère et diminuons sa valeur de 10. De cette façon, si un caractère de nouvelle ligne (10 en ASCII) est lu, le programme s'arrêtera à la prochaine itération, sinon sa valeur sera rétablie en ajoutant 10.
Après cette étape, nos cellules ressembleront à ceci :
11 C1 C2 C3 0* 0 0
Cn est le nième caractère de l'entrée, et * est la position actuelle du pointeur de données. Nous devons maintenant commencer à déplacer le pointeur de données vers la gauche et imprimer toutes les cellules jusqu'à ce que nous atteignions la valeur 11. Voici ce que je pense de cette tâche :
Lorsque je suis tombé sur Brainfuck, un langage de programmation ésotérique, je l'ai d'abord considéré comme un simple gadget ou une blague. Ce langage particulier et, comme beaucoup pourraient l'affirmer, d'une difficulté déconcertante, m'est apparu comme quelque chose d'uniquement destiné à l'amusement. Mais au fil du temps, ma perception de Brainfuck a radicalement changé.
La nature énigmatique de Brainfuck vous met au défi, vous poussant à élargir votre vision des choses. les langages de programmation. Ce langage ésotérique vous permet d'apprécier la beauté et la nécessité des langages de haut niveau auxquels nous sommes habitués. Il met en lumière l'importance des abstractions, des conventions de dénomination appropriées et d'une disposition organisée de la mémoire dans le domaine des langages de programmation. C'est quelque chose que Brainfuck, avec son design minimaliste composé de seulement huit commandes simples, ne fournit pas.
Brainfuck est un langage complet de Turing qui souligne l'importance d'un code source clair et cohérent. Bien qu'il soit reconnu comme l'un des langages ésotériques les plus difficiles pour écrire des programmes, il brille ironiquement en tant que favori des débutants pour quiconque souhaite créer un compilateur ou un interpréteur Brainfuck. La raison en est la simplicité de son jeu de commandes et le fait qu'il ne nécessite pas d'analyse complexe.
La création d'un programme Brainfuck est unique à deux égards. Tout d'abord, vous devez vous adapter à l'utilisation d'un seul pointeur de mémoire, ce qui vous oblige à penser différemment votre code source. Deuxièmement, vous disposez de l'"option zéro", c'est-à-dire de la possibilité de remettre la cellule de mémoire à zéro, une fonctionnalité peu courante dans les autres langages de programmation formels.
En termes d'apprentissage, Brainfuck est plus qu'un simple jeu d'enfant. Avec suffisamment de temps et le bon état d'esprit, il est possible d'écrire le même programme d'une multitude de façons en utilisant différents codes Brainfuck. La dernière moitié de ce voyage consiste à être inventif et à trouver de nouvelles façons créatives d'utiliser ses six symboles.
Les interprètes Brainfuck, bien que minimalistes, vous donnent une compréhension profonde de la façon dont le code s'exécute, de ce que le programme imprime et des mécanismes sous-jacents d'un langage complet de Turing. En fin de compte, Brainfuck n'est pas simplement un autre langage de programmation ésotérique. C'est une toute nouvelle dimension, un regard différent sur la façon dont nous voyons, comprenons et écrivons les programmes.