====== 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: {{ :tutorial1-tetris:overlap_check.png?nolink |}} 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: * Since each row in the piece is a 4-bit nibble, we can extract them by masking out the rest of the nibbles: the first row equals ''shape & %1111000000000000'', the second row equals ''shape & %0000111100000000'', etc... * We need to align the rows that we have just extracted. So we need to shift the second row 4 bits to the left, the third row 8 bits and the last row 12 bits. This way they'll all be placed in the left end. * Now we have to shift all of them to right as much as the piece's X position, to be able to compare them with the palyfield. The following figure might help you to understand the above steps: {{ :tutorial1-tetris:extract_shape.png?nolink |}} 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 ''[[:ifthenelse|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: * The function returns a byte, so we've appended an ''!'' to its name * We need to access the global variable ''playfield'' from within the function so we must prepend it with a backslash: ''\playfield'' Are you still following? Good, let's move on to the next routine. <- step3.2.1|Previous page ^ start|Tetris tutorial ^ step 3.2.3|Next page ->