use strict;
sub spiral {
my $size = pop; # get the size from the arguments
my $elements = $size**2; # how many numbers in the square
my $dir=0; # we will go right at start
my ($dx,$dy)=(1,0); # starting deltas (must match $dir)
my ($x,$y)=(0,0); # start top left
my @board; # the board we will use
my @delta=([1,0], # deltas for going right
[0,1], # ... down
[-1,0], # ... left
[0,-1]); # ... up
# Set up sentinal values in (x,$size) and ($size,y)
# ie, a column on the right and a row at the bottom
$board[$size][$_]=$board[$_][$size]="\n"
for 0..$size;
# The strategy is to treat $x,$y as a cursor on the grid.
# each square we move in the direction specified by $dir
# via the @delta table, assuming that is that the new
# cell has not been filled already. if it has we turn to
# the right by incrementing $dir and finding new deltas.
for (1..$elements) {
# neatly set up the value in the grid, we use the length of
# the center element to determine how many digits to use per "cell"
$board[$y][$x] = sprintf"%0*d",length $elements, $_;
# if we bump into something we need to turn to the right
# the sentinals mean we dont have to check for anything other
# than the cell being nonempty in the direction we are travelling
($dx,$dy)=@{$delta[++$dir%4]}
if $dx && $board[$y][$x+$dx]
|| $dy && $board[$y+$dy][$x];
# and adjust our position according to the deltas
$x+=$dx;
$y+=$dy
};
# we need to remove the bottom row as it is just a list of newlines
pop @board;
# and now we print it out, we dont need to remove the right hand
# sentinals as they conveniently end the line for us.
print"@$_" for @board;
}
for (1..10) {
spiral($_);
print "\n---\n";
}