Tuesday, May 3, 2011

Metaprogramming in Piet

I have always loved the Piet programming "language". It allows for the encoding of programs into a colorful image that resembles abstract art. It is the perfect mating of my love for coding and my love for epileptic fit inducing colors.

Quite a while ago I had the idea to implement a BrainF**k interpreter in Piet. I got halfway through a prototype before it got too complicated and I lost interest in the project for a while. Fast-Forward a few months and I find that it has now been done, no less than three times. I thought it would be a really cool way to show off the power of the Piet language. Seeing as that has now been done, I need to up my ante a bit.

What other crazy, esoteric language could I implement? What better choice than Piet itself? I can't think of one. I realized that npiet, the standard Piet interpreter, can handle ppm files with absolutely no problem. That essentially allows me to interact with images as strings of text, without having to muck about with decoding and encoding difficult image formats (although that is technically possible). In order to get to the point of a Piet interpreter written in Piet I need some more tools first, so I don't rip my brains out. Hopefully I can reach that lofty goal someday.

One discovery that helped me a lot was this blog post about QuickPiet. It is a language to create and debug algorithms on the Piet stack without having to worry about the spatial complications of actually laying out an image. I made a quick Piet interpreter, and made a few additions of my own, like modifying the way the goto command works. It is definitely possible to programatically transform a QuickPiet program into a working image, but I found the result looks mechanical, and is generally less artsy and less fun.
I decided a first step in exploring Piet meta-programming would be to try and write a Piet program that generates another Piet program. I decided to make a program that will accept any string as input, and output a Piet program that will also output that string. Rather worthless, I know, but valuable as a proof that it is possible.

So I coded it up in quick piet until I was fairly confident that it worked. The good thing about quick piet is that is removes all of the space and layout constraints that the image requires, and lets you just worry about the algorithms. So I had about 600 lines of quick piet that appears to work. I wrote a normalization engine to separate it into distinct labels, make all implicit jumps explicit, and generally clean it up. I took the normalized output, and a graph of which blocks lead to which other blocks, and I proceeded to lay it all out by hand (starting over twice when I got waay too lost to continue), and finally I got this little masterpiece:

That program will read all input until it receives a two quotation marks. It will then generate a valid Piet program (as a PPm image) that will in turn output all of the text between the quotation marks. So if I give it the input "Hello, World!", It will give me the following as a result:
Which will of course output "Hello, World!".
It seems to be pretty highly scalable, although a bit slow. For instance, here is a program that generates the declaration of independence:
And here is a real gem. This one outputs a piet program that will in turn output "Hello, World". I would try and wrap it one more level deeper, but I'm afraid the universe might explode if I do so. The image size is something like 55000x116, so it doesn't render very well in a blog. If you want to download it it is here.

2 comments:

  1. Really interesting stuff! Pretty sure this is one of (if not THE) first piet programs to do any sort of metaprogramming at all (excluding a few quines that aren't really doing any programming per-se).

    Just wanted to point out that only the first two brainfuck links are actually interpreters. The second one is actually more of a brainfuck-to-piet compiler or translator which is a pretty different problem domain (but no less complicated to be sure!).

    ReplyDelete
  2. Yes, but he ran a brainfuck interpreter in brainfuck through his compiler to get a piet version.

    ReplyDelete