Piet-Interpreter
view release on metacpan or search on metacpan
Interpreter.pm view on Meta::CPAN
package Piet::Interpreter;
use 5.6.0; # or so.
use strict;
use Carp;
use Image::Magick;
our $VERSION = '0.03';
=head1 NAME
Piet::Interpreter - Interpreter for the Piet programming language
=head1 SYNOPSIS
use Piet::Interpreter;
my $p = Piet::Interpreter->new(image => 'my_code.gif');
$p->run;
=head1 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.
=cut
# Initialize variables and lookup hashes
$| = 1; # buffer bad.
my $HEX_BLACK = '000000';
my $HEX_WHITE = 'FFFFFF';
my %hex2color = ( 'FFC0C0' => 'light red', 'FFFFC0' => 'light yellow',
'C0FFC0' => 'light green', 'C0FFFF' => 'light cyan',
'C0C0FF' => 'light blue', 'FFC0FF' => 'light magenta',
'FF0000' => 'red', 'FFFF00' => 'yellow',
'00FF00' => 'green', '00FFFF' => 'cyan',
'0000FF' => 'blue', 'FF00FF' => 'magenta',
'C00000' => 'dark red', 'C0C000' => 'dark yellow',
'00C000' => 'dark green', '00C0C0' => 'dark cyan',
'0000C0' => 'dark blue', 'C000C0' => 'dark magenta',
'FFFFFF' => 'white', '000000' => 'black',
);
my %hex2abbr = ( 'FFC0C0' => 'lR', 'FFFFC0' => 'lY', 'C0FFC0' => 'lG',
'C0FFFF' => 'lC', 'C0C0FF' => 'lB', 'FFC0FF' => 'lM',
'FF0000' => ' R', 'FFFF00' => ' Y', '00FF00' => ' G',
'00FFFF' => ' C', '0000FF' => ' B', 'FF00FF' => ' M',
'C00000' => 'dR', 'C0C000' => 'dY', '00C000' => 'dG',
'00C0C0' => 'dC', '0000C0' => 'dB', 'C000C0' => 'dM',
'FFFFFF' => 'Wt', '000000' => 'Bk',
);
my %hex2hue = ( 'FFC0C0' => 0, 'FFFFC0' => 1, 'C0FFC0' => 2,
'C0FFFF' => 3, 'C0C0FF' => 4, 'FFC0FF' => 5,
'FF0000' => 0, 'FFFF00' => 1, '00FF00' => 2,
'00FFFF' => 3, '0000FF' => 4, 'FF00FF' => 5,
'C00000' => 0, 'C0C000' => 1, '00C000' => 2,
'00C0C0' => 3, '0000C0' => 4, 'C000C0' => 5,
'FFFFFF' => -1, '000000' => -1,
);
my %hex2light = ( 'FFC0C0' => 0, 'FFFFC0' => 0, 'C0FFC0' => 0,
'C0FFFF' => 0, 'C0C0FF' => 0, 'FFC0FF' => 0,
'FF0000' => 1, 'FFFF00' => 1, '00FF00' => 1,
'00FFFF' => 1, '0000FF' => 1, 'FF00FF' => 1,
'C00000' => 2, 'C0C000' => 2, '00C000' => 2,
'00C0C0' => 2, '0000C0' => 2, 'C000C0' => 2,
'FFFFFF' => -1, '000000' => -1,
);
my @do_arr = (
[ 'do_noop', 'do_push', 'do_pop' ],
[ 'do_add', 'do_subtract', 'do_multiply' ],
[ 'do_divide', 'do_mod', 'do_not' ],
[ 'do_greater', 'do_pointer', 'do_switch' ],
[ 'do_duplicate', 'do_roll', 'do_in_n' ],
[ 'do_in_c', 'do_out_n', 'do_out_c' ],
);
Interpreter.pm view on Meta::CPAN
# The Instantiator. Returns a new interpreter object, ready to go.
# Accepts flags to initialize properties on creation.
my ($class, %args) = @_;
my $self = bless {
_image => undef,
_filename => undef,
_rows => undef,
_cols => undef,
_matrix => undef,
_codel_size => $args{codel_size} || 1,
_debug => $args{debug} || 0,
_trace => $args{trace} || 0,
_warn => $args{warn} || 0,
_nonstandard => $args{nonstandard} || 'white',
}, ref($class) || $class;
$self->reset;
$self->image($args{image}) if $args{image};
return $self;
}
=item $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.
=cut
sub reset {
# usage: $piet->reset;
#
# Resets the PVM (Piet Virtual Machine) back to the initial state.
my $self = shift;
$self->{_dp} = 0; # Direction Pointer: 0=right, 1=down, 2=left, 3=up
$self->{_cc} = -1; # Codel Chooser: -1=left, 1=right
$self->{_cx} = 0; # Current x position
$self->{_cy} = 0; # Current y position
$self->{_stack} = [];
$self->{_change_flag} = 0;
$self->{_step_number} = undef;
$self->{_current_block} = undef;
$self->{_block_value} = undef;
$self->{_last_color} = $self->matrix($self->{_cx},$self->{_cy});
}
=item $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.
=cut
sub image {
# usage: $piet->image('myprog.gif');
#
# Loads in an image from a file to use as the Piet program. Inspects
# the image, and generates properties and the run matrix from it.
my ($self, $file) = @_;
unless (defined $file) {
carp "No image file given in Piet::Interpreter::image()";
return;
}
unless (-e $file) {
carp "File $file does not exist in Piet::Interpreter::image()";
return;
}
# Read file into object and process
$self->{_filename} = $file;
$self->{_image} = Image::Magick->new;
$self->{_image}->Read($file);
$self->_process_image;
}
=item $piet->run;
Starts the Piet interpreter running from the upper-left codel.
Program execution is described under "Language Concepts", below.
=cut
sub run {
# usage: $piet->run;
#
# This is where the magic happens. We initialize the PVM, and
# start running through the program image.
my $self = shift;
return unless $self->{_matrix};
$self->reset;
print $self->to_text if $self->{_debug};
# starting at the upper left, start stepping through the codel blocks
while (1) {
$self->{_step_number} = $self->step;
last unless $self->{_step_number};
}
$self->_debug("\nEnd Of Line.");
}
=item $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.
=cut
sub step {
# usage: $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.
my $self = shift;
$self->_process_current_block;
$self->{_step_number}++;
$self->_debug("\n-- STEP: $self->{_step_number}");
( run in 2.505 seconds using v1.01-cache-2.11-cpan-5837b0d9d2c )