# 8.30: Checking for, and Removing, Complete Lines

def isCompleteLine(board, y):
# Return True if the line filled with boxes with no gaps.
for x in range(BOARDWIDTH):
if board[x][y] == BLANK:
return False
return True

def removeCompleteLines(board):
# Remove any completed lines on the board, move everything above them down, and return the number of complete lines.
numLinesRemoved = 0
y = BOARDHEIGHT - 1 # start y at the bottom of the board
while y >= 0:
if isCompleteLine(board, y):
# Remove the line and pull boxes down by one line.
for pullDownY in range(y, 0, -1):
for x in range(BOARDWIDTH):
board[x][pullDownY] = board[x][pullDownY-1]
# Set very top line to blank.
for x in range(BOARDWIDTH):
board[x][0] = BLANK
numLinesRemoved += 1
# Note on the next iteration of the loop, y is the same.
# This is so that if the line that was pulled down is also
# complete, it will be removed.
else:
y -= 1 # move on to check next row up
return numLinesRemoved


The isCompleteLine does a simple check at the row specified by the y parameter. A row on the board is considered to be "complete" when every space is filled by a box. The for loop on line 3 [409] goes through each space in the row. If a space is blank (which is caused by it having the same value as the BLANK constant), then the function return False.

The removeCompleteLines() function will find any complete lines in the passed board data structure, remove the lines, and then shift all the boxes on the board above that line down one row. The function will return the number of lines that were removed (which is tracked by the numLinesRemoved variable) so that this can be added to the score.

The way this function works is by running in a loop starting on line 13 [419] with the y variable starting at the lowest row (which is BOARDHEIGHT - 1). Whenever the row specified by y is not complete, y will be decremented to the next highest row. The loop finally stops once y reaches -1.

The isCompleteLine() function will return True if the line that y is referring to is complete. In that case, the program needs to copy the values of each row above the removed line to the next lowest line. This is what the for loop on line 16 [422] does (which is why its call to the range() function begins at y, rather than 0. Also note that it uses the three argument form of range(), so that the list it returns starts at y, ends at 0, and after each iteration "increases" by -1.)

Let’s look at the following example. To save space, only the top five rows of the board are shown. Row 3 is a complete line, which means that all the rows above it (row 2, 1, and 0) must be "pulled down". First, row 2 is copied down to row 3. The board on the right shows what the board will look like after this is done:

This "pulling down" is really just copying the higher row’s values to the row below it on line 18 [424]. After row 2 is copied to row 3, then row 1 is copied to row 2 followed by row 0 copied to row 1:

Row 0 (the row at the very top) doesn’t have a row above it to copy values down. But row 0 doesn’t need a row copied to it, it just needs all the spaces set to BLANK. This is what lines 20 [426] and 21 [427] do. After that, the board will have changed from the board shown below on the left to the board shown below on the right:

After the complete line is removed, the execution reaches the end of the while loop that started on line 13 [419], so the execution jumps back to the beginning of the loop. Note that at no point when the line was being removed and the rows being pulled down that the y variable changed at all. So on the next iteration, the y variable is pointing to the same row as before.

This is needed because if there were two complete lines, then the second complete line would have been pulled down and would also have to be removed. The code will then remove this complete line, and then go to the next iteration. It is only when there is not a completed line that the y variable is decremented on line 27 [433]. Once the y variable has been decremented all the way to 0, the execution will exit the while loop.