2 # This file is part of Language::Befunge.
3 # Copyright (c) 2001-2009 Jerome Quelin, all rights reserved.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the same terms as Perl itself.
10 package Language
::Befunge
::IP
;
18 use Language
::Befunge
::Vector
;
19 use Storable
qw(dclone);
23 get_position
=> 'position',
31 get_storage
=> 'storage',
32 get_string_mode
=> 'string_mode',
36 set_position
=> 'position',
43 set_storage
=> 'storage',
44 set_string_mode
=> 'string_mode',
52 my ($class, $dims) = @_;
53 $dims = 2 unless defined $dims;
59 position
=> Language
::Befunge
::Vector
->new_zeroes($dims),
60 delta
=> Language
::Befunge
::Vector
->new_zeroes($dims),
61 storage
=> Language
::Befunge
::Vector
->new_zeroes($dims),
65 libs
=> { map { $_=>[] } 'A'..'Z' },
68 $self->{delta
}->set_component(0, 1);
70 $self->set_id( $self->_get_new_id );
76 my $clone = dclone
( $self );
77 $clone->set_id( $self->_get_new_id );
87 # Remember, the Stack Stack is up->bottom.
88 @_ and $self->get_ss->[0] = shift;
89 return $self->get_ss->[0];
95 return scalar @
{ $self->get_toss };
100 push @
{ $self->get_toss }, @_;
106 $self->spush($v->get_all_components);
112 foreach my $arg ( @_ ) {
114 ( ($arg =~ /^-?\d+$/) ?
116 : reverse map {ord} split //, $arg.chr(0) # A string.
123 my $val = pop @
{ $self->get_toss };
124 defined $val or $val = 0;
129 my ($self, $count) = @_;
130 my @rv = reverse map { $self->spop() } (1..$count);
136 return Language
::Befunge
::Vector
->new($self->spop_mult($self->get_dims));
143 $val = pop @
{ $self->get_toss };
144 defined $val or $val = 0;
146 } while( $val != 0 );
147 chop $str; # Remove trailing \0.
153 $self->set_toss( [] );
157 my ($self, $idx) = @_;
159 $idx = - abs( $idx );
160 return 0 unless exists $self->get_toss->[$idx];
161 return $self->get_toss->[$idx];
166 return scalar( @
{ $self->get_ss } );
170 my ( $self, $n ) = @_;
175 # Push zeroes on *current* toss (to-be soss).
176 $self->spush( (0) x
abs($n) );
178 my $c = $n - $self->scount;
181 @new_toss = splice @
{ $self->get_toss }, -$n;
183 # Transfer elems and fill with zeroes.
184 @new_toss = ( (0) x
$c, @
{ $self->get_toss } );
188 # $n == 0: do nothing
191 # Push the former TOSS on the stack stack and copy reference to
193 # For commodity reasons, the Stack Stack is oriented up->bottom
194 # (that is, a push is an unshift, and a pop is a shift).
195 unshift @
{ $self->get_ss }, $self->get_toss;
196 $self->set_toss( \
@new_toss );
200 my ( $self, $n ) = @_;
203 # Remember, the Stack Stack is up->bottom.
204 my $new_toss = shift @
{ $self->get_ss };
208 if ( scalar(@
$new_toss) >= abs($n) ) {
209 splice @
$new_toss, $n;
214 my $c = $n - $self->scount;
217 push @
$new_toss, splice( @
{ $self->get_toss }, -$n );
219 # Transfer elems and fill with zeroes.
220 push @
$new_toss, ( (0) x
$c, @
{ $self->get_toss } );
223 # $n == 0: do nothing
226 # Store the new TOSS.
227 $self->set_toss( $new_toss );
235 # Transfer from SOSS to TOSS.
236 my $c = $n - $self->soss_count;
239 @elems = splice @
{ $self->soss }, -$n;
241 @elems = ( (0) x
$c, @
{ $self->soss } );
244 $self->spush( reverse @elems );
248 # Transfer from TOSS to SOSS.
249 my $c = $n - $self->scount;
252 @elems = splice @
{ $self->get_toss }, -$n;
254 @elems = ( (0) x
$c, @
{ $self->get_toss } );
257 $self->soss_push( reverse @elems );
265 my @sizes = ( $self->scount );
267 # Store the size of each stack.
268 foreach my $i ( 1..$self->ss_count ) {
269 push @sizes, scalar @
{ $self->get_ss->[$i-1] };
278 return scalar( @
{ $self->soss } );
283 push @
{ $self->soss }, @_;
288 my ($self, $count) = @_;
289 my @rv = reverse map { $self->soss_pop() } (1..$count);
296 $self->soss_push($v->get_all_components);
302 my $val = pop @
{ $self->soss };
303 defined $val or $val = 0;
309 return Language
::Befunge
::Vector
->new($self->soss_pop_mult($self->get_dims));
321 $self->get_delta->clear;
322 $self->get_delta->set_component(0, 1);
327 $self->get_delta->clear;
328 $self->get_delta->set_component(0, -1);
333 $self->get_delta->clear;
334 $self->get_delta->set_component(1, -1);
339 $self->get_delta->clear;
340 $self->get_delta->set_component(1, 1);
345 $self->get_delta->clear;
346 $self->get_delta->set_component(2, 1);
351 $self->get_delta->clear;
352 $self->get_delta->set_component(2, -1);
357 my $nd = $self->get_dims;
358 my $dim = (0..$nd-1)[int(rand $nd)];
359 $self->get_delta->clear;
360 my $value = (-1, 1)[int(rand 2)];
361 $self->get_delta->set_component($dim, $value);
366 my $old_dx = $self->get_delta->get_component(0);
367 my $old_dy = $self->get_delta->get_component(1);
368 $self->get_delta->set_component(0, 0 + $old_dy);
369 $self->get_delta->set_component(1, 0 + $old_dx * -1);
374 my $old_dx = $self->get_delta->get_component(0);
375 my $old_dy = $self->get_delta->get_component(1);
376 $self->get_delta->set_component(0, 0 + $old_dy * -1);
377 $self->get_delta->set_component(1, 0 + $old_dx);
382 $self->set_delta(-$self->get_delta);
386 my ($self, $lib) = @_;
388 my $libs = $self->get_libs;
389 foreach my $letter ( 'A' .. 'Z' ) {
390 next unless $lib->can($letter);
391 push @
{ $libs->{$letter} }, $lib;
396 my ($self, $lib) = @_;
398 my $libs = $self->get_libs;
399 foreach my $letter ( 'A' .. 'Z' ) {
400 next unless $lib->can($letter);
401 pop @
{ $libs->{$letter} };
408 @_ ?
$self->get_data->{$lib} = shift : $self->get_data->{$lib};
415 # my $id = _get_new_id;
417 # Forge a new IP id, that will distinct it from the other IPs of the program.
429 Language::Befunge::IP - an Instruction Pointer for a Befunge-98 program.
435 This is the class implementing the Instruction Pointers. An
436 Instruction Pointer (aka IP) has a stack, and a stack of stacks that
437 can be manipulated via the methods of the class.
439 We need a class, since this is a concurrent Befunge, so we can have
440 more than one IP travelling on the Lahey space.
446 =head2 my $ip = LB::IP->new( [$dimensions] )
448 Create a new Instruction Pointer, which operates in a universe of the given
449 C<$dimensions>. If C<$dimensions> is not specified, it defaults to 2
453 =head2 my $clone = $ip->clone()
455 Clone the current Instruction Pointer with all its stacks, position,
456 delta, etc. Change its unique ID.
464 The following is a list of attributes of a Language::Befunge::IP
465 object. For each of them, a method C<get_foobar> and C<set_foobar>
471 =item $ip->get_id() / $ip->set_id($id)
473 The unique ID of the IP (an integer). Don't set the ID yourself.
476 =item $ip->get_dims()
478 The number of dimensions this IP operates in (an integer). This is
482 =item $ip->get_position() / $ip->set_position($vec)
484 The current coordinates of the IP (a C<Language::Befunge::Vector>
488 =item $ip->get_delta() / $ip->set_delta($vec)
490 The velocity of the IP (a C<Language::Befunge::Vector> object).
493 =item $ip->get_storage() / $ip->set_storage($vec)
495 The coordinates of the storage offset of the IP (a
496 C<Language::Befunge::Vector> object).
499 =item $ip->get_data() / $ip->set_data({})
501 The library private storage space (a hash reference). Don't set this
503 FIXME: not supposed to be accessible
506 =item $ip->get_string_mode() / set_string_mode($bool)
508 The string_mode of the IP (a boolean).
511 =item $ip->get_end() / $ip->set_end($bool)
513 Whether the IP should be terminated (a boolean).
516 =item $ip->get_libs() / $ip->set_libs($aref)
518 The current stack of loaded libraries (an array reference). Don't set
520 FIXME: not supposed to be accessible
523 =item $ip->get_ss() / $ip->set_ss($aref)
525 The stack of stack of the IP (an array reference). Don't set this
527 FIXME: not supposed to be accessible
530 =item $ip->get_toss() / $ip->set_toss($aref)
532 The current stack (er, TOSS) of the IP (an array reference). Don't set
534 FIXME: not supposed to be accessible
540 =head2 $ip->soss([$])
546 =head1 PUBLIC METHODS
548 =head2 Internal stack
550 In this section, I speak about the stack. In fact, this is the TOSS - that
551 is, the Top Of the Stack Stack.
553 In Befunge-98, standard stack operations occur transparently on the
554 TOSS (as if there were only one stack, as in Befunge-93).
561 Return the number of elements in the stack.
566 Push a value on top of the stack.
569 =item spush_vec( vector )
571 Push a vector on top of the stack. The x coordinate is pushed first.
574 =item spush_args ( arg, ... )
576 Push a list of argument on top of the stack (the first argument will
577 be the deeper one). Convert each argument: a number is pushed as is,
578 whereas a string is pushed as a 0gnirts.
580 B</!\> Do B<not> push references or weird arguments: this method
581 supports only numbers (positive and negative) and strings.
586 Pop a value from the stack. If the stack is empty, no error occurs and
587 the method acts as if it popped a 0.
590 =item spop_mult( <count> )
592 Pop multiple values from the stack. If the stack becomes empty, the
593 remainder of the returned values will be 0.
598 Pop a vector from the stack. Returns a Vector object.
603 Pop a 0gnirts string from the stack.
611 =item svalue( offset )
613 Return the C<offset>th value of the TOSS, counting from top of the
614 TOSS. The offset is interpreted as a negative value, that is, a call
615 with an offset of C<2> or C<-2> would return the second value on top
624 This section discusses about the stack stack. We can speak here about
625 TOSS (Top Of Stack Stack) and SOSS (second on stack stack).
631 Return the number of stacks in the stack stack. This of course does
632 not include the TOSS itself.
636 =item ss_create( count )
638 Push the TOSS on the stack stack and create a new stack, aimed to be
639 the new TOSS. Once created, transfer C<count> elements from the SOSS
640 (the former TOSS) to the TOSS. Transfer here means move - and B<not>
641 copy -, furthermore, order is preserved.
643 If count is negative, then C<count> zeroes are pushed on the new TOSS.
646 =item ss_remove( count )
648 Move C<count> elements from TOSS to SOSS, discard TOSS and make the
649 SOSS become the new TOSS. Order of elems is preserved.
652 =item ss_transfer( count )
654 Transfer C<count> elements from SOSS to TOSS, or from TOSS to SOSS if
655 C<count> is negative; the transfer is done via pop/push.
657 The order is not preserved, it is B<reversed>.
662 Return a list with all the sizes of the stacks in the stack stack
663 (including the TOSS), from the TOSS to the BOSS.
668 Return the number of elements in SOSS.
671 =item soss_push( value )
673 Push a value on top of the SOSS.
676 =item soss_pop_mult( <count> )
678 Pop multiple values from the SOSS. If the stack becomes empty, the
679 remainder of the returned values will be 0.
682 =item soss_push_vec( vector )
684 Push a vector on top of the SOSS.
690 Pop a value from the SOSS. If the stack is empty, no error occurs and
691 the method acts as if it popped a 0.
694 =item soss_pop_vec( )
696 Pop a vector from the SOSS. If the stack is empty, no error occurs
697 and the method acts as if it popped a 0. returns a Vector.
708 =head2 Changing direction
714 Implements the C<E<gt>> instruction. Force the IP to travel east.
719 Implements the C<E<lt>> instruction. Force the IP to travel west.
722 =item dir_go_north( )
724 Implements the C<^> instruction. Force the IP to travel north.
726 Not valid for Unefunge.
729 =item dir_go_south( )
731 Implements the C<v> instruction. Force the IP to travel south.
733 Not valid for Unefunge.
738 Implements the C<h> instruction. Force the IP to travel up.
740 Not valid for Unefunge or Befunge.
745 Implements the C<l> instruction. Force the IP to travel down.
747 Not valid for Unefunge or Befunge.
752 Implements the C<?> instruction. Cause the IP to travel in a random
753 cardinal direction (in Befunge's case, one of: north, south, east or
757 =item dir_turn_left( )
759 Implements the C<[> instruction. Rotate by 90 degrees on the left the
760 delta of the IP which encounters this instruction.
762 Not valid for Unefunge. For Trefunge and greater, only affects the
766 =item dir_turn_right( )
768 Implements the C<]> instruction. Rotate by 90 degrees on the right the
769 delta of the IP which encounters this instruction.
771 Not valid for Unefunge. For Trefunge and higher dimensions, only
772 affects the X and Y axes.
778 Implements the C<r> instruction. Reverse the direction of the IP, that
779 is, multiply the IP's delta by -1.
785 =head2 Libraries semantics
791 Load the given library semantics. The parameter is an extension object
792 (a library instance).
798 Unload the given library semantics. The parameter is the library name.
800 Return the library name if it was correctly unloaded, undef otherwise.
802 B</!\> If the library has been loaded twice, this method will only
803 unload the most recent library. Ie, if an IP has loaded the libraries
804 ( C<FOO>, C<BAR>, C<FOO>, C<BAZ> ) and one calls C<unload( "FOO" )>,
805 then the IP will follow the semantics of C<BAZ>, then C<BAR>, then
809 =item extdata( library, [value] )
811 Store or fetch a value in a private space. This private space is
812 reserved for libraries that need to store internal values.
814 Since in Perl references are plain scalars, one can store a reference
815 to an array or even a hash.
824 L<Language::Befunge>.
829 Jerome Quelin, E<lt>jquelin@cpan.orgE<gt>
833 =head1 COPYRIGHT & LICENSE
835 Copyright (c) 2001-2009 Jerome Quelin, all rights reserved.
837 This program is free software; you can redistribute it and/or modify
838 it under the same terms as Perl itself.