Recently, I discovered an interesting esoteric programming language: Piet. Programs written in this language look like abstract paintings and commands are defined by the color changes in the picture/program. That’s what gives you a lot of freedom to create nice looking and functional programs, which makes it a lot of fun. For example, the below picture is a fully functional Piet program.

Piet Basics

Photo by Ernest Ojeh on Unsplash

Piet programs look like abstract paintings. To achieve this, commands are defined by color changes instead of words or characters. A program (picture) is organized in a grid of codels. Codels are used instead of pixels to make it possible to scale up program pictures and consequently to make it easier to see them. For example, one codel could have a size of 20x20 pixels.

Further, Piet programs are two dimensional and the language is stack based.

In the next subsections I’ll point out some Piet basics. If you want to write programs in Piet, I’d also recommend you to read the official language specification. If you are only interested in my program, you can skip this part and jump to the section “My first Piet Program”.

Program Execution

Direction Pointer (DP)

  • Possible values: “right”, “down”, “left, “up”
  • Initial value: “right”

Codel Chooser (CC)

  • Possible values: “left”, “right”
  • Initial value: “left”

Color Cycles

Command Colors

The same principle applies to the lightness level of colors. Each color is aligned on a “Lightness Circle”. As there exist 6 base colors, we have 6 Lightness Circles. Here you can iterate over each circle again. Again, light red is one step darker than dark red because of the cycles. Additionally, dark red is one step lighter than light red because the circles work in both directions. The Lightness Circles are represented by the grey arrows in the picture below.

Piet: Hue and Lightness Circles

Black and White

White blocks are basically “free zones”. This means, the interpreter just slides (or floats) through them in a straight line until it hits a block of any other color than white. In the beginning it was a bit unclear, what happens if a black block or an edge follows directly after a white block, so interpreters handle this scenario in two possible ways:

  • The same scenario, as when a black block or an edge is hit by a “normal” color block happens (Codel Chooser and Direction Pointer are rotated). The author of the language stated that this is how we interprets the specification.
  • The program is terminated (that’s the way, the interpreter I used works).

Commands

Piet command table

Please head over to the official language specification to read more about how each command works.

Piet Interpreters

Hello World

The program above simply prints “Hi” to the console. You can see the program trace in the picture itself, to learn more about it, head over to this link.

The picture above shows a very artistic way to print “Hello, world!” to the console. Here you can find some detailled information about it.

Check out this page for more sample Piet programs.

My first Piet Program

The given problem

The input is a text file with passport data. The passports in this file are separated by new lines. The fields in a passport are separated by spaces or new lines.

Head over to Advent of Code to read the full problem description.

First solution

Working solution for AoC Day 4 in Piet

Below, I’ll give my best, to explain what the program is doing in each step. If you would like to analyze it in detail, you can simply download the picture above and import it to a Piet Editor. I’d recommend the one from When Life Gives You a SIGSEGV, but it should work with most of the editors out there.

Working solution for AoC Day 4 in Piet — Explained

In the above picture, you can see, that I divided the program into 7 sections. Each section is represented by a color and described below.

Initialization (Orange)

  1. Push 0 onto the stack. The first number on the stack will always be the count of valid passports.
  2. This part just reads in a character and prints it to the console. We added this, because we had problems with the input parsing of the editor sometimes and this way we made sure, that everything was fine. We just added a “?” at the beginning of the input and checked, if it was printed to the console.
  3. There is no logic in this part, it’s just a line break. We didn’t know, if we need more initialization logic, so we moved all other logic to the next lines, to make sure, that we have enough space if we need it.
  4. That’s a very cool thing my friend came up with. We named it CC-fixer and it just makes sure, that the CC is pointing left.

Initialize new passport (Blue)

Read in the next key and check it (Green)

  1. Read in the next char, duplicate it and check if its value is 10 (ASCII value for a new line character). If yes, it means that a new passport starts. Therefore, rotate the DP by one and move on to the turquoise section. If no, the character, that has just been read, is the first character of a new key -> continue with part 2 of the current section.
  2. Read in two more characters, to push the full key onto the stack. Add the values of characters up. This can be done, because the sums of all keys are unique and that’s why the sums can be used to differentiate the keys.
  3. Push the values 4, 3 and 10 onto the stack.
  4. Duplicate 10 and multiply and add the numbers in order to get 304 (the sum of the key cid) on the top of the stack. Then subtract this value from the sum of the key, to check if the key, that was just read, is cid. If yes, rotate the DP by one and continue with the purple section. If no, continue with the next part of the green section.
  5. If the program reaches this point, it read in a new key that is not cid. Therefore, the number of valid keys in the current passport is increased by one. Then the direction of the DP is changed, because of the black codel at the end and the purple section is executed next.

Dump all characters until the next key starts or the end of the file is reached (Purple)

  1. Set the direction of the DP to left and the value of the CC to right.
  2. Read in the next character and duplicate it. Then check if it equals 0 (End of File) and if yes, rotate the pointer and continue with the red section to terminate the program. If no, simply continue with part 3 of the current section.
  3. Duplicate the char again, push 10 (ASCII value for the new line character) onto the stack and subtract those two values to check if the read in character is a new line. If yes, switch the CC (to left) and therefore continue with the first part of the pink section. Otherwise, leave the CC as it is and continue with part 4 of this section.
  4. Push the numbers that are necessary to multiply and add up to 32 (ASCII value for the space character) onto the stack. Then multiply and add them up, until the value 32 is on top of the stack. Next, subtract this number to check if the current character is a space. If yes, switch the CC (to left) and therefore continue with the second part of the pink section. Otherwise, leave the CC as it is and continue with part 5 of this section.
  5. Use white, colored and black blocks to adapt the DP to jump back to part 1 of this section and to execute the loop again to read in and review the next character.

Jump back to the main loop and read in the next key (Pink)

  1. Pop the last read in character off the stack, as it is not needed anymore.
  2. Change the direction DP to up (because it can't go further to the left).
  3. Change the direction of the DP to right (because it can't go further up) and continue with the green section afterwards.

Validate the valid field count of the current passport and initialize the next passport (Turquoise)

  1. Change the direction of the DP to left (because it can't go further down).
  2. Pop the new line character, that has just been read in.
  3. Use a CC-Fixer to make sure the CC points to the right.
  4. Subtract the top value on the stack (the number of valid fields in the current passport) by 7 and apply the command not on the result. This means, if the result is 0 the value 1 will be pushed onto the stack instead of the result. If the result is not 0 the value 0 will be pushed onto the stack instead of the result. Add this new value to the total count of valid passports.
  5. Adapt the DP to loop back to the blue section, that initializes a new passport. (By doing that it passes the CC-fixer of the orange section, which makes sure, that the CC is pointing left).

Print the result to the console and terminate the program (Red)

  1. Change the direction DP to right (because it can't go further up).
  2. Use a CC-Fixer to make sure the CC points to the left.
  3. Subtract the top value on the stack (the number of valid fields in the current passport) by 7 and apply the command not on the result. This means, if the result is 0 the value 1 will be pushed onto the stack instead of the result. If the result is not 0 the value 0 will be pushed onto the stack instead of the result. Add this new value to the total count of valid passports.
  4. Print the total count of valid passports to the console.
  5. Terminate the program.

A Christmas themed Piet Program

In the picture below, I highlighted the same blocks, as in the explanation of the first example, that is described above. Please note that some blocks, like the sanity check and line break in the beginning (orange section, part 2–4) are missing, because I decided to not implement them in the themed variant. Further, the commands aren’t exactly the same, but the program can be separated into the same logical blocks. Especially the commands to change directions/make loops are a bit different, because the structure of the program has changed. Nevertheless, if you understand the first example, it will be easy for you to understand this tree as well. Especially, with the explanation squares I added in the picture below.

Please take note of the yellow codel in the top left of the image. This codel is necessary, because the program execution always starts at the top left codel. By starting at this point, the executor “floats” through the white codels, until it reaches the star (orange section, part 1), where the actual program starts.

Well, that’s it :D I hope you enjoyed reading the article and some nice Piet programming is coming up for you.

Merry Christmas,

Kathi

Originally published at https://ksick.dev on December 24, 2020.

Creative and detail-oriented software developer. Advanced from mobile to backend development and now getting into full stack solutions.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store