4 points par GN⁺ 2024-04-25 | 1 commentaires | Partager sur WhatsApp
  • Piet est un langage de programmation ésotérique conçu pour que le code ressemble à de l’art abstrait ; il doit son nom à Piet Mondrian, pionnier de l’abstraction géométrique
  • Un programme est une image composée de 20 couleurs reconnues, et l’exécuteur se déplace entre des blocs de couleur en interprétant les variations de couleur comme des commandes
  • Toutes les données n’existent que sous forme d’entiers et sont stockées sur une pile ; la taille d’un bloc de couleur représente une valeur, mais celle-ci n’est pas automatiquement placée sur la pile sans commande push
  • Le contrôle de flux est déterminé par le Direction Pointer, le Codel Chooser, ainsi que par les règles des blocs noirs, des bords et des blocs blancs ; certains comportements peuvent varier selon les implémentations
  • Il existe des exemples et un écosystème d’outils externes, mais pas d’interpréteur officiel faisant autorité ; la gestion des erreurs et l’interprétation des couleurs non standard restent dépendantes de l’implémentation

L’idée de base de Piet

  • Piet est un langage de programmation dont le code ressemble à de l’art abstrait
  • Son nom vient de Piet Mondrian, pionnier de l’abstraction géométrique
  • Le nom Mondrian aurait été souhaité, mais comme un langage de script portait déjà ce nom, le nom Piet a été utilisé
  • Depuis la rédaction de la spécification, une petite communauté s’est formée et a créé des programmes, des interpréteurs, des IDE et des compilateurs
  • Il n’existe pas d’interpréteur officiel faisant autorité, et les implémentations disponibles peuvent interpréter la spécification de façon légèrement différente
  • Certaines explications de la spécification ont été ajoutées, mais il est possible que certaines implémentations existantes ne les suivent pas

Couleurs et unités de code

  • Piet utilise au total 20 couleurs
    • 18 couleurs font partie du cycle des teintes et du cycle de luminosité
    • Le blanc et le noir ne font partie d’aucun de ces deux cycles
  • Le cycle des teintes suit l’ordre red -> yellow -> green -> cyan -> blue -> magenta -> red
  • Le cycle de luminosité suit l’ordre light -> normal -> dark -> light
    • light est aussi considéré comme un cran plus sombre que dark, et l’inverse est également vrai
  • Des couleurs non standard, comme l’orange ou le marron, peuvent être utilisées, mais leur effet dépend de l’implémentation
    • Dans le cas le plus simple, les couleurs non standard sont traitées comme du blanc
    • Une autre possibilité est qu’elles soient traitées comme du noir

Codels et blocs de couleur

  • Le code Piet est une image composée de couleurs reconnaissables
  • Comme chaque pixel de code a une signification au niveau du langage, dans les programmes agrandis pour être plus lisibles, un pixel unique du code est appelé codel
  • L’unité d’exécution de base est le bloc de couleur
    • Un bloc de couleur est une zone de codels de même couleur reliés horizontalement ou verticalement
    • Des blocs qui ne se touchent qu’en diagonale ne sont pas considérés comme reliés
    • Un bloc de couleur peut avoir n’importe quelle forme et contenir des trous d’une autre couleur
    • Les trous internes ne font pas partie de ce bloc

Pile et représentation des valeurs

  • Piet stocke toutes les valeurs de données sur une pile
  • Les valeurs de données sont uniquement des entiers
    • Selon les commandes, elles peuvent être saisies ou affichées comme valeurs de caractères Unicode
  • Conceptuellement, la pile a une profondeur infinie, mais une implémentation peut définir une taille maximale finie
  • Sur une pile finie, un dépassement de capacité est une erreur d’exécution, dont le traitement dépend de l’implémentation
  • Un bloc de couleur qui n’est ni noir ni blanc représente une valeur entière égale au nombre de codels qu’il contient
    • Les entiers non positifs ne peuvent pas être représentés directement
    • Ils peuvent toutefois être créés au moyen d’opérateurs
    • La valeur d’un bloc de couleur n’est pas automatiquement poussée sur la pile ; une commande explicite push est nécessaire
  • La taille des entiers est également conceptuellement infinie, mais une implémentation peut définir une taille maximale finie
    • Un dépassement d’entier est une erreur d’exécution, dont le traitement dépend de l’implémentation

Flux d’exécution

  • L’interpréteur commence l’exécution dans le bloc de couleur contenant le codel situé en haut à gauche du programme
  • Pendant l’exécution, deux états sont maintenus
    • Direction Pointer (DP) : il pointe initialement vers la droite et peut pointer vers la droite, la gauche, le bas ou le haut
    • Codel Chooser (CC) : il pointe initialement vers la gauche et peut pointer vers la gauche ou la droite
  • La prochaine destination est déterminée par la bordure du bloc de couleur courant et par la combinaison DP/CC
    • On cherche le bord du bloc de couleur courant le plus éloigné dans la direction du DP
    • Sur ce bord, on choisit le codel le plus éloigné dans la direction du CC, relativement à la direction de progression du DP
    • Depuis ce codel, on se déplace vers le bloc de couleur auquel appartient le codel immédiatement suivant dans la direction du DP
  • Ce processus se répète jusqu’à ce qu’une condition de terminaison soit atteinte, auquel cas le programme se termine

Blocs noirs, bords et blocs blancs

  • Les blocs de couleur noirs et les bords du programme agissent comme des barrières qui bloquent le flux d’exécution
  • Si l’interpréteur tente de se déplacer vers un bloc noir ou hors des bords, il s’arrête et inverse le CC
  • Si la deuxième tentative échoue également, il fait tourner le DP d’un cran dans le sens horaire
  • Après avoir alterné changements de CC et de DP pour un total de 8 tentatives, si le bloc de couleur courant ne peut toujours pas être quitté, le programme se termine
  • Déplacement dans les blocs blancs

    • Les blocs de couleur blancs sont des zones libres que l’interpréteur traverse sans obstruction
    • Lorsqu’il passe d’un bloc de couleur à une zone blanche, l’interpréteur se déplace en ligne droite dans la direction du DP jusqu’à atteindre un bloc de couleur non blanc
    • Aucune commande n’est exécutée lors du passage à une nouvelle couleur à travers un bloc blanc
    • Grâce à cette propriété, les blocs blancs permettent de changer la couleur courante sans exécuter de commande, ce qui est utile pour écrire des boucles
    • Le déplacement dans un bloc blanc n’utilise pas la procédure de choix de sortie d’un bloc de couleur non blanc et n’effectue qu’un déplacement en ligne droite
  • Lorsqu’on est bloqué dans un bloc blanc

    • Si, en traversant un bloc blanc en ligne droite, l’interpréteur rencontre un bloc noir ou un bord, cela est traité comme une contrainte
    • Dans ce cas, le CC est inversé, mais comme la position visée ne change pas, le DP est immédiatement tourné d’un cran dans le sens horaire
    • Ensuite, depuis le codel blanc courant, le déplacement en ligne droite reprend dans la nouvelle direction du DP
    • Chaque fois qu’une contrainte est rencontrée dans un bloc blanc, l’inversion du CC et la rotation du DP se répètent
    • Si un bloc de couleur est atteint, l’exécution continue ; si le chemin commence à se rebrousser à l’intérieur du bloc blanc, il n’existe aucune sortie et l’exécution se termine

Système de commandes

  • Les commandes de Piet sont déterminées par la variation de couleur lors du passage d’un bloc de couleur au suivant
  • La commande est définie par le nombre d’étapes parcourues dans le cycle des teintes et dans le cycle de luminosité
  • Aucune commande n’est exécutée lors d’une transition de couleur effectuée via un bloc blanc
  • Commandes de pile et arithmétiques

    • push : place sur la pile la valeur du bloc de couleur qui vient d’être quitté
    • pop : retire et jette la valeur au sommet de la pile
    • add : additionne les deux valeurs du sommet et replace le résultat sur la pile
    • subtract : soustrait la valeur du sommet de la deuxième valeur et place le résultat sur la pile
    • multiply : multiplie les deux valeurs du sommet
    • divide : effectue une division entière de la deuxième valeur par la valeur du sommet
    • La division par zéro est une erreur dépendante de l’implémentation ; il est recommandé d’ignorer la commande
    • mod : place sur la pile le reste de la division de la deuxième valeur par la valeur du sommet
    • Le résultat a le même signe que le diviseur, c’est-à-dire la valeur au sommet de la pile
    • Si la valeur au sommet est 0, il s’agit d’une erreur de division par zéro ; il est recommandé d’ignorer la commande
    • Pour un dividende négatif, mod est identique à la division euclidienne arrondie vers le bas décrite dans l’article Wikipedia sur l’opération modulo
  • Commandes de comparaison, de pointeurs et d’entrée/sortie

    • not : remplace la valeur au sommet de la pile par 0 si elle n’est pas 0, ou par 1 si elle vaut 0
    • greater : place 1 sur la pile si la deuxième valeur est supérieure à la valeur du sommet, sinon 0
    • pointer : retire la valeur au sommet de la pile et fait tourner le DP dans le sens horaire autant de fois
    • Si elle est négative, la rotation se fait dans le sens antihoraire
    • switch : retire la valeur au sommet de la pile et inverse le CC autant de fois
    • Si elle est négative, il est inversé autant de fois que sa valeur absolue
    • duplicate : place une copie de la valeur au sommet de la pile sur la pile
    • roll : retire les deux valeurs du sommet et fait tourner une partie restante de la pile selon une profondeur et un nombre de rotations donnés
    • Si la profondeur est négative, il s’agit d’une erreur et la commande est ignorée
    • Un roll qui dépasse la profondeur maximale de pile dépendante de l’implémentation est une erreur dépendante de l’implémentation ; il est recommandé d’ignorer la commande
    • in : lit un nombre ou un caractère depuis STDIN et le place sur la pile
    • S’il n’y a pas d’entrée, ou si une entrée entière ne fournit pas d’entier, il s’agit d’une erreur et la commande est ignorée
    • out : affiche sur STDOUT la valeur au sommet de la pile sous forme de nombre ou de caractère
    • Les opérations qui ne peuvent pas être exécutées faute de valeurs suffisantes sur la pile sont ignorées, puis l’exécution passe à la commande suivante

Exemples et outils

1 commentaires

 
GN⁺ 2024-04-25
Avis sur Hacker News
  • Le dernier programme de la page d’exemples est vraiment étonnant : une personne nommée Piet aurait vu une œuvre d’art qui lui faisait penser au langage Piet et l’aurait exécutée.
    Elle s’est exécutée, et il s’agit peut-être du premier cas de l’histoire où un artiste graphique a peint par hasard un programme informatique fonctionnel.
    https://www.dangermouse.net/esoteric/piet/samples.html
    https://gitlab.fabcity.hamburg/hofalab/piet-get-together

    • Si l’on définit assez largement ce que signifie « fonctionner », il a déjà été montré que la plupart des éclaboussures de peinture sont des programmes Perl valides.
      https://www.mcmillen.dev/sigbovik/
    • Piet J. a vu une œuvre dans une petite galerie et a eu l’impression qu’elle ressemblait à un programme Piet ; l’artiste a dit ne pas connaître du tout ce langage.
      Piet a pris l’œuvre en photo, l’a convertie en un fichier image réorganisé avec des couleurs proches de la palette Piet, puis l’a exécutée : elle s’est effectivement lancée, et le code était une boucle infinie qui lisait des caractères ASCII et affichait leur valeur numérique ASCII.
      C’est vraiment difficile à croire.
    • L’exemple qui calcule π était bien aussi.
      L’explication selon laquelle « bien sûr, avec un programme plus grand, on peut obtenir une valeur plus précise » m’a paru être un type de blague que je n’avais encore jamais vu.
    • Malheureusement, cela repose sur une différence entre npiet et la spécification actuelle de Piet.
      Selon la spécification, l’interpréteur doit commencer à glisser depuis le codel blanc courant dans la nouvelle direction du DP, et continuer jusqu’à entrer dans un bloc de couleur ou rencontrer une autre limite.
      Mais l’interpréteur npiet regarde dans l’espace blanc, puis revient à la position du dernier codel coloré. J’aimerais un jour ajouter ce comportement en option au lexer de mon compilateur Piet, mais je ne m’y suis pas encore attaqué.
      En suivant la spécification, ce programme devient une simple boucle non terminante, car les coins extrêmes de presque tous les blocs sont adjacents au blanc. Écrire des programmes Piet complexes ciblant plusieurs interpréteurs et compilateurs est assez difficile, chacun ayant de subtiles différences d’interprétation non documentées.
      Je pense que la sortie de mon backend Piet dépend généralement moins de l’interpréteur, mais je n’ai examiné en détail que trois ou quatre autres interpréteurs.
      https://github.com/boothby/repiet/
    • Je me demande quelle est la probabilité qu’une image simple de ce genre, c’est-à-dire composée de quelques grands blocs rectangulaires, soit un programme valide.
      En parcourant la documentation, à cause de la règle selon laquelle « les opérations impossibles à effectuer, comme une opération de dépilement quand la pile ne contient pas assez de valeurs, sont simplement ignorées et l’exécution continue avec l’instruction suivante », il me semble possible que toutes ces images s’exécutent sans erreur.
      Reste à savoir combien de ces images aléatoires font réellement quelque chose de « significatif ».
  • Piet est une expérience marquante parmi les langages de programmation ésotériques, mais à mon avis il n’atteint pas vraiment son objectif de faire ressembler les programmes à des tableaux de Mondrian, sauf si le développeur le cherche vraiment.
    J’aurais aimé que la structure même du langage soit conçue de sorte que, quoi que l’on « écrive », cela ressemble à un tableau de Mondrian.

    • Cela dit, Mondrian utilisait en fait surtout des couleurs primaires, donc cela aurait été assez restrictif.
  • Ce genre de question me revient sans cesse : à quoi ressemble un algorithme ?
    Peut-on créer dans le monde réel quelque chose qui ressemble à ce qu’on trouve dans le roman de Herman Hesse The Glass Bead Game ? Le titre original est Magister Ludi
    En tant que personne très visuelle, j’ai envie de croire que c’est possible, et j’ai même déjà utilisé de tels outils
    https://community.carbide3d.com/uploads/default/original/3X/5/b/5b0872a5666fec9b7bb6fd623c431de03263372d.jpeg
    Mais sans réponse claire à la question précédente, ces outils risquent toujours de finir comme ceci
    https://blueprintsfromhell.tumblr.com/
    https://scriptsofanotherdimension.tumblr.com/
    Il est aussi difficile de trouver l’équilibre entre expressivité visuelle et modularité ; et si l’on pousse trop la modularité, on retombe trop facilement sur la barrière du texte que l’on voulait éviter

    • Écrire Piet à la main a quelque chose d’amusant pour explorer « à quoi ressemble un algorithme »
      Sergei Lewis et moi avons chacun créé des outils qui génèrent du code Piet. L’assembleur de Sergei produit un code bien plus agréable à regarder que mon backend Piet
      Ce qu’on voit vraiment dans la sortie de mon compilateur, c’est surtout que j’ai utilisé un trampoline de manière très paresseuse
      http://www.toothycat.net/wiki/wiki.pl?MoonShadow/Piet
      https://github.com/boothby/repiet/
      https://en.wikipedia.org/wiki/Trampoline_(computing)
    • Je crois que tout algorithme, voire tout concept mental, entretient une relation 1:1 avec une représentation visuelle
      C’est une idée qui m’est venue en lisant un livre de Steven Pinker : les mots abstraits peuvent être décomposés en termes plus simples et finissent par décrire une relation spatiale. Par exemple, « rekindle » peut être vu comme « ramener deux choses ensemble »
      De même, une boucle for est le concept mental d’« une chose qui passe au-dessus de plusieurs autres », ce qui a une représentation visuelle comme « 100 » -> « 010 » -> « 001 »
      Je me demande donc s’il serait possible de créer un langage qui définisse ces briques comme de pures transformations visuelles
    • Pour un programme simple, on pourrait aussi imaginer implémenter une machine de Turing dont les symboles seraient des couleurs
  • Ce genre de chose aurait sa place dans un thriller criminel, où cela bloquerait le protagoniste ou les enquêteurs jusqu’à ce que quelqu’un réalise que c’est du code
    Moi qui pensais que seuls les QR codes étaient utiles

  • Quelqu’un a créé un quine en Piet : http://mamememo.blogspot.com/2009/10/piet-quine.html?m=1
    L’image de l’article est cassée, mais une copie se trouve ici : https://codegolf.stackexchange.com/a/23255/103045

  • Découvrir Piet est un moment particulier, mêlé d’émerveillement, de confusion et de surprise
    Dans mon cas, c’est capturé dans cette conversation de « The CS Primer Show », un podcast d’informatique avec mon ami Oz : https://show.csprimer.com/episodes/e2-dont-let-a-gpt-have-all-the-fun

  • À l’université, il y avait un petit cours sur les langages de programmation ésotériques
    Chacun devait choisir un langage comme Brainfuck ou Piet et jouer avec ; j’ai choisi Piet et je me suis bien amusé
    Honnêtement, la petite appli d’exemple que j’ai faite n’était pas très réussie esthétiquement, et j’ai l’impression qu’il faut devenir expert de Piet pour faire de l’art avec

  • La page d’exemples est excellente
    On peut voir le canevas évoluer progressivement vers quelque chose de plus sophistiqué et plus agréable à regarder
    https://www.dangermouse.net/esoteric/piet/samples.html

  • « light est considéré comme un cran plus sombre que dark », c’est assez profond

  • Ce serait chouette de pouvoir créer un autoencodeur qui apprend à prendre du code Python, ou d’un autre langage moins ésotérique, et à produire du Piet
    On pourrait alors peut-être générer des algorithmes aléatoires, un peu comme avec Stable Diffusion