- Piet es un lenguaje de programación esotérico diseñado para que el código parezca arte abstracto, y toma su nombre de Piet Mondrian, pionero del arte abstracto geométrico
- Un programa es un gráfico hecho con 20 colores reconocidos; el ejecutor se mueve entre bloques de color e interpreta los cambios de color como comandos
- Todos los datos existen solo como enteros y se almacenan en una pila; el tamaño de un bloque de color es un valor, pero no se sube automáticamente a la pila sin el comando
push - El control de flujo se determina mediante Direction Pointer y Codel Chooser, además de reglas para bloques negros, bordes y bloques blancos; algunos comportamientos pueden variar según la implementación
- Aunque existen ejemplos y un ecosistema de herramientas externas, no hay un intérprete oficial autoritativo, y el manejo de errores y la interpretación de colores no estándar siguen dependiendo de la implementación
La idea básica de Piet
- Piet es un lenguaje de programación en el que el código del programa parece arte abstracto
- Su nombre proviene de Piet Mondrian, pionero del arte abstracto geométrico
- Se quería usar el nombre
Mondrian, pero ya existía un lenguaje de scripting con ese nombre, así que se usó Piet - Después de escribirse la especificación, se formó una pequeña comunidad que ha creado programas, intérpretes, IDEs y compiladores
- No existe un intérprete oficial autoritativo, y las implementaciones disponibles pueden interpretar la especificación de formas ligeramente distintas
- Se han agregado algunas aclaraciones a la especificación, pero es posible que algunas implementaciones existentes no las sigan
Colores y unidades de código
- Piet usa un total de 20 colores
- 18 colores forman parte del ciclo de matiz y del ciclo de luminosidad
- El blanco y el negro no forman parte de ninguno de los dos ciclos
- El ciclo de matiz sigue el orden
red -> yellow -> green -> cyan -> blue -> magenta -> red - El ciclo de luminosidad sigue el orden
light -> normal -> dark -> lightlighttambién se considera un paso más oscuro quedark, y viceversa
- Se pueden usar colores no estándar como naranja o marrón, pero su efecto depende de la implementación
- En el caso más simple, los colores no estándar se tratan como blanco
- Otra posibilidad es que se traten como negro
Codels y bloques de color
- El código Piet es un gráfico compuesto por colores reconocibles
- Como cada píxel de código tiene significado en el lenguaje, en programas ampliados para verse mejor, un único píxel del código se llama codel
- La unidad básica de ejecución es el bloque de color
- Un bloque de color es un área donde codels del mismo color están conectados vertical u horizontalmente
- Los bloques que solo se tocan en diagonal no se consideran conectados
- Un bloque de color puede tener cualquier forma y puede contener huecos internos de otros colores
- Los huecos internos no forman parte de ese bloque
Pila y representación de valores
- Piet almacena todos los valores de datos en una pila
- Los valores de datos solo existen como enteros
- Según el comando, pueden ingresarse o imprimirse como valores de caracteres Unicode
- Conceptualmente, la pila tiene profundidad infinita, pero una implementación puede imponer un tamaño máximo finito de pila
- Si ocurre un desbordamiento en una pila finita, es un error en tiempo de ejecución, y su manejo depende de la implementación
- Un bloque de color que no sea negro ni blanco representa un valor entero igual al número de codels de ese bloque
- Los enteros no positivos no pueden representarse directamente
- Sí pueden generarse mediante operadores
- El valor de un bloque de color no se hace
pushautomáticamente a la pila; se necesita un comandopushexplícito
- Conceptualmente, el tamaño de los enteros también es infinito, pero una implementación puede imponer un tamaño máximo finito de entero
- Un desbordamiento de entero es un error en tiempo de ejecución y su manejo depende de la implementación
Flujo de ejecución
- El intérprete comienza la ejecución en el bloque de color que contiene el codel de la esquina superior izquierda del programa
- Durante la ejecución se mantienen dos estados
- Direction Pointer (DP): al principio apunta a la derecha, y puede apuntar a derecha, izquierda, abajo o arriba
- Codel Chooser (CC): al principio apunta a la izquierda, y puede apuntar a la izquierda o a la derecha
- El siguiente destino de movimiento se decide por el borde del bloque de color actual y la combinación de DP y CC
- Se encuentra el borde del bloque de color actual que está más lejos en la dirección del DP
- En ese borde, se elige el codel más alejado en la dirección del CC respecto de la dirección de avance del DP
- Desde ese codel se avanza en la dirección del DP al bloque de color al que pertenece el codel inmediatamente siguiente
- Este proceso se repite hasta que se alcanza una condición de terminación, momento en el que el programa finaliza
Bloques negros, bordes y bloques blancos
- Los bloques de color negro y los bordes del programa actúan como barreras que bloquean el flujo de ejecución
- Si el intérprete intenta moverse a un bloque negro o salir fuera de un borde, se detiene y alterna el CC
- Si el segundo intento también falla, rota el DP un paso en sentido horario
- Después de alternar CC y DP e intentarlo un total de 8 veces, si no puede salir del bloque de color actual, el programa termina
-
Movimiento por bloques blancos
- Los bloques de color blanco son áreas libres que el intérprete atraviesa sin obstáculos
- Si se mueve desde un bloque de color a una zona blanca, el intérprete avanza en línea recta en la dirección del DP hasta llegar a un bloque de color que no sea blanco
- Al moverse a un nuevo color atravesando un bloque blanco, no se ejecuta ningún comando
- Por esta característica, los bloques blancos permiten cambiar el color actual sin ejecutar comandos, lo que resulta útil para escribir bucles
- El movimiento por bloques blancos no usa el procedimiento de elegir una salida desde un bloque de color no blanco; solo realiza movimiento en línea recta
-
Cuando queda bloqueado dentro de un bloque blanco
- Si al atravesar un bloque blanco en línea recta encuentra un bloque negro o un borde, se trata como una restricción
- En ese caso se alterna el CC, pero como la posición a la que intenta moverse no cambia, el DP rota inmediatamente un paso en sentido horario
- Luego vuelve a avanzar en línea recta desde el codel blanco actual en la nueva dirección del DP
- Cada vez que se encuentra una restricción dentro de un bloque blanco, se repite la alternancia del CC y la rotación del DP
- Si entra a un bloque de color, la ejecución continúa; si dentro del bloque blanco empieza a desandar su camino, no hay salida y la ejecución termina
Sistema de comandos
- Los comandos de Piet se determinan por el cambio de color al moverse de un bloque de color al siguiente
- La cantidad de pasos avanzados en el ciclo de matiz y en el ciclo de luminosidad determina el comando
- En una transición de color realizada a través de un bloque blanco, no se ejecuta ningún comando
-
Comandos de pila y aritmética
push: sube a la pila el valor del bloque de color que se acaba de abandonarpop: saca y descarta el valor superior de la pilaadd: suma los dos valores superiores y sube el resultado de vuelta a la pilasubtract: sube a la pila el resultado de restar el valor superior al segundo valormultiply: multiplica los dos valores superioresdivide: divide el segundo valor entre el valor superior usando división entera- La división por cero es un error dependiente de la implementación, y se recomienda ignorar el comando
mod: sube a la pila el resto de dividir el segundo valor entre el valor superior- El resultado tiene el mismo signo que el divisor, es decir, el valor superior de la pila
- Si el valor superior es 0, es un error de división por cero, y se recomienda ignorar el comando
modcon un dividendo negativo equivale a la floored division descrita en Wikipedia para la operación módulo
-
Comandos de comparación, punteros y entrada/salida
not: cambia el valor superior de la pila a 0 si no es 0, o a 1 si es 0greater: sube 1 a la pila si el segundo valor es mayor que el valor superior; si no, sube 0pointer: saca el valor superior de la pila y rota el DP en sentido horario esa cantidad de veces- Si es negativo, rota en sentido antihorario
switch: saca el valor superior de la pila y alterna el CC esa cantidad de veces- Si es negativo, alterna tantas veces como su valor absoluto
duplicate: sube a la pila una copia del valor superiorroll: saca los dos valores superiores y rota una parte de la pila restante según la profundidad y la cantidad indicadas- Si la profundidad es negativa, es un error y el comando se ignora
- Un
rollque supere la profundidad máxima de pila dependiente de la implementación es un error dependiente de la implementación, y se recomienda ignorar el comando in: lee un número o un carácter desde STDIN y lo sube a la pila- Si no hay entrada o, para entrada entera, no se recibe un entero, es un error y el comando se ignora
out: imprime en STDOUT el valor superior de la pila como número o carácter- Las operaciones que no puedan realizarse por falta de valores en la pila se ignoran y se pasa al siguiente comando
Ejemplos y herramientas
- Se pueden ver ejemplos de Piet en Sample programs
- Los intérpretes externos y herramientas de desarrollo están recopilados en Third-party Piet interpreters and development tools
1 comentarios
Comentarios en Hacker News
El último programa de la página de ejemplos es realmente asombroso: una persona llamada Piet vio una obra de arte que le recordó al lenguaje Piet y decidió probar a ejecutarla
Funcionó, y quizá sea el primer caso en la historia en que un artista gráfico dibujó por accidente un programa de computadora funcional
https://www.dangermouse.net/esoteric/piet/samples.html
https://gitlab.fabcity.hamburg/hofalab/piet-get-together
https://www.mcmillen.dev/sigbovik/
Piet tomó una foto de la obra, la convirtió en un archivo de imagen acomodado a colores cercanos a la paleta de Piet y luego la ejecutó; de hecho funcionó, y el código era un bucle infinito que leía caracteres ASCII e imprimía su valor numérico ASCII
De verdad cuesta creerlo
La explicación de que “por supuesto, si escribes un programa más grande puedes obtener un valor más preciso” me sonó a un tipo de chiste que nunca había visto
Según la especificación, el intérprete debe empezar a deslizarse desde el codel blanco actual en la nueva dirección del DP y seguir hasta entrar en un bloque de color o encontrarse con otra restricción
Pero el intérprete npiet mira dentro del espacio en blanco y luego retrocede hasta la posición del último codel de color. Algún día quisiera añadir ese comportamiento como opción al lexer de mi compilador de Piet, pero todavía no lo he tocado
Si se sigue la especificación, ese programa se convierte en un simple bucle no terminante porque las esquinas extremas de casi todos los bloques son adyacentes al blanco. Es bastante difícil escribir programas complejos de Piet que apunten a varios intérpretes y compiladores, porque todos tienen diferencias sutiles de interpretación no documentadas
Creo que la salida de mi backend de Piet depende menos del intérprete en general, pero solo he investigado a fondo otras tres o cuatro implementaciones
https://github.com/boothby/repiet/
Hojeando la documentación, por la condición de que “las operaciones que no pueden realizarse, como una operación pop cuando no hay suficientes valores en la pila, simplemente se ignoran y se continúa con la siguiente instrucción”, parecería que todas esas imágenes podrían ejecutarse sin errores
Aun así, cuántas de esas imágenes aleatorias llegan a hacer algo realmente “significativo” es otra cuestión
Piet es un experimento emblemático incluso entre los lenguajes de programación esotéricos, pero creo que no alcanza la meta de hacer que un programa se vea como una pintura de Mondrian a menos que el desarrollador realmente se lo proponga
Me gustaría que la propia estructura del lenguaje estuviera diseñada para que, sin importar lo que “escribas”, se vea como una pintura de Mondrian
Siempre me surge esta pregunta: ¿cómo se ve un algoritmo?
¿Se podrá hacer en la realidad algo parecido a lo que aparece en la novela de Herman Hesse The Glass Bead Game? El título original es Magister Ludi
Como alguien orientado a lo visual, quiero creer que sí, y de hecho he usado herramientas así
https://community.carbide3d.com/uploads/default/original/3X/5/b/5b0872a5666fec9b7bb6fd623c431de03263372d.jpeg
Pero si no hay una respuesta clara a la pregunta anterior, estas herramientas siempre corren el riesgo de terminar así
https://blueprintsfromhell.tumblr.com/
https://scriptsofanotherdimension.tumblr.com/
También es difícil equilibrar la expresividad visual y la modularidad, y si empujas demasiado la modularidad, es muy fácil volver a la barrera del texto que querías evitar
Sergei Lewis y yo hicimos cada uno herramientas para generar código Piet. El ensamblador de Sergei produce código mucho más agradable a la vista que mi backend de Piet
Lo único que realmente se nota en la salida de mi compilador es que usé trampolines con una flojera impresionante
http://www.toothycat.net/wiki/wiki.pl?MoonShadow/Piet
https://github.com/boothby/repiet/
https://en.wikipedia.org/wiki/Trampoline_(computing)
Es una idea que saqué al leer un libro de Steven Pinker: las palabras abstractas pueden descomponerse en términos más simples y al final terminan describiendo alguna relación espacial. Por ejemplo, “rekindle” puede verse como “volver a juntar dos cosas”
De forma parecida, un bucle
fortambién es un concepto mental de “una cosa que pasa sobre muchas otras”, y eso tiene una representación visual como “100” -> “010” -> “001”Entonces me pregunto si se podrá crear un lenguaje que defina estos componentes como puras transformaciones visuales
Esto queda perfecto para una escena de thriller criminal donde bloquea al protagonista o a los investigadores hasta que alguien se da cuenta de que es código
Y yo que pensaba que solo los códigos QR eran útiles
Alguien hizo un quine en Piet: http://mamememo.blogspot.com/2009/10/piet-quine.html?m=1
La imagen de esa entrada está rota, pero aquí hay una copia: https://codegolf.stackexchange.com/a/23255/103045
El momento de descubrir Piet es algo especial, una mezcla de asombro, confusión y sorpresa
En mi caso, quedó registrado en esta conversación del pódcast de informática “The CS Primer Show” que hago con mi amigo Oz: https://show.csprimer.com/episodes/e2-dont-let-a-gpt-have-all-the-fun
En la universidad hubo una clase pequeña sobre lenguajes de programación esotéricos
Cada quien tenía que elegir uno de entre Brainfuck, Piet y otros para jugar un poco con él, y yo escogí Piet y la pasé bastante bien
Si soy sincero, la app de ejemplo que hice no era gran cosa en lo estético, y siento que para hacer arte con Piet hay que volverse experto en Piet
La página de ejemplos es excelente
Puedes ver cómo el lienzo va evolucionando hasta volverse cada vez más sofisticado y agradable a la vista
https://www.dangermouse.net/esoteric/piet/samples.html
Eso de que “light se considera un paso más oscuro que dark” está bastante profundo
Estaría genial poder crear un autoencoder que aprenda a tomar código de Python o de otros lenguajes menos esotéricos y producirlo en Piet
Entonces quizá también se podrían generar algoritmos aleatorios, algo parecido a Stable Diffusion