Step 3.2.2: Testing if a piece overlaps

The next one is the overlaps() function that is to check if a piece overlaps the blocks on the playfield. This is a key function as it has to run every time we're about to move or rotate a piece, to check whether a move is legal.

If you remember the previous steps, we have defined both the shape and the playfield as integers where each bit corresponds to a block. For this reason we can use bitwise operations to check if the piece overlaps. The only difficulty is to extract the individual parts of the piece that's comparable with a single row of the playfield. I'll try to explain this with the help of the following figure:

The blocks in black are parts of the plyfield and the ones in orange are parts of the piece. We will compare 4 times 2 integers, the rows of the palyfield to the rows of the piece. The former is easy, we just take the corresponding row from the palyfield array. But for the latter we will need bitwise operations to extract a row from the piece. So here's the plan:

The following figure might help you to understand the above steps:

It is worth to code this operation into a separate function, because we will use it for another purpose later! Here is how it can be coded:

REM -- Extract a single row from the shape
FUN extract_row(shape, row!, x!)
  REM -- Step 1: mask the nibble
  REM -- Step 2: move it to the left end
  REM -- Step 3: move it right by the piece's  X position    
  RETURN RSHIFT(LSHIFT(shape & mask[row!], bitpos![row!]), x!)
  
  REM -- Helper data for bitwise calculations
  DATA mask[] = %1111000000000000, %0000111100000000, ~
                %0000000011110000, %0000000000001111
  DATA bitpos![] = 0, 4, 8, 12
ENDFUN

Unlike in CBM BASIC, the bitwise AND operator in XC=BASIC is the ampersand (&) character. The keyword AND is different. It is a conditional operator that can be used in an IF ... THEN statement.

When we have extracted all rows from the shape, we can compare them with the palyfield easily using the bitwise AND operation. If the AND operation results in true for any bit, it means there was an overlap.

Here is the overlaps() function:

REM -- Check if the piece overlaps the playfield
REM -- at the given position
REM -- Returns 1 or 0 (true or false)
FUN overlaps!(shape_no!, rotation!, x!, y!)
  REM -- Get shape by number and rotation
  tmp_shape = get_shape(shape_no!, rotation!)
  REM -- Check row by row
  FOR i! = 0 TO 3
    playfield_row = \playfield[i! + y!]
    piece_row = extract_row(tmp_shape, i!, x!)
    IF piece_row & playfield_row <> 0 THEN RETURN 1
  NEXT
  RETURN 0
ENDFUN

Read the above code carefully and notice the following:

Are you still following? Good, let's move on to the next routine.