in reply to spiral path traversal for a grid

One possible solution would be to traverse the first row until you need to stop, then change the direction and traverse downwards until you need to stop and then traverse to left and eventually up. At that point you would be one row below the starting point. Then just repeat the process until done.

I guess that could be the way how I would implement it if I was trying to solve the problem.

I hope that helps some
- negation

Replies are listed 'Best First'.
Re^2: spiral path traversal for a grid
by serf (Chaplain) on Dec 31, 2005 at 13:54 UTC
    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), $/;