Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Naive Gravity for Tetris game using 2D Array for the playfield

I'm writing a Tetris-clone and I'm prototyping in C#. The final code is supposed to run on an embedded system (using an 8-Bit CPU and very little RAM), so I'm trying to use a naïve algorithm to do line clear.

Right now, my playfield is a 2D Array:

private readonly TetrominoType[][] _playfield;

(where TetrominoType is an enum to indicate either None or one of the 7 types, used for coloring blocks)

When a line is cleared, I want to modify this array in-place, which is where my problem is. Take this example:

   Before       After
0 #      #     #      #
1 #      #     #      #
2 #      #     #      #
3 #      #     #      #
4 #      #     #      #
5 #xxxxxx#     #      #
6 #x   xx#     #      #
7 #xxxxxx#     #      #
8 #xxxxxx#     #x   xx#
9 #x xxxx#     #x xxxx#
  ########     ########

I have already determined that lines 5, 7 and 8 need to be removed and thus other lines should fall down, leaving me with the state on the right.

My naïve way is to iterate backwards and copy the line above a cleared one, basically:

for(int iy = 9; iy >= 0; iy--) {
    if(_linesToClear.Contains(iy)) {
        for(int ix = 0; ix < 6; ix++) {
            _playfield[iy][ix] = _playfield[iy-1][ix];
        }
    }
 }

The problem here is that the line above might also be cleared (e.g, if iy == 8 then I don't want to copy line 7 but line 6) and also that I need to clear the copied line (iy-1) - or copy the line above that one which in turn need to trickle upward.

I tried counting how many lines I already skipped, but that works only if I create a new array and then swap them out, but I can't get the math work for in-place modification of the playfield array.

It's possibly really simple, but I'm just not seeing the algorithm. Does anyone have some insight how I can do this?

like image 754
Michael Stum Avatar asked Oct 20 '22 15:10

Michael Stum


2 Answers

The main problem is multiple cleared lines, so we need to make sure that when you have multiple cleared lines in a row to move everything down through all of them. Since you have a list of which lines need to be cleared, instead of just copying the line above it, you can find how far up the next non-cleared line is, and move everything above it down that many lines. For example, you could do this:

for(int iy = 9; iy >= 0; iy--)
{
    if(_linesToClear.Contains(iy))
    {
        int nextLineIndex = iy-1;
        while( _linesToClear.contains(nextLineIndex) && nextLineIndex >= 0 )
        {
            nextLineIndex--;
        }
        if ( nextLineIndex >= 0 )
        {
            int amountToDrop = iy - nextLineIndex
            for(int ix = 0; ix < 6; ix++)
            {
                _playfield[iy][ix] = _playfield[iy-amountToDrop][ix];
            }
        }
    }
 }

This would figure out how many cleared lines there are in a row, then drop everything down that many lines. I hope this helps!

like image 169
JPLynk Avatar answered Nov 03 '22 01:11

JPLynk


Would it work?

int k = 0;
for(int iy = 9; iy >= 0; iy--) {
    if(!_linesToClear.Contains(iy)) {
        for(int ix = 0; ix < 6; ix++) {
            _playfield[iy + k][ix] = _playfield[iy][ix];
        }
    }
    else
        k++;
}
like image 23
AlexD Avatar answered Nov 03 '22 00:11

AlexD