line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Array::Tour - Base class for Array Tours. |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# For a new package. Add extra methods and internal attributes afterwards. |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
package Array::Tour::NewTypeOfTour |
11
|
|
|
|
|
|
|
use base qw(Array::Tour); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# (Code goes here). |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
or |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# |
18
|
|
|
|
|
|
|
# Make use of the constants in the package. |
19
|
|
|
|
|
|
|
# |
20
|
|
|
|
|
|
|
use Array::Tour qw(:directions); |
21
|
|
|
|
|
|
|
use Array::Tour qw(:status); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
or |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# |
26
|
|
|
|
|
|
|
# Use Array::Tour for its default 'typewriter' tour of the array. |
27
|
|
|
|
|
|
|
# |
28
|
|
|
|
|
|
|
use Array::Tour; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
my $by_row = Array::Tour->new(dimensions => [24, 80, 1]); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 PREREQUISITES |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
Perl 5.8 or later. This is the version of perl under which this module |
36
|
|
|
|
|
|
|
was developed. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 DESCRIPTION |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Array::Tour is a base class for iterators that traverse the cells of an |
41
|
|
|
|
|
|
|
array. This class should provide most of the methods needed for any type |
42
|
|
|
|
|
|
|
of tour, whether it needs to visit each cell or not, and whether |
43
|
|
|
|
|
|
|
the tour needs to be a continuous path or not. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
The iterator provides coordinates and directions. It does not define |
46
|
|
|
|
|
|
|
the array. This leaves the user of the tour object free to |
47
|
|
|
|
|
|
|
define the form of the array or the data structure behind it without |
48
|
|
|
|
|
|
|
restrictions from the tour object. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
By itself without any subclassing or options, the Array::Tour class traverses a |
51
|
|
|
|
|
|
|
simple left-to-right, top-to-bottom typewriter path. There are options to change |
52
|
|
|
|
|
|
|
the direction or rotation of the path. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
package Array::Tour; |
57
|
9
|
|
|
9
|
|
14829
|
use 5.008; |
|
9
|
|
|
|
|
33
|
|
|
9
|
|
|
|
|
362
|
|
58
|
9
|
|
|
9
|
|
49
|
use strict; |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
258
|
|
59
|
9
|
|
|
9
|
|
58
|
use warnings; |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
334
|
|
60
|
9
|
|
|
9
|
|
841
|
use integer; |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
43
|
|
61
|
|
|
|
|
|
|
|
62
|
9
|
|
|
9
|
|
342
|
use vars qw(@ISA); |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
889
|
|
63
|
|
|
|
|
|
|
require Exporter; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
66
|
|
|
|
|
|
|
|
67
|
9
|
|
|
9
|
|
53
|
use vars qw(%EXPORT_TAGS @EXPORT_OK); |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
1515
|
|
68
|
|
|
|
|
|
|
%EXPORT_TAGS = ( |
69
|
|
|
|
|
|
|
'directions' => [ qw ( NoDirection |
70
|
|
|
|
|
|
|
North NorthWest West SouthWest Ceiling |
71
|
|
|
|
|
|
|
South SouthEast East NorthEast Floor |
72
|
|
|
|
|
|
|
SetPosition |
73
|
|
|
|
|
|
|
)], |
74
|
|
|
|
|
|
|
'status' => [ qw (START TOURING STOP)] |
75
|
|
|
|
|
|
|
); |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
@EXPORT_OK = ( @{ $EXPORT_TAGS{'directions'} }, @{ $EXPORT_TAGS{'status'} } ); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
our $VERSION = '0.06'; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# |
82
|
|
|
|
|
|
|
# Directions. |
83
|
|
|
|
|
|
|
# |
84
|
|
|
|
|
|
|
# The eight possible directions that one can move from a cell, including |
85
|
|
|
|
|
|
|
# "null" direction NoDirection, and position change indicator SetPosition. |
86
|
|
|
|
|
|
|
# |
87
|
9
|
|
|
9
|
|
46
|
use constant NoDirection => 0x0000; |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
1462
|
|
88
|
9
|
|
|
9
|
|
46
|
use constant North => 0x0001; # 0; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
509
|
|
89
|
9
|
|
|
9
|
|
43
|
use constant NorthWest => 0x0002; # 1; |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
485
|
|
90
|
9
|
|
|
9
|
|
47
|
use constant West => 0x0004; # 2; |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
332
|
|
91
|
9
|
|
|
9
|
|
44
|
use constant SouthWest => 0x0008; # 3; |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
370
|
|
92
|
9
|
|
|
9
|
|
44
|
use constant Ceiling => 0x0010; # 4; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
391
|
|
93
|
9
|
|
|
9
|
|
44
|
use constant South => 0x0020; # 5; |
|
9
|
|
|
|
|
24
|
|
|
9
|
|
|
|
|
373
|
|
94
|
9
|
|
|
9
|
|
51
|
use constant SouthEast => 0x0040; # 6; |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
356
|
|
95
|
9
|
|
|
9
|
|
40
|
use constant East => 0x0080; # 7; |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
312
|
|
96
|
9
|
|
|
9
|
|
40
|
use constant NorthEast => 0x0100; # 8; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
391
|
|
97
|
9
|
|
|
9
|
|
52
|
use constant Floor => 0x0200; # 9; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
316
|
|
98
|
9
|
|
|
9
|
|
42
|
use constant SetPosition => 0x8000; # 15; |
|
9
|
|
|
|
|
28
|
|
|
9
|
|
|
|
|
730
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# |
101
|
|
|
|
|
|
|
# {tourstatus} constants. |
102
|
|
|
|
|
|
|
# |
103
|
9
|
|
|
9
|
|
44
|
use constant START => 0; |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
397
|
|
104
|
9
|
|
|
9
|
|
40
|
use constant TOURING => 1; |
|
9
|
|
|
|
|
93
|
|
|
9
|
|
|
|
|
336
|
|
105
|
9
|
|
|
9
|
|
55
|
use constant STOP => 2; |
|
9
|
|
|
|
|
30
|
|
|
9
|
|
|
|
|
24108
|
|
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head2 Tour Object Methods |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head3 new([ => value, ...]) |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Creates the object with its attributes. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
With the exception of C and C, attributes are set using the |
115
|
|
|
|
|
|
|
internal method _set(). This means that subclasses should not override new(), |
116
|
|
|
|
|
|
|
but instead provide their own _set() method to handle their own attributes. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
In addition to C and C, new() also creates internal |
119
|
|
|
|
|
|
|
attributes that may be used by subclasses. See the Attributes section for more |
120
|
|
|
|
|
|
|
details. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=cut |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub new |
125
|
|
|
|
|
|
|
{ |
126
|
209
|
|
|
209
|
1
|
83075
|
my $class = shift; |
127
|
209
|
|
|
|
|
403
|
my $self = {}; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# |
130
|
|
|
|
|
|
|
# We are copying from an existing Tour object? |
131
|
|
|
|
|
|
|
# |
132
|
209
|
50
|
|
|
|
602
|
if (ref $class) |
133
|
|
|
|
|
|
|
{ |
134
|
0
|
0
|
|
|
|
0
|
if ($class->isa("Array::Tour")) |
135
|
|
|
|
|
|
|
{ |
136
|
0
|
|
|
|
|
0
|
$class->_copy($self, @_); |
137
|
0
|
|
|
|
|
0
|
return bless($self, ref $class); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
0
|
warn "Attempts to create an Array Touring object from a '", |
141
|
|
|
|
|
|
|
ref $class, "' object fail.\n"; |
142
|
0
|
|
|
|
|
0
|
return undef; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# |
146
|
|
|
|
|
|
|
# Starting from scratch. |
147
|
|
|
|
|
|
|
# |
148
|
209
|
|
|
|
|
1043
|
bless($self, $class); |
149
|
209
|
|
|
|
|
979
|
my %attributes = @_; |
150
|
209
|
|
|
|
|
888
|
$self->_set_dimensions(%attributes); |
151
|
209
|
|
|
|
|
832
|
$self->_set_offset(%attributes); |
152
|
209
|
|
|
|
|
762
|
delete @attributes{qw(dimensions offset)}; |
153
|
209
|
|
|
|
|
609
|
$self->{position} = [0, 0, 0]; |
154
|
209
|
|
|
|
|
510
|
$self->{start} = [0, 0, 0]; |
155
|
209
|
|
|
|
|
369
|
$self->{array} = undef; |
156
|
209
|
|
|
|
|
325
|
$self->{tourlength} = 1; |
157
|
209
|
|
|
|
|
484
|
map {$self->{tourlength} *= $_} $self->get_dimensions(); |
|
627
|
|
|
|
|
1034
|
|
158
|
209
|
|
|
|
|
483
|
$self->{tourstatus} = START; |
159
|
209
|
|
|
|
|
548
|
$self->{odometer} = 0; |
160
|
209
|
|
|
|
|
934
|
$self->_set(%attributes); |
161
|
|
|
|
|
|
|
|
162
|
209
|
|
|
|
|
904
|
return $self; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head3 reset() |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
$tour->reset([ => value, ...]) |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Reset the object by returning its internal state to its original form. |
170
|
|
|
|
|
|
|
Optionally change some of the characteristics using the same parameters |
171
|
|
|
|
|
|
|
found in the new() method. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=cut |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub reset |
176
|
|
|
|
|
|
|
{ |
177
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
178
|
0
|
|
|
|
|
0
|
my %newargs = @_; |
179
|
|
|
|
|
|
|
|
180
|
0
|
|
|
|
|
0
|
my %params = $self->describe(); |
181
|
0
|
|
|
|
|
0
|
$params{position} = [0, 0, 0]; |
182
|
0
|
|
|
|
|
0
|
$params{tourlength} = 1; |
183
|
0
|
|
|
|
|
0
|
$params{tourstatus} = START; |
184
|
0
|
|
|
|
|
0
|
$params{odometer} = 0; |
185
|
0
|
0
|
|
|
|
0
|
$params{array} = undef if ($self->_uses_array()); |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# |
188
|
|
|
|
|
|
|
# Apply any options passed in. |
189
|
|
|
|
|
|
|
# |
190
|
0
|
|
|
|
|
0
|
map {$params{$_} = $newargs{$_}} keys %newargs; |
|
0
|
|
|
|
|
0
|
|
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
return $self->_set(%params); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head3 has_next() |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Returns 1 if there is more to the tour, 0 if finished. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=cut |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub has_next |
202
|
|
|
|
|
|
|
{ |
203
|
8338
|
|
|
8338
|
1
|
15023
|
my $self = shift; |
204
|
8338
|
100
|
|
|
|
34271
|
return ($self->{tourstatus} == STOP)? 0: 1; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head3 get_dimensions() |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Returns an array of the dimensions. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=cut |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub get_dimensions |
214
|
|
|
|
|
|
|
{ |
215
|
418
|
|
|
418
|
1
|
1885
|
my $self = shift; |
216
|
418
|
|
|
|
|
432
|
return @{$self->{dimensions}}; |
|
418
|
|
|
|
|
1473
|
|
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=head3 direction() |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Returns the current direction as found in the :directions EXPORT tag. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=cut |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub direction |
226
|
|
|
|
|
|
|
{ |
227
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
228
|
0
|
0
|
|
|
|
0
|
return (${$self->{position}}[0] == 0)? NoDirection: East; |
|
0
|
|
|
|
|
0
|
|
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=head3 opposite_direction() |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
Return the direction opposite from the current direction. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=cut |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
sub opposite_direction |
238
|
|
|
|
|
|
|
{ |
239
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
240
|
0
|
|
|
|
|
0
|
my $dir = $self->direction(); |
241
|
0
|
0
|
|
|
|
0
|
return NoDirection if ($dir == NoDirection); |
242
|
0
|
0
|
|
|
|
0
|
return ($dir <= Ceiling )? ($dir << 5): ($dir >> 5); |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head3 say_direction() |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Return the name in English of the current direction. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=cut |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub say_direction |
252
|
|
|
|
|
|
|
{ |
253
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
254
|
0
|
|
|
|
|
0
|
my $dir = $self->direction(); |
255
|
|
|
|
|
|
|
|
256
|
0
|
|
|
|
|
0
|
return $self->direction_name($dir); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=head3 direction_name() |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Return the name in English of the direction passed in. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
print $tour->direction_name(NorthWest), " is ", NorthWest, "\n"; |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=cut |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub direction_name |
268
|
|
|
|
|
|
|
{ |
269
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
270
|
0
|
|
|
|
|
0
|
my($dir) = @_; |
271
|
|
|
|
|
|
|
|
272
|
0
|
0
|
|
|
|
0
|
return q(NoDirection) if ($dir == NoDirection); |
273
|
0
|
0
|
|
|
|
0
|
return q(North) if ($dir == North); |
274
|
0
|
0
|
|
|
|
0
|
return q(NorthWest) if ($dir == NorthWest); |
275
|
0
|
0
|
|
|
|
0
|
return q(West) if ($dir == West); |
276
|
0
|
0
|
|
|
|
0
|
return q(SouthWest) if ($dir == SouthWest); |
277
|
0
|
0
|
|
|
|
0
|
return q(Ceiling) if ($dir == Ceiling); |
278
|
0
|
0
|
|
|
|
0
|
return q(South) if ($dir == South); |
279
|
0
|
0
|
|
|
|
0
|
return q(SouthEast) if ($dir == SouthEast); |
280
|
0
|
0
|
|
|
|
0
|
return q(East) if ($dir == East); |
281
|
0
|
0
|
|
|
|
0
|
return q(NorthEast) if ($dir == NorthEast); |
282
|
0
|
0
|
|
|
|
0
|
return q(Floor) if ($dir == Floor); |
283
|
0
|
0
|
|
|
|
0
|
if ($dir == SetPosition) |
284
|
|
|
|
|
|
|
{ |
285
|
0
|
|
|
|
|
0
|
my @p = @{$self->get_position()}; |
|
0
|
|
|
|
|
0
|
|
286
|
0
|
|
|
|
|
0
|
return q(SetPosition) . "[" . join(", ", @p) . "]"; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
0
|
return q(unknown direction); |
290
|
|
|
|
|
|
|
}; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head3 get_position() |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
Return a reference to an array of coordinates of the current position. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
@absolute_pos = @{$self->get_position()}; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=cut |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
sub get_position |
301
|
|
|
|
|
|
|
{ |
302
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
303
|
0
|
|
|
|
|
0
|
return $self->{position}; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=head3 get_offset() |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Return a reference to an array of offsets to be added to the current position. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
@offset = @{$self->get_offset()}; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=cut |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub get_offset |
315
|
|
|
|
|
|
|
{ |
316
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
317
|
0
|
|
|
|
|
0
|
return $self->{offset}; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head3 adjusted_position() |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Return a reference to an array of coordinates that are created from the position |
323
|
|
|
|
|
|
|
plus the offset. Used by the next() method. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
@current_pos = @{$self->adjusted_position()}; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=cut |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub adjusted_position |
330
|
|
|
|
|
|
|
{ |
331
|
8129
|
|
|
8129
|
1
|
9478
|
my $self = shift; |
332
|
|
|
|
|
|
|
|
333
|
8129
|
|
|
|
|
17698
|
my @position = @{ $self->{position} }; |
|
8129
|
|
|
|
|
32354
|
|
334
|
8129
|
|
|
|
|
9992
|
my @offset = @{ $self->{offset} }; |
|
8129
|
|
|
|
|
16195
|
|
335
|
8129
|
|
|
|
|
15565
|
map {$position[$_] += $offset[$_]} (0..$#position); |
|
16283
|
|
|
|
|
27846
|
|
336
|
8129
|
|
|
|
|
25668
|
return \@position; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=head3 next() |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
Returns an array reference to the next coordinates to use. Returns |
342
|
|
|
|
|
|
|
undef if the iterator is finished. |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
my $ctr = 1; |
345
|
|
|
|
|
|
|
my $tour = Array::Tour->new(dimensions => 64); |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
while (my $cref = $tour->next()) |
348
|
|
|
|
|
|
|
{ |
349
|
|
|
|
|
|
|
my($x_coord, $y_coord, $z_coord) = @{$cref}; |
350
|
|
|
|
|
|
|
$grid[$y_coord, $x_coord] = isprime($ctr++); |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
The above example would look like a completed Sieve of Eratothenes in the array |
354
|
|
|
|
|
|
|
@grid. |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=cut |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub next |
359
|
|
|
|
|
|
|
{ |
360
|
26
|
|
|
26
|
1
|
149
|
my $self = shift; |
361
|
|
|
|
|
|
|
|
362
|
26
|
100
|
|
|
|
36
|
return undef unless ($self->has_next()); |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# |
365
|
|
|
|
|
|
|
# Set up the conditions for the pacing. |
366
|
|
|
|
|
|
|
# |
367
|
25
|
100
|
|
|
|
42
|
if ($self->{tourstatus} == START) |
368
|
|
|
|
|
|
|
{ |
369
|
1
|
|
|
|
|
1
|
$self->{tourstatus} = TOURING; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
else |
372
|
|
|
|
|
|
|
{ |
373
|
|
|
|
|
|
|
# |
374
|
|
|
|
|
|
|
# Move to the next cell, checking to see if we've |
375
|
|
|
|
|
|
|
# reached the end of the row/plane/cube. |
376
|
|
|
|
|
|
|
# |
377
|
24
|
|
|
|
|
14
|
my($dim, $lastdim) = (0, scalar @{$self->{dimensions}}); |
|
24
|
|
|
|
|
36
|
|
378
|
24
|
|
66
|
|
|
47
|
while ($dim < $lastdim and ${$self->{position}}[$dim] == ${$self->{dimensions}}[$dim] - 1) |
|
28
|
|
|
|
|
38
|
|
|
28
|
|
|
|
|
75
|
|
379
|
|
|
|
|
|
|
{ |
380
|
4
|
|
|
|
|
5
|
${$self->{position}}[$dim++] = 0; |
|
4
|
|
|
|
|
9
|
|
381
|
|
|
|
|
|
|
} |
382
|
24
|
50
|
|
|
|
43
|
${$self->{position}}[$dim] += 1 unless ($dim == $lastdim); |
|
24
|
|
|
|
|
28
|
|
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
25
|
100
|
|
|
|
50
|
$self->{tourstatus} = STOP if (++$self->{odometer} == $self->{tourlength}); |
386
|
25
|
|
|
|
|
36
|
return $self->adjusted_position(); |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=head3 get_array() |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
Return a reference to the internally generated array. |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
$arrayref = $self->get_array() |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=cut |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub get_array |
398
|
|
|
|
|
|
|
{ |
399
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
400
|
0
|
0
|
|
|
|
0
|
$self->_make_array() unless (defined $self->{array}); |
401
|
0
|
|
|
|
|
0
|
return $self->{array}; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head3 describe() |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Returns as a hash the attributes of the tour object. The hash may be |
407
|
|
|
|
|
|
|
used to create a new object. |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=cut |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub describe |
412
|
|
|
|
|
|
|
{ |
413
|
96
|
|
|
96
|
1
|
570
|
my $self = shift; |
414
|
96
|
|
|
|
|
135
|
return map {$_, $self->{$_}} grep(/^[a-z]/, keys %{$self}); |
|
1536
|
|
|
|
|
15593
|
|
|
96
|
|
|
|
|
1310
|
|
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=head2 Internal Tour Object Methods |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head3 _set_dimensions() |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
my $tour = Array::Tour->new(dimensions => [12, 16]); |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
This works identically as |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
my $tour = Array::Tour->new(dimensions => [12, 16, 1]); |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
If the grid is going to be square, a single integer is sufficient: |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
my $tour = Array::Tour->new(dimensions => 16); |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
In both cases, the new() member funcntion calls _set_dimensions() and sets the |
432
|
|
|
|
|
|
|
C attribute with a reference to a three dimensional array. The third |
433
|
|
|
|
|
|
|
dimension is set to 1 if no value is given for it. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=cut |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub _set_dimensions |
438
|
|
|
|
|
|
|
{ |
439
|
209
|
|
|
209
|
|
284
|
my $self = shift; |
440
|
209
|
|
|
|
|
712
|
my(%params) = @_; |
441
|
209
|
|
50
|
|
|
1532
|
my $dim = $params{dimensions} || [1, 1, 1]; |
442
|
|
|
|
|
|
|
|
443
|
209
|
|
|
|
|
250
|
my @dimensions; |
444
|
|
|
|
|
|
|
|
445
|
209
|
100
|
|
|
|
550
|
if (ref $dim eq 'ARRAY') |
446
|
|
|
|
|
|
|
{ |
447
|
184
|
|
50
|
|
|
232
|
@dimensions = map {$_ ||= 1} @{$dim}; |
|
464
|
|
|
|
|
1365
|
|
|
184
|
|
|
|
|
548
|
|
448
|
184
|
50
|
|
|
|
499
|
push @dimensions, 1 if (@dimensions < 1); |
449
|
184
|
50
|
|
|
|
456
|
push @dimensions, $dimensions[0] if (@dimensions < 2); |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
else |
452
|
|
|
|
|
|
|
{ |
453
|
|
|
|
|
|
|
# |
454
|
|
|
|
|
|
|
# Square grid if only one dimension is defined. |
455
|
|
|
|
|
|
|
# |
456
|
25
|
|
|
|
|
68
|
@dimensions = ($dim) x 2; |
457
|
|
|
|
|
|
|
} |
458
|
209
|
100
|
|
|
|
775
|
push @dimensions, 1 if (@dimensions < 3); |
459
|
209
|
|
|
|
|
720
|
$self->{dimensions} = \@dimensions; |
460
|
|
|
|
|
|
|
|
461
|
209
|
|
|
|
|
647
|
return $self; |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head3 _set_offset() |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
The new() member funcntion calls _set_offset() and sets the C attribute |
467
|
|
|
|
|
|
|
with a reference to an array of coordinates. This method matches the size of the |
468
|
|
|
|
|
|
|
C array to the size of C, so _set_dimensions() must be called |
469
|
|
|
|
|
|
|
beforhand. |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=cut |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
sub _set_offset |
474
|
|
|
|
|
|
|
{ |
475
|
209
|
|
|
209
|
|
289
|
my $self = shift; |
476
|
209
|
|
|
|
|
1283
|
my(%params) = @_; |
477
|
209
|
|
50
|
|
|
1171
|
my $offsetref = $params{offset} || [0, 0, 0]; |
478
|
|
|
|
|
|
|
|
479
|
209
|
|
|
|
|
388
|
$self->{offset} = $offsetref; |
480
|
|
|
|
|
|
|
|
481
|
209
|
|
|
|
|
239
|
my $dims = scalar @{$self->{dimensions}}; |
|
209
|
|
|
|
|
370
|
|
482
|
209
|
|
|
|
|
300
|
my $offsets = scalar @{$self->{offset}}; |
|
209
|
|
|
|
|
353
|
|
483
|
209
|
50
|
|
|
|
517
|
push @{$self->{offset}}, (0) x ($dims - $offsets) if ($dims > $offsets); |
|
0
|
|
|
|
|
0
|
|
484
|
209
|
|
|
|
|
215
|
return @{$self->{offset}}; |
|
209
|
|
|
|
|
655
|
|
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=head3 _move_to() |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
$position = $self->_move_to($direction); # [$c, $r, $l] |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
Return a new position depending upon the direction taken. This does not set a |
492
|
|
|
|
|
|
|
new position. |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=cut |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
sub _move_to |
497
|
|
|
|
|
|
|
{ |
498
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
499
|
0
|
|
|
|
|
0
|
my($dir) = @_; |
500
|
0
|
|
|
|
|
0
|
my($c, $r, $l) = @{ $self->{position} }; |
|
0
|
|
|
|
|
0
|
|
501
|
|
|
|
|
|
|
|
502
|
0
|
0
|
|
|
|
0
|
--$r if ($dir & (North | NorthWest | NorthEast)); |
503
|
0
|
0
|
|
|
|
0
|
++$r if ($dir & (South | SouthWest | SouthEast)); |
504
|
0
|
0
|
|
|
|
0
|
++$c if ($dir & (East | NorthEast | SouthEast)); |
505
|
0
|
0
|
|
|
|
0
|
--$c if ($dir & (West | NorthWest | SouthWest)); |
506
|
0
|
0
|
|
|
|
0
|
++$l if ($dir & Floor); |
507
|
0
|
0
|
|
|
|
0
|
--$l if ($dir & Ceiling); |
508
|
0
|
|
|
|
|
0
|
return [$c, $r, $l]; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=head3 _make_array() |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
$self->_make_array(); |
514
|
|
|
|
|
|
|
or |
515
|
|
|
|
|
|
|
$self->_make_array($value); |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
Make an internal array for reference purposes. If no value to set the array cels |
518
|
|
|
|
|
|
|
with is passed in, the array cells are set to zero by default. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=cut |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
sub _make_array |
523
|
|
|
|
|
|
|
{ |
524
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
525
|
0
|
0
|
|
|
|
0
|
my $dflt = (scalar @_)? $_[0]: 0; |
526
|
0
|
|
|
|
|
0
|
my($cols, $rows, $lvls) = map {$_ - 1} @{$self->{dimensions}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
527
|
|
|
|
|
|
|
|
528
|
0
|
|
|
|
|
0
|
my $m = $self->{array} = ([]); |
529
|
0
|
|
|
|
|
0
|
foreach my $l (0..$lvls) |
530
|
|
|
|
|
|
|
{ |
531
|
0
|
|
|
|
|
0
|
foreach my $r (0..$rows) |
532
|
|
|
|
|
|
|
{ |
533
|
0
|
|
|
|
|
0
|
foreach my $c (0..$cols) |
534
|
|
|
|
|
|
|
{ |
535
|
0
|
|
|
|
|
0
|
$$m[$l][$r][$c] = $dflt; |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
} |
539
|
0
|
|
|
|
|
0
|
return $self; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=head3 _set() |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
$self->_set(%attributes); |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
Take the parameters provided to new() and use them to set the |
547
|
|
|
|
|
|
|
attributes of the touring object. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=cut |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub _set() |
552
|
|
|
|
|
|
|
{ |
553
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
554
|
1
|
|
|
|
|
2
|
my(%params) = @_; |
555
|
|
|
|
|
|
|
|
556
|
1
|
|
|
|
|
2
|
warn "Unknown paramter $_" foreach (grep{$_ !~ /reverse/} (keys %params)); |
|
1
|
|
|
|
|
7
|
|
557
|
1
|
|
|
|
|
2
|
return $self; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=head3 _uses_array() |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
Returns 0 or 1 depending upon whether there's an internal array to return. |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=cut |
565
|
|
|
|
|
|
|
|
566
|
0
|
|
|
0
|
|
|
sub _uses_array {my $self = shift; return 0;} |
|
0
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
# |
569
|
|
|
|
|
|
|
# dump_array |
570
|
|
|
|
|
|
|
# |
571
|
|
|
|
|
|
|
# @xlvls = $obj->dump_array($spr_fmt); |
572
|
|
|
|
|
|
|
# $xstr = $obj->dump_array($spr_fmt); |
573
|
|
|
|
|
|
|
# |
574
|
|
|
|
|
|
|
# Returns a formatted string of all the cell values. By default, |
575
|
|
|
|
|
|
|
# the format string is " %04x", so the default output strings will |
576
|
|
|
|
|
|
|
# be rows of hexadecimal numbers separated by a space. |
577
|
|
|
|
|
|
|
# |
578
|
|
|
|
|
|
|
# If called in a list context, returns a list of strings, each one |
579
|
|
|
|
|
|
|
# representing a level. If called in a scalar context, returns a single |
580
|
|
|
|
|
|
|
# string, each level separated by a single newline. |
581
|
|
|
|
|
|
|
# |
582
|
|
|
|
|
|
|
sub dump_array |
583
|
|
|
|
|
|
|
{ |
584
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
585
|
0
|
|
0
|
|
|
|
my $format = $_[0] || " %04x"; |
586
|
0
|
|
|
|
|
|
my($cols, $rows, $lvls) = map {$_ - 1} @{$self->{dimensions}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
587
|
0
|
|
|
|
|
|
my $m = $self->{array}; |
588
|
0
|
|
|
|
|
|
my @levels; |
589
|
|
|
|
|
|
|
|
590
|
0
|
|
|
|
|
|
foreach my $l (0..$lvls) |
591
|
|
|
|
|
|
|
{ |
592
|
0
|
|
|
|
|
|
my $vxstr = ""; |
593
|
0
|
|
|
|
|
|
foreach my $r (0..$rows) |
594
|
|
|
|
|
|
|
{ |
595
|
0
|
|
|
|
|
|
foreach my $c (0..$cols) |
596
|
|
|
|
|
|
|
{ |
597
|
0
|
|
|
|
|
|
$vxstr .= sprintf($format, $$m[$l][$r][$c]); |
598
|
|
|
|
|
|
|
} |
599
|
0
|
|
|
|
|
|
$vxstr .= "\n"; |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
0
|
|
|
|
|
|
push @levels, $vxstr; |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
0
|
0
|
|
|
|
|
return wantarray? @levels: join("\n", @levels); |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# |
609
|
|
|
|
|
|
|
# $class->_copy($self); |
610
|
|
|
|
|
|
|
# |
611
|
|
|
|
|
|
|
# Duplicate the iterator. |
612
|
|
|
|
|
|
|
# |
613
|
|
|
|
|
|
|
sub _copy |
614
|
|
|
|
|
|
|
{ |
615
|
0
|
|
|
0
|
|
|
my($other, $self) = @_; |
616
|
0
|
|
|
|
|
|
foreach my $k (grep($_ !~ /_array/, keys %{$other})) |
|
0
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
{ |
618
|
0
|
|
|
|
|
|
$self->{$k} = $other->{$k}; |
619
|
|
|
|
|
|
|
} |
620
|
0
|
0
|
|
|
|
|
if ($other->uses_array()) |
621
|
|
|
|
|
|
|
{ |
622
|
|
|
|
|
|
|
# copy it. |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
1; |
627
|
|
|
|
|
|
|
__END__ |