2 # This file is part of Language::Befunge.
3 # Copyright (c) 2001-2008 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
::Vector
;
18 '-' => \
&vector_subtract
,
19 'neg' => \
&vector_invert
,
21 '+=' => \
&vector_add_inplace
,
23 '==' => \
&vector_equality
,
24 '!=' => \
&vector_inequality
,
25 '""' => \
&vector_as_string
;
31 # my $v = new( $dimensions, $x, [$y, ...] )
33 # Creates a new vector. The first argument is an integer specifying how
34 #many dimensions this vector operates in. The remaining arguments constitute
35 #the actual vector data; one integer per dimension.
39 my $dimensions = shift;
40 my $usage = "Usage: $package->new(\$dimensions, \$x, ...)";
41 croak
$usage unless defined $dimensions;
42 croak
$usage unless $dimensions > 0;
43 croak
$usage unless $dimensions == scalar @_;
44 return bless({dims
=> $dimensions, v
=> [@_]}, $package);
49 # new_zeroes( dimensions )
51 # Creates a new vector, set to the origin (all zeroes). ->new_zeroes(2) is
52 #exactly equivalent to ->new(2, 0, 0).
56 my $dimensions = shift;
57 my $usage = "Usage: $package->new_zeroes(\$dimensions)";
58 croak
$usage unless defined $dimensions;
59 croak
$usage unless $dimensions > 0;
61 push(@initial,0) for(1..$dimensions);
62 return bless({dims
=> $dimensions, v
=> [@initial]}, $package);
69 # my $dims = get_dims( )
71 # Returns the number of dimensions, an integer.
80 # vector_subtract( v2 )
82 # $v0 = $v1->vector_subtract($v2);
85 # Returns a new Vector object, which is the result of v1 minus v2.
89 croak
"uneven dimensions in vector subtraction!" unless $v1->get_dims == $v2->get_dims;
90 my $vr = ref($v1)->new_zeroes($v1->get_dims);
91 for(my $i = 0; $i < $v1->get_dims; $i++) {
92 $$vr{v
}[$i] = $$v1{v
}[$i] - $$v2{v
}[$i];
101 # $v1->vector_invert();
104 # Subtracts v1 from the origin. Effectively, gives the inverse of the
105 # original vector. The new vector is the same distance from the origin,
106 #in the opposite direction.
110 my $rv = ref($v1)->new_zeroes($v1->get_dims);
111 for(my $i = 0; $i < $v1->get_dims; $i++) {
112 $$rv{v
}[$i] = -$$v1{v
}[$i];
121 # $v0 = $v1->vector_add($v2);
124 # Returns a new Vector object, which is the result of v1 plus v2.
128 croak
"uneven dimensions in vector addition!" unless $v1->get_dims == $v2->get_dims;
129 my $rv = ref($v1)->new_zeroes($v1->get_dims);
130 for(my $i = 0; $i < $v1->get_dims; $i++) {
131 $$rv{v
}[$i] = $$v1{v
}[$i] + $$v2{v
}[$i];
138 # vector_add_inplace( v2 )
140 # $v1->vector_add_inplace($v2);
143 # Adds v2 to v1, and stores the result back into v1.
145 sub vector_add_inplace
{
147 croak
"uneven dimensions in vector addition!" unless $v1->get_dims == $v2->get_dims;
148 for(my $i = 0; $i < $v1->get_dims; $i++) {
149 $$v1{v
}[$i] += $$v2{v
}[$i];
158 # $v0 = $v1->vector_copy();
161 # Returns a new Vector object, which has the same dimensions and coordinates as v1.
165 return bless {dims
=> $$v{dims
}, v
=> [@
{$$v{v
}}]}, ref $v;
170 # set_component( dimension, data )
172 # $v->set_component(0, 1); # set X to 1
174 # Sets the value for dimension dimension to the value data.
177 my ($self, $d, $data) = @_;
178 croak
"No such dimension $d!" unless ($d >= 0 && $self->get_dims > $d);
179 $$self{v
}[$d] = $data;
184 # get_component( dimension )
186 # my $x = $v->get_component(0);
188 # Gets the value for dimension dimension.
192 croak
"No such dimension $d!" unless ($d >= 0 && $self->get_dims > $d);
193 return $$self{v
}[$d];
198 # get_all_components( )
200 # my $v = Language::Befunge::Vector->new(3, 1, 2, 3);
201 # # $v now holds a 3-dimensional vector, <1,2,3>
202 # my @list = $v->get_all_components(); # returns (1, 2, 3)
204 # Gets the value for all dimensions, in order from 0..N.
206 sub get_all_components
{
215 # Sets the vector back to the origin, all 0's. See also the constructor,
216 # new_from_origin, above.
220 @
{$$self{v
}} = map { 0 } (1..$self->get_dims);
225 # bounds_check( begin, end )
227 # die "out of bounds"
228 # unless $vector->bounds_check($begin, $end);
230 # Checks whether the given vector is within the box defined by begin and end.
231 # Returns 1 if vector is contained within the box, and 0 otherwise.
234 my ($vchk, $begin, $end) = @_;
235 croak
"uneven dimensions in bounds check!" unless $vchk->get_dims == $begin->get_dims;
236 croak
"uneven dimensions in bounds check!" unless $vchk->get_dims == $end->get_dims;
237 for(my $d = 0; $d < $vchk->get_dims; $d++) {
238 return 0 if $vchk->get_component($d) < $begin->get_component($d);
239 return 0 if $vchk->get_component($d) > $end->get_component($d);
246 # vector_as_string( )
248 # Returns the stringified form of the vector. For instance, a Befunge vector might look like "(1,2)".
250 sub vector_as_string
{
252 return "(" . join(",",@
{$$self{v
}}) . ")";
257 # vector_equality( v2 )
259 # print("Equal!\n") if $v1->vector_equality($v2);
260 # print("Equal!\n") if $v1 == $v2;
262 # Checks whether the vectors both point at the same spot. Returns 1 if they
263 # do, 0 if they don't.
265 sub vector_equality
{
267 croak
"uneven dimensions in bounds check!" unless $v1->get_dims == $v2->get_dims;
268 for(my $d = 0; $d < $v1->get_dims; $d++) {
269 return 0 unless $v1->get_component($d) == $v2->get_component($d);
276 # vector_inequality( v2 )
278 # print("Equal!\n") unless $v1->vector_inequality($v2);
279 # print("Equal!\n") unless $v1 != $v2;
281 # Checks whether the vectors point to different spots. Returns 1 if they
282 # don't, 0 if they do. Compare vector_equality, above.
284 sub vector_inequality
{
285 return !vector_equality
(@_);
293 Language::Befunge::Vector - an opaque, N-dimensional vector class.
298 my $v1 = Language::Befunge::Vector->new($d, $x, $y, ...);
299 my $v2 = Language::Befunge::Vector->new_zeroes($d);
303 This class abstracts normal vector manipulation. It lets you pass
304 around one argument to your functions, rather than N arguments, one
305 per dimension. This means much of your code doesn't have to care
306 how many dimensions you're working with.
308 You can do vector arithmetic, test for equality, or even stringify
309 the vector to a string like I<"(1,2,3)">.
314 =head2 new( dimensions, x, [y, ...] )
316 Creates a new vector. The first argument is an integer specifying
317 how many dimensions this vector operates in. The remaining arguments
318 constitute the actual vector data; one integer per dimension.
321 =head2 new_zeroes( dimensions )
323 Creates a new vector, set to the origin (all zeroes).
324 ->B<new_zeroes>(2) is exactly equivalent to ->B<new>(2, 0, 0).
327 =head1 PUBLIC METHODS
331 Returns the number of dimensions, an integer.
334 =head2 vector_subtract( v2 )
336 $v0 = $v1->vector_subtract($v2);
339 Returns a new Vector object, which is the result of I<v1> minus I<v2>.
342 =head2 vector_invert( )
344 $v1->vector_invert();
347 Subtracts I<v1> from the origin. Effectively, gives the inverse of
348 the original vector. The new vector is the same distance from the
349 origin, in the opposite direction.
352 =head2 vector_add( v2 )
354 $v0 = $v1->vector_add($v2);
357 Returns a new Vector object, which is the result of I<v1> plus I<v2>.
360 =head2 vector_add_inplace( v2 )
362 $v1->vector_add_inplace($v2);
365 Adds I<v2> to I<v1>, and stores the result back into I<v1>.
368 =head2 vector_copy( )
370 $v0 = $v1->vector_copy();
373 Returns a new Vector object, which has the same dimensions and
374 coordinates as I<v1>.
377 =head2 set_component( dimension, data )
379 $v->set_component(0, 1); # set X to 1
381 Sets the value for dimension I<dimension> to the value I<data>.
384 =head2 get_component( dimension )
386 my $x = $v->get_component(0);
388 Gets the value for dimension I<dimension>.
391 =head2 get_all_components( )
393 my $v = Language::Befunge::Vector->new(3, 1, 2, 3);
394 # $v now holds a 3-dimensional vector, <1,2,3>
395 my @list = $v->get_all_components(); # returns (1, 2, 3)
397 Gets the value for all dimensions, in order from 0..N.
402 Sets the vector back to the origin, all 0's. See also the
403 constructor, B<new_from_origin>, above.
406 =head2 bounds_check( begin, end )
409 unless $vector->bounds_check($begin, $end);
411 Checks whether the given I<vector> is within the box defined by
412 I<begin> and I<end>. Returns I<1> if I<vector> is contained within
413 the box, and I<0> otherwise.
416 =head2 vector_as_string( )
418 Returns the stringified form of the vector. For instance, a Befunge
419 vector might look like I<"(1,2)">.
422 =head2 vector_equality( v2 )
424 print("Equal!\n") if $v1->vector_equality($v2);
425 print("Equal!\n") if $v1 == $v2;
427 Checks whether the vectors both point at the same spot. Returns
428 I<1> if they do, I<0> if they don't.
431 =head2 vector_inequality( v2 )
433 print("Equal!\n") unless $v1->vector_inequality($v2);
434 print("Equal!\n") unless $v1 != $v2;
436 Checks whether the vectors point to different spots. Returns
437 I<1> if they don't, I<0> if they do. Compare B<vector_equality>,
449 Jerome Quelin, E<lt>jquelin@cpan.orgE<gt>
451 Development is discussed on E<lt>language-befunge@mongueurs.netE<gt>
454 =head1 COPYRIGHT & LICENSE
456 Copyright (c) 2001-2008 Jerome Quelin, all rights reserved.
458 This program is free software; you can redistribute it and/or modify
459 it under the same terms as Perl itself.