sub iterator { my $box = shift; # direction: # 0 => right # 1 => down # 2 => left # 3 => up my $direction = 0; my @pos = (0,0); my $up = 0; my $left = 0; my $down = ( scalar @$box ) - 1; my $right = ( scalar @{ $box->[0] } ) - 1; return sub { my $return_element = $box->[ $pos[1] ]->[ $pos[0] ]; if ( $up > $down or $left > $right ) { # reset, so if we call it after undef, it will start over. $up = 0; $left = 0; $down = ( scalar @$box ) - 1; $right = ( scalar @{ $box->[0] } ) - 1; @pos = ( 0, 0 ); $direction = 0; # return that we are done. return undef; } LABEL: { if ( $direction == 0 ) { if ( $pos[0] == $right ) { # we're traveling right and have hit the right edge. # change the direction to down. $direction++; # move our top edge (because we just got finished with # our uppermost remaining row) $up++; redo LABEL; } } if ( $direction == 1 ) { if ( $pos[1] == $down ) { # we're traveling down and have hit the bottom edge. # change the direction to left. $direction++; # move our right edge (because we just got finished with # our rightmost remaining row) $right--; redo LABEL; } } if ( $direction == 2 ) { if ( $pos[0] == $left ) { # we're traveling left and have hit the leftmost edge. # change the direction to up. $direction++; # move our bottom edge (because we just got finished with # our bottommost remaining row) $down--; redo LABEL; } } if ( $direction == 3 ) { if ( $pos[1] == $up ) { # we're traveling up and have hit the top edge. # change the direction to right. $direction=0; # move our left edge (because we just got finished with # our leftmost remaining row) $left++; redo LABEL; } } }; # move our position. if ( $direction == 0 ) { $pos[ 0 ]++; } elsif ( $direction == 1 ) { $pos[ 1 ]++; } elsif ( $direction == 2 ) { $pos[ 0 ]--; } elsif ( $direction == 3 ) { $pos[ 1 ]--; } return $return_element; } }