18

I am programming a Tetris clone and in my game I store my tetromino blocks as 4x4 arrays of blocks. I now need to be able to rotate the integer positions in the arrays so that I get a rotated tetris block. I cannot simply rotate the texture because all my collision detection, etc has been designed to work with the 2D array. The game is written in C# using XNA.

How can i possibly rotate my 2D array of ints by 90 degrees clockwise/counter clockwise.

Here is how my 'L' block is stored as an example.

0 1 0 0
0 1 0 0
0 1 1 0 
0 0 0 0

Thanks for your help.

Brock Woolf
  • 46,656
  • 50
  • 121
  • 144

7 Answers7

30

If they're a 2D array, you can implement rotation by copying with different array access orders.

i.e., for a clockwise rotation, try:

int [,] newArray = new int[4,4];

for (int i=3;i>=0;--i)
{
    for (int j=0;j<4;++j)
    {
         newArray[j,3-i] = array[i,j];
    }
}

Counter-clockwise is similar.

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Good solution, but overkill given the problem domain. – Ryan Emerle Mar 14 '09 at 18:59
  • I am voting this up, it should be marked as the solution. Not sure what you mean rde6173, unless you too are vouching for storing 4 orientation arrays. – Ricket Mar 14 '09 at 19:07
  • That's what he's suggesting. There are advantages to that, but this answers the question directly - I wasn't trying to suggest alternate designs. – Reed Copsey Mar 14 '09 at 19:11
  • This is not overkill as it will save manual labor of producing those pre-transformed arrays, and will be extensible to non-tetraminos if further work is put into the game beyond basic tetris. (Will +1 tomorrow when my votes reset :) – Merlyn Morgan-Graham Nov 17 '11 at 14:57
  • It's up to the programmer whether he wants to rotate the piece or store it as 4 orientation arrays.There's not that much labour in writing out 7 * 4 pieces.I would prefer rotating though. – devsaw Sep 21 '13 at 14:08
  • Reed, please, be very kind, see my question http://stackoverflow.com/questions/42496192/rotating-a-two-dimensional-array-not-90-degrees – StepUp Feb 28 '17 at 12:48
11

Don't rotate the pieces with code. Just store an array of the different piece orientations and cycle through them when the piece is rotated. There's no need to dynamically rotate them in a Tetris game.

As the problem domain is Tetris, you will find that a rotation algorithm causes undesirable effects, such as the long thin Tetronimo not alternating between two positions (as it does in the real thing).

Jon
  • 5,247
  • 6
  • 30
  • 38
  • -1; There is no advantage to storing 4 orientations of each piece rather than just rotating. You should be focused on answering his question, not discouraging him, unless he's making a critical mistake; which he certainly is not. – Ricket Mar 14 '09 at 19:03
  • It would take me far less time to write a double for loop as was suggested above. – Brock Woolf Mar 14 '09 at 19:05
  • 4
    Ricket, easy on the tone there. I have updated my answer to indicate why rotation is a bad idea in this case. – Jon Mar 14 '09 at 19:28
  • It's not about the time it takes you to write as a developer, it's all about the time it takes to execute. Remember, compilers might be good at optimising loops, but they're even better when it comes to constants. – Ian Jun 26 '09 at 13:34
  • I agree with Jon, I've just been contemplating this problem myself. If you rotate the array, the blocks don't rotate the same way as they do in the original game. They appear to rotate around the centre. – devilcrack Mar 15 '10 at 19:03
6

In classic tetris there are very few permutations of objects. I would simply have a constant array for each "tetromino," at each of the 4 positions, and simple logic to choose the appropriate one based on input.

Why waste CPU cycles trying to rotate it?

Ryan Emerle
  • 15,461
  • 8
  • 52
  • 69
  • The math is so simple in this case, it's probably just as fast to rotate it as it would be to do the permutation search based on the current block style + position. – Reed Copsey Mar 14 '09 at 18:56
  • I'd also add that from a gameplay and design point-of-view, it might be better to have pre-set rotations. What do you do when you get the long 4x1 piece? If you rotate it twice, should it really be one full space over to the side (which it would be if you use pure math)? – Matt Howell Mar 14 '09 at 18:59
  • CPU cycles are not an issue in this case. Do not try to overoptimize by thinking about "wasting CPU cycles". Whether you store 4 different permutations and select one, or loop through and rotate the array, either way will be so minimal a time span that it won't matter at all. Down vote. – Ricket Mar 14 '09 at 19:02
  • 2
    I have a 2.4GHz Core 2 Duo processor, not to mention that a double for loop that checks an integer is doing a comparison of 8 bytes times 16. That's almost nothing at all for the CPU. Plus what if I one day wanted a 5x5 matrix? I'd have to recode it all. – Brock Woolf Mar 14 '09 at 19:04
3

If you want to rotate a 4 x 4 block, you just move the positions:

A B C A
C D D B
B D D C
A C B A

Each A moves to the next A, and the same for B, C and D.

   /-----\
   |     |
   |     V
   A B C A
/->C D>D B--\
|  B D D C  |
|  A C B A  |
|    | ^    |
|    | |    |
\----/ \----/     
Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
  • I think your picture is a little off, not sure exactly what you're trying to clarify with it and the arrows seem to point b -> c and a -> c rather than supporting your instructions. fmsf, grow up. – Ricket Mar 14 '09 at 19:05
1
int[,] source = { { 1,2,3 }, {4,5,6 }, { 7,8,9} };
int[,] result = new int[3,3];
var rows = source.GetLength(0);
var cols = source.GetLength(1);

for (var r=0; r<rows; r++)
{
    for (var c = 0; c < cols; c++)
    {
        result[r, c] = source[rows - 1 - c, r];
    }
}
Baqer Naqvi
  • 6,011
  • 3
  • 50
  • 68
1

I'd store (x, y) coordinates of the "cells" and use rotation matrix to rotate them. See Drawing a Rotated Rectangle for example. You probably have to round the result to closest 0.5 increment.

Community
  • 1
  • 1
Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
0

js code for both clockwise and counter-clockwise:

function arrRotation90(arr, clockwise) {
            var arr_rotated = [];
            for (var i = 0; i < arr[0].length; i++) {
                arr_rotated[i] = [];
            }
            if (clockwise) {
                for (var i = 0; i < arr.length; i++) {
                    for (var j = 0; j < arr[i].length; j++) {
                        arr_rotated[arr[i].length-1-j][i] = arr[i][j];
                    }
                }
            } else {
                for (var i = 0; i < arr.length; i++) {
                    for (var j = 0; j < arr[i].length; j++) {
                        arr_rotated[j][arr.length - 1 - i] = arr[i][j];
                    }
                }
            }
            return arr_rotated;
        }
Sunny Sun
  • 65
  • 5
  • 13