Search code examples
rubyalgorithmspiral

Looping in a spiral outside-in


I'm looking to loop through a matrix similar to Looping in a spiral but looping outside-in, instead of inside-out. Can anyone help me with a good way to do this for a matrix of any size, ideally in Ruby?

Example: In a 3x4 matrix I want to start at [0,0] going right, then move down once I reach [3,0], move left at [3,2] etc.

[0,0] [1,0] [2,0] [3,0]
[0,1] [1,1] [2,1] [3,1]
[0,2] [1,2] [2,2] [3,2]

The order to move is shown below:

0  1  2  3
9  10 11 4
8  7  6  5

And the output would be:

[0,0], [1,0], [2,0], [3,0], [3,1], [3,2], [2,2], [1,2], [0,2], [0,1], [1,1], [2,1]

Solution

  • Without loss of generality, let's write the array as:

    arr = [
      [ 1,  2,  3, 4,],
      [12, 13, 14, 5,],
      [11, 16, 15, 6,],
      [10,  9,  8, 7,]
    ]
    

    The desired result is:

    [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
    

    I will use a helper:

    def rotate_anticlockwise(arr)
      arr.map(&:reverse).transpose
    end
    

    For example:

    rotate_anticlockwise(arr)
      #=> [[4,  5,  6, 7],
      #    [3, 14, 15, 8],
      #    [2, 13, 16, 9],
      #    [1, 12, 11, 10]] 
    

    We can now compute the desired result as follows:

    out = []
    a = arr.map(&:dup)
    while a.any?
      out.concat(a.shift)
      a = rotate_anticlockwise(a)
    end
    out
      # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]