# 8.29: The isOnBoard() and isValidPosition() Functions

def isOnBoard(x, y):
return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT

# Return True if the piece is within the board and not colliding
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
isAboveBoard = y + piece['y'] + adjY < 0
if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:
continue
if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):
return False
if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:
return False
return True


The isOnBoard() is a simple function which checks that the XY coordinates that are passed represent valid values that exist on the board. As long as both the XY coordinates are not less 0 or greater than or equal to the BOARDWIDTH and BOARDHEIGHT constants, then the function returns True.

The isValidPosition() function is given a board data structure and a piece data structure, and returns True if all the boxes in the piece are both on the board and not overlapping any boxes on the board. This is done by taking the piece’s XY coordinates (which is really the coordinate of the upper right box on the 5x5 boxes for the piece) and adding the coordinate inside the piece data structure. Here’s a couple pictures to help illustrate this:

On the left board, the falling piece’s (that is, the top left corner of the falling piece’s) XY coordinates are $$(2, 3)$$ on the board. But the boxes inside the falling piece’s coordinate system have their own coordinates. To find the "board" coordinates of these pieces, we just have to add the "board" coordinates of the falling piece’s top left box and the "piece" coordinates of the boxes.

On the left board, the falling piece’s boxes are at the following "piece" coordinates:

$(2, 2), (3, 2), (1, 3), (2, 3) \nonumber$

When we add the $$(2, 3)$$ coordinate (the piece’s coordinates on the board) to these coordinates, it looks like this:

$(2 + 2, 2 + 3), (3 + 2, 2 + 3), (1 + 2, 3 + 3), (2 + 2, 3 + 3) \nonumber$

After adding the $$(2, 3)$$ coordinate the boxes are at the following "board" coordinates:

$(4, 5), (5, 5), (3, 6), (4, 6) \nonumber$

And now that we can figure out where the falling piece’s boxes are as board coordinates, we can see if they overlap with the landed boxes that are already on the board. The nested for loops on lines 7 [396] and 8 [397] go through each of the possible coordinates on the falling piece.

We want to check if a box of the falling piece is either off of the board or overlapping a box on the board. (Although one exception is if the box is above the board, which is where it could be when the falling piece just begins falling.) Line 9 [398] creates a variable named isAboveBoard that is set to True if the box on the falling piece at the coordinates pointed to be x and y is above the board. Otherwise it is set to False.

The if statement on line 10 [399] checks if the space on the piece is above the board or is blank. If either of those is True, then the code executes a continue statement and goes to the next iteration. (Note that the end of line 10 [399] has [y][x] instead of [x][y]. This is because the coordinates in the PIECES data structure are reversed. See the previous section, "Setting Up the Piece Templates").

The if statement on line 12 [401] checks that the piece’s box is not located on the board. The if statement on line 14 [403] checks that the board space the piece’s box is located is not blank. If either of these conditions are True, then the isValidPosition() function will return False. Notice that these if statements also adjust the coordinates for the adjX and adjY parameters that were passed in to the function.

If the code goes through the nested for loop and hasn’t found a reason to return False, then the position of the piece must be valid and so the function returns True on line 16 [405].