Step 2.2: Designing the shapes

The following shapes may appear in a standard Tetris game:

They are often called I, J, L, O, S, T and Z, respectively.

If we take all of them in all rotations, we will get 28 shapes:

Now we must decide how we store each shape in memory. We have 28 shapes, four times each of the 7 distinct shapes (we will store the 4 rotations for each shape). We know that they'll be all 4×4 matrices, holding 16 squares blocks each.

It seems obvious that one square should be mapped to one bit in memory: it can hold a value 0 or 1, meaning a square is empty or set. And since there are 16 squares in each shape, one shape can be stored in a 16-bit range, that is exactly the length of an integer in XC=BASIC. Moreover, XC=BASIC features bitwise operations on 16-bit integers that can be useful when we need to check if shapes overlap, or merge the shape to the playfield, etc… More about this later.

So how do we encode a single shape in 16 bits? By simply reading out the squares from top left to bottom right and writing the bits one after another, for example:

The T shape will be encoded as 0000 1110 0100 0000 in binary form, which is decimal 16398. But since XC=BASIC accepts numbers in binary form, we don't have to care about the latter.

Okay, so we can store all shapes in an array of 28 integers.

Let's roll up our sleeves and encode all the shapes in a single DATA statement. I did the dirty job for you and here is the statement that holds all of them:

REM -- Shapes of all pieces in all rotations
DATA shapes[] = %0100010001000100, %0000111100000000, %0010001000100010, %0000000011110000, ~
                %0100010011000000, %1000111000000000, %0110010001000000, %0000111000100000, ~
                %0100010001100000, %0000111010000000, %1100010001000000, %0010111000000000, ~
                %1100110000000000, %1100110000000000, %1100110000000000, %1100110000000000, ~
                %0000011011000000, %1000110001000000, %0110110000000000, %0100011000100000, ~
                %0000111001000000, %0100110001000000, %0100111000000000, %0100011001000000, ~
                %0000110001100000, %0100110010000000, %1100011000000000, %0010011001000000

Ther are several important things to note here:

You can read more about the DATA statement here.

Let's define another array that holds the color code for each shape:

REM -- Piece color codes
DATA colors![] = 14, 6, 8, 7, 5, 4, 2

This time the ! sigil is appended to the variable name which means it is of the byte type, a value betweeen 0 and 255.

Good job, we have found a data type for the shapes and written a DATA statement that holds all of them in an array.

Let's move on to the next page where we'll design the playfield.