Non recursive implementation, strict safe, but not warning free. 252 chars.
use strict;
sub spiral {
my$S=pop;my($z,$s,$t,$d,$x,$y,@b)=($S**2,1);@_=([1,
0],[0,1],[-1,0],[0,-1]);$b[$S][$_]=$b[$_][$S]=$/for
0..$S;map{$b[$y][$x]=sprintf"%0*d",length$z,$_;($s,
$t)=@{$_[++$d%4]}if$s&&$b[$y][$x+$s]||$t&&$b[$y+$t]
[$x];$x+=$s;$y+=$t}1..$z;pop@b;print"@$_"for@b;
}
for (1..10) {
spiral($_);
print "\n---\n";
}
It could go smaller fairly easily by using globals, but then couldnt be run more than once per process.
Update: And here is the annotated version. Funny, while annotating it I noticed a couple of things I could have done to make it smaller :-)
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 travell
+ing
($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 newline
+s
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";
}
---
$world=~s/war/peace/g