http://www.perlmonks.org?node_id=520147


in reply to Re: spiral path traversal for a grid
in thread spiral path traversal for a grid

Very literally and verbosely so you can see what it's doing:
#!/usr/bin/perl # # Matrix Spiral # use strict; use warnings; # # Size of input matrix in columns and rows # my $cols = 7; my $rows = 3; # # Decrement rows & columns because we're using them as array indices # (i.e. counting from 0 not 1) # $cols--; $rows--; # # Populate a list of elements to feed the matrix from # my @elements; while (<DATA>) { # # Display data to screen so we can compare results to it # print; push @elements, (split(' ', $_)); } # # Keep the size of elements for after we've shifted it empty # my $count = @elements; # # Populate a matrix of the elements # which pacman can then walk around & eat pill by pill... # my @matrix; for my $row (0 .. $rows ) { for my $col (0 .. $cols ) { $matrix[$col][$row] = shift(@elements); } } my @output; my $x = 0; # X position in matrix my $y = 0; # Y position in matrix my $v = 0; # Vertical direction my $h = 1; # Horizontal direction my $row_s = 0; # Current Row start my $row_e = $rows; # Current Row end my $col_s = 0; # Current Column start my $col_e = $cols; # Current Column end for my $place ( 0 .. $count-1 ) { # # Show X and Y coordinate in bounds "min<coord<max" # and the value at that coordinate in [ ] so we can see it work # print "$place x[$col_s<$x<$col_e] y[$row_s<$y<$row_e]", " [$matrix[$x][$y]]\n"; # # Push the element at that matrix coordinate into the output list # $output[$place] = $matrix[$x][$y]; if ( $h == 1 && $v == 0 && $x == $col_e && $y == $row_s ) { print "> reached last col. go v\n"; $h = 0; # Stop horizontal movement (was right) $v = 1; # Go down # Finished highest remaining row # so remove it from matrix bounds $row_s++; } elsif ( $h == 0 && $v == 1 && $x == $col_e && $y == $row_e ) { print "v reached last row. go <\n"; $h = -1; # Go left $v = 0; # Stop vertical movement (was down) # Finished rightmost remaining column # so remove it from matrix bounds $col_e--; } elsif ( $h == -1 && $v == 0 && $x == $col_s && $y == $row_e ) { print "< reached first col. go ^\n"; $h = 0; # Stop horizontal movement (was left) $v = -1; # Go up # Finished lowest remaining row # so remove it from matrix bounds $row_e--; } elsif ( $h == 0 && $v == -1 && $x == $col_s && $y == $row_s ) { print "^ reached first row. go >\n"; $h = 1; # Go right $v = 0; # Stop vertical movement (was up) # Finished leftmost remaining column # so remove it from matrix bounds $col_s++; } # # Increment (or decrement) matrix position pointer # $x += $h; $y += $v; } print join($/, @output), $/; __DATA__ a b c d e f g h i j k l m n o p q r s t u
Try it with:
my $cols = 26; my $rows = 26;
at the top and
__DATA__ aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw a +x ay az ba bb bc bd be bf bg bh bi bj bk bl bm bn bo bp bq br bs bt bu bv bw b +x by bz ca cb cc cd ce cf cg ch ci cj ck cl cm cn co cp cq cr cs ct cu cv cw c +x cy cz da db dc dd de df dg dh di dj dk dl dm dn do dp dq dr ds dt du dv dw d +x dy dz ea eb ec ed ee ef eg eh ei ej ek el em en eo ep eq er es et eu ev ew e +x ey ez fa fb fc fd fe ff fg fh fi fj fk fl fm fn fo fp fq fr fs ft fu fv fw f +x fy fz ga gb gc gd ge gf gg gh gi gj gk gl gm gn go gp gq gr gs gt gu gv gw g +x gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw h +x hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir is it iu iv iw i +x iy iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp jq jr js jt ju jv jw j +x jy jz ka kb kc kd ke kf kg kh ki kj kk kl km kn ko kp kq kr ks kt ku kv kw k +x ky kz la lb lc ld le lf lg lh li lj lk ll lm ln lo lp lq lr ls lt lu lv lw l +x ly lz ma mb mc md me mf mg mh mi mj mk ml mm mn mo mp mq mr ms mt mu mv mw m +x my mz na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv nw n +x ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot ou ov ow o +x oy oz pa pb pc pd pe pf pg ph pi pj pk pl pm pn po pp pq pr ps pt pu pv pw p +x py pz qa qb qc qd qe qf qg qh qi qj qk ql qm qn qo qp qq qr qs qt qu qv qw q +x qy qz ra rb rc rd re rf rg rh ri rj rk rl rm rn ro rp rq rr rs rt ru rv rw r +x ry rz sa sb sc sd se sf sg sh si sj sk sl sm sn so sp sq sr ss st su sv sw s +x sy sz ta tb tc td te tf tg th ti tj tk tl tm tn to tp tq tr ts tt tu tv tw t +x ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un uo up uq ur us ut uu uv uw u +x uy uz va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw v +x vy vz wa wb wc wd we wf wg wh wi wj wk wl wm wn wo wp wq wr ws wt wu wv ww w +x wy wz xa xb xc xd xe xf xg xh xi xj xk xl xm xn xo xp xq xr xs xt xu xv xw x +x xy xz ya yb yc yd ye yf yg yh yi yj yk yl ym yn yo yp yq yr ys yt yu yv yw y +x yy yz za zb zc zd ze zf zg zh zi zj zk zl zm zn zo zp zq zr zs zt zu zv zw z +x zy zz
at the bottom, that way it's easier to see what it's doing because the letters correspond to columns and rows.

Also with such a large list you might want to format the output with:

my $place; for my $row (0 .. $rows) { for my $col (0 .. $cols) { print $output[$place++], " "; } print $/; }
instead of:
print join($/, @output), $/;