It's alive! This is a Piet intepreter in Clojure with design goals of:
- the code to be pretty comprehensible
- the corners softened with decent errors and forgiving treatment of edge cases
- runtime verbosity that is comprehensive but not overwhelming.
clj-piet exists, check my fork, but it's over a decade old and doesn't traverse whitespace as per the updated spec. This project is inspired by and takes influence from that one but is just my updated personal rewrite.
clj -X:run '{:file "programs/file.png"}'
:codel-size
, :verbose?
, and :limit
default to 1
, true
, and 0
(unlimited).
- corner-test ✅
- factorial ✅
- hello-world-1 ✅
- hello-world-2 ✅
- hello-world-3 ✅
- pi ❌ Int madness
- tetris ✅
- whitespace-test ✅
Most of the programs are reused or slightly edited from Piet sample programs.
Piet scripts are images, or, 2D arrays of pixels representing a predetermined set of color values.
Execution happens "between" tiles, in the movement from one color tile to the next.
The color of a pixel doesn't contain any data about what to run, only the difference between two colors.
What is this, a programming language for ants?! Where a textual language parses files one-dimensionally character by character, the layout of colors causes the interpreter to crawl around the program as it would on a plane. It looks forward, zigzagging and looping around based on boundaries between plots of color.
Piet has 18 program colors and two utility shades (walls and open space), see below.
Hex, the RGB ints that .getRGB
returns, and RGB.
⬇️ hue shift ➡️ tone shift
+0 | +1 | +2 | |
---|---|---|---|
+0 | push | pop | |
+1 | + | - | * |
+2 | / | mod | not |
+3 | > | pointer | switch |
+4 | duplicate | roll | int in |
+5 | char in | int out | char out |
White is kind of strange
On white blocks the pointer acts differently from colorful spaces. Instead of a rigid 'flip-check-turn-check' cycle, it acts identically to blocks in icy zelda dungeons or slippery sokoban puzzles.
Instead of terminating after 8 unsuccessful checks in each possible block outlet, a program caught in whitespace terminates once its path of checks loops back onto itself.
Two termination cases adds some unpleasant complexity, but whitespace handling is more intuitive.
Why Clytemnestra?
Just descriptive...like mathematicians use Greek letters to extend the alphabet.
This language is so impossible to write
Yeah...
If you want to change one piece in the middle of the program you probably have to rewrite the whole thing.
With an abstract colorful visual language I'd rather have the pointer jumping around than doing an ant walk.
Each codel block has 4 different "easy"-to-spot properties: area, R, G, and B. In Piet the RGB values are reduced to one property, ∆color, so each unit of language only encodes two pieces of data.
I imagine a language equally difficult to deal with for different reasons, where, for instance,
- area: int value
- ∆R: command to execute
- G: relative X offset to next codel
- B: relative Y offset to next codel
That would be chaos...