# How do I detect and remove completed rows of blocks in Tetris?

I am making Tetris for a learning experience in XNA, and I'm having trouble deleted completed rows.

I am having an issue with deleting rows, for some reason when I go to delete a row, I end up creating more blocks or not deleting all of the blocks in the row. The method I am using to detect and remove blocks is as follows:

    // 'rowCount' is an int[20] holding the number of blocks in each row
// (my playing field is 20 rows tall and 10 blocks wide).
for (int i = 0; i < rowCount.Length; i++)
{
if (rowCount[i] >= 10)
{
// The row is full, remove the blocks.
// 'blocks' is a list of all blocks that have settled.
for (int j = 0; j < blocks.Count; j++)
{
if (blocks[j].Row == i)
{
// If the settled block is in this row, remove it.
blocks.RemoveAt(j);
rowCount[i]--;
}
}

// Move any blocks above the now-empty row down one row.
foreach (Block b in blocks)
{
if (b.Row < i)
{
b.Row++;
rowCount[b.Row]++;
}
}
}
}


This is done in my main Update method after I've determined if the current block has settled or not.

As implemented, this algorithm will usually end up recording more than ten blocks in some rows and will not correctly clear completed rows and move the rows above down one unit. Why is this, and what can I do to fix the algorithm?

• You provided a lot of code, most of which didn't seem particularly relevant to the core question. I removed most of it to concentrate on the basic algorithm you're driving at so your question reads less like a "debug my code for me" question and more like something that has a lasting value on the site (and is less likely to be voted for closure). I also tried to mark up the code with comments describing your algorithm in plain English. You should try to do these sorts of things with questions in the future. – user1430 Dec 6 '13 at 6:44
• (And please re-edit the correction is my interpretation of your algorithm was incorrect.) – user1430 Dec 6 '13 at 6:46
• This question appears to be off-topic because it is about debugging code for you. – bummzack Dec 6 '13 at 7:51

It looks to me like the crux of your problem is the foreach loop at the bottom, which contains this:

if (b.Row < i)
{
b.Row++;
rowCount[b.Row]++;
}


For every (settled) block on the field, you are checking if the block is above the recently-cleared row (assuming row 0 is the top of the screen and your rows count downward to 19 at the bottom).

If a block is above the cleared row, you move it down by increasing its row index. You then update the count of blocks in its new row to account for the fact that you moved it. But you don't decrement the block count from the old row. Over time this will cause your row counts to creep outside your expected ranges as more and more settled blocks fall into the spots vacated by cleared rows. You should probably --rowCount[b.Row] before you b.Row++ to handle this.

I think your general approach is sound, although your code might be more readable if you chose to eschew the "list of settled blocks" and "blocks per row" structures and instead simply stored a simple (2D) array of blocks. Checking, clearing, and moving blocks down would then require only one data structure for reading and writing, which is less prone to these sorts of errors.

The actual act of displacing the blocks when a row is cleared would be slightly less efficient, but for Tetris I don't think that's going to hurt you much.

• Yes, that was one of the problems that I encountered. Thanks! – TheUnrealMegashark Dec 6 '13 at 14:44
• You're welcome. If you find an answer useful, you should indicate that by clicking the up arrow in the top-left of the answer box. Also, if you find a particular answer that solved your problem you should mark it as the "accepted" answer by clicking the green check box. You can accept your own answer (although you can't upvote your own answer). See the faq for more about how this site works. – user1430 Dec 6 '13 at 16:18
• I know about the upvote and accepted answer, I just couldn't accept an answer that soon or upvote a comment due to my low reputation. – TheUnrealMegashark Dec 6 '13 at 21:49

I didn't decrement my increment variable (j) when I found a block to delete, so it wouldn't check the next block, rather, it would skip over it.