Tetris Piece Rotation Algorithm

Viewed 75583

What are the best algorithms (and explanations) for representing and rotating the pieces of a tetris game? I always find the piece rotation and representation schemes confusing.

Most tetris games seem to use a naive "remake the array of blocks" at each rotation:

http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=tetris

However, some use pre-built encoded numbers and bit shifting to represent each piece:

http://www.codeplex.com/wintris

Is there a method to do this using mathematics (not sure that would work on a cell based board)?

16 Answers

There is a limited amount of shapes, so I would use a fixed table and no calculation. That saves time.

But there are rotation algorithms.

Chose a centerpoint and rotate pi/2.

If a block of a piece starts at (1,2) it moves clockwise to (2,-1) and (-1,-2) and (-1, 2). Apply this for each block and the piece is rotated.

Each x is the previous y and each y - the previous x. Which gives the following matrix:

[  0   1 ]
[ -1   0 ]

For counterclockwise rotation, use:

[  0  -1 ]
[  1   0 ]

This is how I did it recently in a jQuery/CSS based tetris game.

Work out the centre of the block (to be used as a pivot point), i.e. the centre of the block shape. Call that (px, py).

Each brick that makes up the block shape will rotate around that point. For each brick, you can apply the following calculation...

Where each brick's width and height is q, the brick's current location (of the upper left corner) is (x1, y1) and the new brick location is (x2, y2):

x2 = (y1 + px - py)

y2 = (px + py - x1 - q)

To rotate the opposite direction:

x2 = (px + py - y1 - q)

y2 = (x1 + py - px)

This calculation is based on a 2D affine matrix transformation. If you are interested in how I got to this let me know.

Personally I've always just represented the rotations by hand - with very few shapes, it's easy to code that way. Basically I had (as pseudo-code)

class Shape
{
    Color color;
    ShapeRotation[] rotations;
}

class ShapeRotation
{
    Point[4] points;
}

class Point
{
    int x, y;
}

At least conceptually - a multi-dimensional array of points directly in shape would do the trick too :)

Since there are only 4 possible orientations for each shape, why not use an array of states for the shape and rotating CW or CCW simply increments or decrements the index of the shape state (with wraparound for the index)? I would think that might be quicker than performing rotation calculations and whatnot.

I derived a rotation algorithm from matrix rotations here. To sum it up: If you have a list of coordinates for all cells that make up the block, e.g. [(0, 1), (1, 1), (2, 1), (3, 1)] or [(1, 0), (0, 1), (1, 1), (2, 1)]:

 0123       012
0....      0.#.
1####  or  1###
2....      2...
3....

you can calculate the new coordinates using

x_new = y_old
y_new = 1 - (x_old - (me - 2))

for clockwise rotation and

x_new = 1 - (y_old - (me - 2))
y_new = x_old

for counter-clockwise rotation. me is the maximum extent of the block, i.e. 4 for I-blocks, 2 for O-blocks and 3 for all other blocks.

for 3x3 sized tetris pieces flip x and y of your piece then swap the outer columns that's what I figured out some time

I have used a shape position and set of four coordinates for the four points in all the shapes. Since it's in 2D space, you can easy apply a 2D rotational matrice to the points.

The points are divs so their css class is turned from off to on. (this is after clearing the css class of where they were last turn.)

Python:

pieces = [
    [(0,0),(0,1),(0,2),(0,3)],
    [(0,0),(0,1),(1,0),(1,1)],
    [(1,0),(0,1),(1,1),(1,2)],
    [(0,0),(0,1),(1,0),(2,0)],
    [(0,0),(0,1),(1,1),(2,1)],
    [(0,1),(1,0),(1,1),(2,0)]
]

def get_piece_dimensions(piece):
    max_r = max_c = 0
    for point in piece:
        max_r = max(max_r, point[0])
        max_c = max(max_c, point[1])
    return max_r, max_c

def rotate_piece(piece):
    max_r, max_c = get_piece_dimensions(piece)
    new_piece = []
    for r in range(max_r+1):
        for c in range(max_c+1):
            if (r,c) in piece:
                new_piece.append((c, max_r-r))
    return new_piece

In Java:

private static char[][] rotateMatrix(char[][] m) {
    final int h = m.length;
    final int w = m[0].length;
    final char[][] t = new char[h][w];

    for(int y = 0; y < h; y++) {
        for(int x = 0; x < w; x++) {
            t[w - x - 1][y]  = m[y][x];
        }
    }
    return t;
}

A simple Tetris implementation as a single-page application in Java: https://github.com/vadimv/rsp-tetris

Related