| Array-Tour documentation | Contained in the Array-Tour distribution. |
Array::Tour::Serpentine - Return coordinates to take a serpentine path.
use Array::Tour::Serpentine qw(:directions);
my $tour = Array::Tour::Serpentine->new(
dimensions => [5, 5],
vertical => $vertical,
corner_right => $corner_right,
corner_bottom => $corner_bottom);
Creates the object with its attributes. The attributes dimensions, offset, start, and position are inherited from Array::Tour. This package adds more attributes of its own, which are:
Default values: 0. All are boolean values that affect the starting point and the direction of the tour. By default, the tour is generated the upper left corner in a horizontal back-and-forth path.
See the Examples section to see what effects the different combinations produce.
Perl 5.8 or later. This is the version of perl under which this module was developed.
A simple iterator that will return the coordinates of the next cell if one were to tour an array's cells in a serpentine path.
$dir = $tour->direction() Return the direction we just walked. Overrides Array::Tour's direction() method. =cut
Returns a reference to an array of coordinates. Returns undef if there is no next cell to visit.
Overrides Array::Tour's next() method.
$ruot = $tour->opposite();
Return a new object that follows the same path as the original object, reversing the inward/outward direction.
$self->_set(%parameters); Override Array::Tour's _set() method for one that can handle our parameters. =cut
The four by four case demonstrates the different possible arrangements.
There are four possible central positions. By default, the tour will
begin in the top left corner, but the options corner_bottom and
corner_right can force the starting point to a different corner of
the square.
The :directions and :status EXPORT tags are available, as defined in Array::Tour.
John M. Gamble may be found at <jgamble@cpan.org>
| Array-Tour documentation | Contained in the Array-Tour distribution. |
package Array::Tour::Serpentine; use 5.008; use strict; use warnings; use integer; use base q(Array::Tour); use Array::Tour qw(:directions :status); our $VERSION = '0.06';
sub direction() { my $self = shift; return ($self->{status} == STOP)? undef: ${$self->{direction}}[0]; }
sub next { my $self = shift; return undef unless ($self->has_next()); # # Set up the conditions for the pacing. # if ($self->{tourstatus} == START) { $self->{tourstatus} = TOURING; $self->{pacer} = ${$self->{pacing}}[0]; } else { # # Pace off in the current direction. # my $direction = ${$self->{direction}}[0]; ${$self->{position}}[(($direction & (North | South)) == 0)? 0: 1] += (($direction & (North | West)) == 0)? 1: -1; # # Will the next pace be in a different direction? # if (--$self->{pacer} == 0) { $self->{pacer} = ${$self->{pacing}}[1]; ${$self->{pacing}}[0] += $self->{pacechange}; # # Rotate to the next pacing length and the next direction. # push @{$self->{pacing}}, shift @{$self->{pacing}}; push @{$self->{direction}}, shift @{$self->{direction}}; } } $self->{tourstatus} = STOP if (++$self->{odometer} == $self->{tourlength}); return $self->adjusted_position(); }
sub opposite() { my $self = shift; my %anti_self; my @dimensions = @{ $self->{dimensions} }; $anti_self{dimensions} = $self->{dimensions}; $anti_self{corner_right} ^= 1; $anti_self{corner_bottom} ^= 1; return Array::Tour::Serpentine->new(%anti_self); }
sub _set() { my $self = shift; my(%params) = @_; my($pace_x, $pace_y) = (1, 1); my($start_x, $start_y) = (0, 0); my @dirlist = (East, South, West, North); my @dimensions = @{$self->{dimensions}}; my @direction; warn "Unknown paramter $_" foreach (grep{$_ !~ /vertical|corner_right|corner_bottom/} (keys %params)); # # Parameter checks. # # Set corner_right, corner_bottom, and vertical to 0/1 values. # my $vertical = (defined $params{vertical} and $params{vertical} != 0)? 1: 0; my $corner_right = (defined $params{corner_right} and $params{corner_right} != 0)? 1: 0; my $corner_bottom = (defined $params{corner_bottom} and $params{corner_bottom} != 0)? 1: 0; $pace_x = $dimensions[0] - 1 unless ($vertical); $pace_y = $dimensions[1] - 1 if ($vertical); $start_x = $dimensions[0] - 1 if ($corner_right); $start_y = $dimensions[1] - 1 if ($corner_bottom); my $idx0 = ((($corner_bottom & $vertical)| ($corner_right & ($vertical^1))) << 1) | $vertical; my $idx1 = ((($corner_bottom & ($vertical^1))| ($corner_right & $vertical)) << 1) | ($vertical ^ 1); push @direction, @dirlist[$idx0, $idx1, $idx0 ^ 2, $idx1]; $self->{corner_right} = $corner_right; $self->{corner_bottom} = $corner_bottom; $self->{vertical} = $vertical; $self->{direction} = \@direction; $self->{pacechange} = 0; $self->{pacing} = (($direction[0] & (West | East)) == 0)? [$pace_y, $pace_x]: [$pace_x, $pace_y]; $self->{start} = [$start_x, $start_y]; $self->{position} = [$start_x, $start_y]; return $self; } 1; __END__