NAME
Piet::Interpreter - Interpreter for the Piet programming language
SYNOPSIS
use Piet::Interpreter;
my $p = Piet::Interpreter->new(image => 'my_code.gif');
$p->run;
DESCRIPTION
Piet is a programming language in which programs look like abstract paintings. The language is named after Piet Mondrian, who pioneered the field of geometric abstract art. The language is fully described at http://www.physics.usyd.edu.au/~mar/esoteric/piet.html. A Piet program is an image file, usually a gif, which uses a set of 20 colors and the transitions between blocks of those colors to define a series of instructions and program flow. See the above URL for more details. (Note: some sample programs there may not work, as they were constructed before a working interpreter was available.)
Since Piet is a visual language, an image parsing mechanism is required. This module uses Image::Magick, so it would be to your advantage to download, install, and test that module and its related stuff before trying to use this one.
METHODS
- my $piet = Piet::Interpreter->new( %args );
-
Instantiates and returns a new Piet::Interpreter object. Valid arguments are:
- image => 'my_prog.gif'
-
Specifies the program image file to load into the interpreter.
- codel_size => $size
-
Tells the interpreter how large a codel is, in pixels. Defaults to 1.
- nonstandard => ('white'|'black')
-
Sets the behavior of non-standard colored codels to either 'white' or 'black'. Defaults to 'white'.
- debug => (1|0)
-
Turns on debugging information, including warnings.
- warn => (1|0)
-
Turns on warnings only.
- trace => (1|0)
-
Turns on program tracing, which only outputs instructions and values.
- $piet->reset;
-
Resets the PVM (Piet Virtual Machine) back to the default state. After a reset, the current x and y should both be 0, the DP points to the right, the CC points to the left, and the stack should be empty.
- $piet->image('myprog.gif');
-
Loads in a program image from the specified file. The interpreter was designed and tested using gif images, but any format that is supported by Image::Magick should work just fine. Once the file has been loaded, it is inspected and processed, creating a run-matrix and determining some useful properties from the image.
Note: Be sure to set the codel size, if needed, before loading the image. Otherwise, a size of 1 will be assumed, and the codel columns and rows will not be calculated correctly, causing pain and irritation.
- $piet->run;
-
Starts the Piet interpreter running from the upper-left codel. Program execution is described under "Language Concepts", below.
- $done = $piet->step;
-
Performs one "step" of a Piet program, where a step is one transition from one codel block to the next. A failed transition (trying to go out of bounds, or onto black) is not considered a step, but a slide into or out of a while block is. Returns the step count number, or undef if the step terminates the program.
- $piet->debug(1);
-
Turns debugging information on or off.
- $piet->warn(1);
-
Turns warnings on or off.
- $piet->trace(1);
-
Turns program instruction tracing on or off.
- $piet->codel_size(5);
-
Sets or returns the codel size for the program image.
- $piet->nonstandard('white');
-
Sets the behavior of non-standard codels to 'white' or 'black'.
- $rows = $piet->rows;
-
Returns the number of codel rows in the program image.
- $cols = $piet->rows;
-
Returns the number of codel columns in the program image.
- $file = $piet->rows;
-
Returns the name of the file from which the program image was loaded.
- $piet->state("CHECK");
-
Prints detailed information about the state of the PVM, with an optional label. Information reported includes the filename, number of codel columns and rows, which debugging, warning, or tracing flags are set, how non-standard colored codels are handled, the step number, the current x and y position of the pointer, the directions of the DP and CC, the last color visited, and the values currently on the stack.
- print $piet->to_text;
-
Returns a nicely formatted text version of the program image's codel matrix, with the filename, codel size, and column/row information.
LANGUAGE CONCEPTS
Colors
Piet uses 20 distinct colors, 18 of which are related cyclically in two ways:
Hue Cycle:
Red -> Yellow -> Cyan -> Blue -> Magenta -> Red
Lightness Cycle:
Light -> Normal -> Dark -> Light
Note that "light" is considered to be one step "darker" than "dark", and vice versa. White and black do not fall into either cycle.
Additional colors (such as orange or brown) may also be used. In the default case, non-standard colors are treated by the PVM (Piet Virtual Machine) as the same as white, so may be used freely wherever white is used. You may also use the nonstandard() method to tell the PVM to treat them the same as black.
Codels
Piet code takes the form of an image made up of the recognised colors. Individual pixels of color are significant in the language, so it is common for programs to be enlarged for viewing so that the details are easily visible. In such enlarged programs, the term "codel" is used to mean a block of color equivalent to a single pixel of code, to avoid confusion with the actual pixels of the enlarged graphic, of which many may make up one codel.
Stack
Piet uses a stack for storage of all data values. Data values exist only as integers, though they may be read in or printed as Unicode character values with the appropriate commands.
Program Execution
The Piet language interpreter begins executing a program in the color block which includes the upper left codel of the program. The interpreter maintains a Direction Pointer (DP), initially pointing to the right. The DP may point either right, left, down or up. The interpreter also maintains a Codel Chooser (CC), initially pointing left. The CC may point either left or right. The directions of the DP and CC will often change during program execution. As it executes the program, the interpreter traverses the color blocks of the program under the following rules:
The interpreter finds the edge of the current color block which is furthest in the direction of the DP. (This edge may be disjoint if the block is of a complex shape.)
The interpreter finds the codel of the current color block on that edge which is furthest to the CC's direction of the DP's direction of travel. (For example, if the DP points downwards, and the CC is to the left, the interpreter looks for the rightmost codel on the edge.)
The interpreter travels from that codel into the color block containing the codel immediately in the direction of the DP.
The interpreter continues doing this until the program terminates.
SYNTAX ELEMENTS
Numbers
Each non-black, non-white color block in a Piet program represents an integer equal to the number of codels in that block. Note that non-positive integers cannot be represented, although they can be constructed with operators. When the interpreter encounters a number, it does not necessarily do anything with it. In particular, it is not automatically pushed on to the stack - there is an explicit command for that.
Black Blocks and Edges
Black color blocks and the edges of the program restrict program flow. If the Piet interpreter attempts to move into a black block or off an edge, it is stopped and the CC is toggled. The interpreter then attempts to move from its current block again. If it fails a second time, the DP is moved clockwise one step. These attempts are repeated, with the CC and DP being changed between alternate attempts. If, after eight attempts the interpreter cannot leave its current color block, there is no way out and the program terminates.
White Blocks
White color blocks are "free" zones through which the interpreter passes unhindered. If it moves from a color block into a white area, the interpreter "slides" through the white codels in the direction of the DP until it reaches a non-white color block. If the interpreter slides into a black block or an edge, it is considered restricted (see above), otherwise it moves into the color block so encountered. Sliding across white blocks does not cause a command to be executed.
Commands
Commands are defined by the transition of color from one color block to the next as the interpreter travels through the program. The number of steps along the Hue Cycle and Lightness Cycle in each transition determine the command executed, as shown in the table below. If the transition between color blocks occurs via a slide across a white block, no command is executed.
- (0 hue steps, 1 step darker) => push
-
Pushes the value of the color block just exited on to the stack. Note: values are not automatically pushed onto the stack - the push operation must be explicitly carried out.
- (0 hue steps, 2 steps darker) => pop
-
Pops the top value off the stack and discards it.
- (1 hue step, 0 steps darker) => add
-
Pops the top two values off the stack, adds them, and pushes the result back on the stack.
- (1 hue step, 1 step darker) => subtract
-
Pops the top two values off the stack, subtracts the top value from the second top value, and pushes the result back on the stack.
- (1 hue step, 2 steps darker) => multiply
-
Pops the top two values off the stack, multiplies them, and pushes the result back on the stack.
- (2 hue steps, 0 steps darker) => divide
-
Pops the top two values off the stack, calculates the integer division of the second top value by the top value, and pushes the result back on the stack.
- (2 hue steps, 1 step darker) => mod
-
Pops the top two values off the stack, calculates the second top value modulo the top value, and pushes the result back on the stack.
- (2 hue steps, 2 steps darker) => not
-
Replaces the top value of the stack with 0 if it is non-zero, and 1 if it is zero.
- (3 hue steps, 0 steps darker) => greater
-
Pops the top two values off the stack, and pushes 1 on to the stack if the second top value is greater than the top value, and pushes 0 if it is not greater.
- (3 hue steps, 1 step darker) => pointer
-
Pops the top value off the stack and rotates the DP clockwise that many steps, or counterclockwise if it is negative.
- (3 hue steps, 2 steps darker) => switch
-
Pops the top value off the stack and toggles the CC that many times.
- (4 hue steps, 0 steps darker) => duplicate
-
Pushes a copy of the top value on the stack on to the stack.
- (4 hue steps, 1 step darker) => roll
-
Pops the top two values off the stack and "rolls" the remaining stack entries to a depth equal to the second value popped, by a number of rolls equal to the first value popped. A single roll to depth nis defined as burying the top value on the stack n deep and bringing all values above it up by 1 place. A negative number of rolls rolls in the opposite direction. A negative depth is an error and the command is ignored.
- (4 hue steps, 2 steps darker) => number_in
-
Reads a character from STDIN as a number, and pushes it on to the stack.
- (5 hue steps, 0 steps darker) => character_in
-
Reads a value from STDIN as a character, and pushes it on to the stack.
- (5 hue steps, 1 step darker) => number_out
-
Pops the top value off the stack and prints it to STDOUT as a number.
- (5 hue steps, 2 steps darker) => character_out
-
Reads a value from STDIN as a character, and pushes it on to the stack.
Any operations which cannot be performed (such as popping values when not enough are on the stack) are simply ignored.
AUTHOR
Marc Majcher (piet-interpreter@majcher.com)