Nice problem! and some nice solutions ... everyone loves a diversion ...
Here's mine. For variety, and cos I'm looking for a new job (wink) I went for an OO approach. Certainly not the least characters, and I'm not sure it adds much in readability, but something different. Perhaps not even that, as I suspect that it is really a dressed up version of the iterative solution that was given already. Anyhow, here it is. I had fun doing it.
The object itself:
package SpiralSq;
use strict;
sub new
{
my ($class, $size, $offset) = @_;
$offset = 1 unless defined ($offset);
my $self = { 'size'=>$size,
'offset' => $offset,
'nextoffset' => (4*($size - 1) + $offset)};
bless $self, $class;
return $self;
}
sub getInside
{
my ($self) = @_;
$self->{'inside'} = new SpiralSq($self->{'size'} - 2,
$self->{'nextoffset'})
unless (defined $self->{'inside'});
return $self->{'inside'};
}
sub getRow
{
my ($self, $r) = @_;
my $o = $self->{'offset'};
my $s = $self->{'size'};
my $n = $self->{'nextoffset'};
my @row;
if ($r == 0)
{
@row = ($o .. ($s - 1 + $o));
}
elsif ($r == $s - 1)
{
@row = ((2*($s - 1) + $o) .. (3*($s - 1) + $o));
@row = reverse @row;
}
elsif ($r < $s)
{
@row = (($n - $r),
$self->getInside->getRow($r - 1),
($s -1 + $r + $o));
}
else
{
die "error!";
}
return @row;
}
1;
And a test script:
#!/opt/perl/bin/perl -w
use strict;
use SpiralSq;
my $n = 18;
my $s = new SpiralSq($n);
for (0 .. ($n-1))
{
print join " ", $s->getRow($_);
print "\n";
}