Rotating an array using C#

I've recently been working on a number of small test programs for the different sections which make up a game I'm planning on writing. One of these test systems involved a series of polyominoes which I needed to rotate. Internally, the data for these shapes are stored as a simple boolean array, which I access as though it were two dimensions.

One of the requirements was that the player needs to be able to rotate these shapes at 90° intervals, and so there were two ways I could have solved this

  • Define pre-rotated versions of all shapes
  • Rotate the shapes on the fly

Clearly, I went with option two otherwise there would be no need for this article! I choose not to go with the pre-rotated approach, as firstly I'm using a lot of shapes and creating up to 4 versions of each of these is not really worthwhile, and secondly I don't want to store them either, or have to care which orientation is currently in use.

This article describes how to rotate a 2D array in fixed 90° intervals, and also how to rotate 1D arrays that masquerade as 2D arrays.

Note: The code in this article will only work with rectangle arrays. I don't usually use jagged arrays, so this code has no special provisions to work with them.

Creating a simple sample

First up, we need an array to rotate. For the purposes of our demo, we'll use the following array - note that the width and the height of the array don't match.

bool[,] src;

src = new bool[2, 3];

src[0, 0] = true;
src[0, 1] = true;
src[0, 2] = true;
src[1, 2] = true;

We can visualize the contents of the array but dumping it in a friendly fashion to the console

private static void PrintArray(bool[,] src)
{
  int width;
  int height;

  width = src.GetUpperBound(0);
  height = src.GetUpperBound(1);

  for (int row = 0; row < height + 1; row++)
  {
    for (int col = 0; col < width + 1; col++)
    {
      char c;

      c = src[col, row] ? '#' : '.';

      Console.Write(c);
    }

    Console.WriteLine();
  }

  Console.WriteLine();
}

PrintArray(src);

All of which provides the following stunning output

#.
#.
##

Rotating the array clockwise

This function will rotate an array 90° clockwise

private static bool[,] RotateArrayClockwise(bool[,] src)
{
  int width;
  int height;
  bool[,] dst;

  width = src.GetUpperBound(0) + 1;
  height = src.GetUpperBound(1) + 1;
  dst = new bool[height, width];

  for (int row = 0; row < height; row++)
  {
    for (int col = 0; col < width; col++)
    {
        int newRow;
        int newCol;

        newRow = col;
        newCol = height - (row + 1);

        dst[newCol, newRow] = src[col, row];
    }
  }

  return dst;
}

How does it work? First we get the width and height of the array using the GetUpperBound method of the Array class. As arrays are zero based, we add 1 to each of these results, otherwise the new array will be too small to hold the data.

Next, we create a new array - with the width and height ready previously swapped, allowing us to correctly handle non-square arrays.

Finally, we loop through each row and each column. For each entry, we calculate the new row and column, then assign the value from the source array to the transposed location in the destination array

  • To calculate the new row, we simply set the row to the existing column value
  • To calculate the new column, we take the current row, add one to it, then subtract that value from the original array's height

If we now call RotateArrayClockwise using our source array, we'll get the following output

###
#..

Perfect!

Rotating the array anti-clockwise

Rotating the array anti-clockwise (or counter clockwise depending on your terminology) uses most of the same code as previous, but the calculation for the new row and column is slightly different

newRow = width - (col + 1);
newCol = row;
  • To calculate the new row we take the current column, add one to it, then subtract that value from the original array's width
  • The new column is the current row

Using our trusty source array, this is what we get

..#
###

Rotating 1D arrays

Rotating a 1D array follows the same principles outlined above, with the following differences

  • As the array has only a single dimension, you cannot get the width and the height automatically - you must know these in advance
  • When calculating the new index position using row-major order remember that as the width and the height have been swapped, the calculation will be something similar to newIndex = newRow * height + newCol

The following functions show how I rotate a 1D boolean array.

public Polyomino RotateAntiClockwise()
{
  return this.Rotate(false);
}

public Polyomino RotateClockwise()
{
  return this.Rotate(true);
}

private Polyomino Rotate(bool clockwise)
{
  byte width;
  byte height;
  bool[] result;
  bool[] matrix;

  matrix = this.Matrix;
  width = this.Width;
  height = this.Height;
  result = new bool[matrix.Length];

  for (int row = 0; row < height; row++)
  {
    for (int col = 0; col < width; col++)
    {
      int index;

      index = row * width + col;

      if (matrix[index])
      {
        int newRow;
        int newCol;
        int newIndex;

        if (clockwise)
        {
          newRow = col;
          newCol = height - (row + 1);
        }
        else
        {
          newRow = width - (col + 1);
          newCol = row;
        }

        newIndex = newRow * height + newCol;

        result[newIndex] = true;
      }
    }
  }

  return new Polyomino(result, height, width);
}

Downloads

Filename Description Version Release Date
RotateArray.zip
  • md5: b34557c7c9d55d451bd5441234cafc15

Sample project for the rotating an array using C# article.

1.0.0.0 24/12/2015 Download

About The Author

Gravatar

The founder of Cyotek, Richard enjoys creating new blog content for the site. Much more though, he likes to develop programs, and can often found writing reams of code. A long term gamer, he has aspirations in one day creating an epic video game. Until that time, he is mostly content with adding new bugs to WebCopy and the other Cyotek products.

Leave a Comment

While we appreciate comments from our users, please follow our posting guidelines. Have you tried the Cyotek Forums for support from Cyotek and the community?

Styling with Markdown is supported