1. Technology
You can opt-out at any time. Please refer to our privacy policy for contact information.

Rotating a Two Dimensional Array in Ruby

By

See More About

The following article is part of a series.  For more articles in this series, see Cloning the Game 2048 in Ruby.  For the complete and final code, see the gist.

In order to implement our 2048 clone, we need to be able to rotate a two dimensional array. What do we mean by rotate? We want to turn the entire puzzle clockwise by 90 degrees. So in the example below, array A turns into array B.


a) [ [1,2],    b) [ [3,1],
     [3,4]          [4,2]
   ]               ]

Now this is a bit tricky. When working with problems like this, it's invaluable to write out a few examples. Really look at what you're working with before you jump in.

The first thing that you'll notice is the first row of the rotated array is the first column of the original array. The second thing you'll notice is the column is reversed. And that's all we need to do. Get the columns of the array and reverse them. This will work for two dimensional arrays of any size, including our 4x4 for the 2048 game.

To get the columns of the array, the first thing we need is a list of the column indices for each row. The column indices are 0 to n-1, where n is the width of the two dimensional array. So let's start with that.


#!/usr/bin/env ruby
require 'pp'

a = Array.new(4) { Array.new(4, 0) }
cols = 0..a.size-1
pp cols

 

Now to get the actual columns, what we need to do is map the column index range. By doing this, we start with what is essentially the array [0,1,2,3] (the column indices) and we're going to replace each of those values with the actual columns.


#!/usr/bin/env ruby
require 'pp'

a = Array.new(4) { Array.new(4, 0) }
rotated = (0..a.size-1).map{|colidx| colidx }
pp rotated

 

So inside the column index map, we need a second map. In this case, we're iterating over the 2D array and collecting the column values. So inside the map block we have, we need to say something like a.map{|row| … }, but what are we doing with each row? We're indexing it using the column index given to us using the outer map to collect all values in that column from each row. I've also added temporary values to the example so we can better see what we're doing.


#!/usr/bin/env ruby
require 'pp'

i = 0
a = Array.new(4) { Array.new(4) { i += 1} }
pp a

rotated = (0..a.size-1).map{|colidx| a.map{|row| row[colidx] } }
pp rotated

And the output of this program:


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

As you can see, we're almost there. The first column is 1,5,9,13, and that's represented in the rotated 2D array. However, the column needs to be reversed. So let's add that in. We need to reverse the collected column, so we need to reverse the result of the inner map.


#!/usr/bin/env ruby
require 'pp'

i = 0
a = Array.new(4) { Array.new(4) { i += 1} }
pp a

rotated = (0..a.size-1).map{|colidx| a.map{|row| row[colidx] }.reverse }
pp rotated

And the code output.


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

And there you have it, a rotated 2D array. To be a bit more visual, we've taken this array:


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

And rotated it 90 degrees clockwise to make this.


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

And the final code to do this is a single line.


rotated = (0..a.size-1).map{|colidx| a.map{|row| row[colidx] }.reverse }

Or, if you prefer (since this code is really very dense), a few more lines.


rotated = (0..a.size-1).map do|colidx|
  a.map do|row|
    row[colidx]
  end.reverse
end

 

There's more!  To keep reading, see the next article in this series: The Board Class.

  1. About.com
  2. Technology
  3. Ruby
  4. Tutorials
  5. Writing a 2048 Clone in Ruby
  6. Rotating a Two Dimensional Array in Ruby

©2014 About.com. All rights reserved.