Tetris V2 - Add Hold Feature and Queue

Posted on: June 12, 2023

Today I have added a Hold feature and Queue to my Tetris V2. In this blog post, I will talk about why and how I rewrote the logic of the generate piece method in order to add these two features.

Hold and Queue

Firstly let me explain what these two features do.

Hold: To hold the unwanted piece temporarily on the left hand side grid (Hold Grid). If you don't like the current piece, you can click hold to swap with the piece held in the hold grid. Or if hold grid is empty, the current piece will be held and the next piece in the queue becomes the current piece.

Queue: It is a list of next pieces shown on the right hand side grid (Queue Grid). The top one will be the next piece to appear on the main grid and the rest will push up.

Why do I need to change the way the piece is generated

Initially, I have created an array of pieces with calculated initial positions according to the Main Grid size, the center cell of each piece has the coordinates of (x: main_grid_width / 2, y: main_grid_height). Then a piece will be picked randomly in each round using sample method from lodash package. In this case, the generated piece will always start at the center top of the Grid component, and it does not matter what size the Main Grid has. This method works perfectly before the hold feature and queue were added.

However I cannot generate pieces to display on Hold Grid or Queue Grid using this pieces array as they have different sizes to the Main Grid. I would need to create two other arrays for these two grids, but this then violates the DRY prinicple.

I also realised that the pieces shown on Hold Grid and Queue Grid do not need to know all the information that an actual piece knows, such as its centerIndex, Cell component information and Piece component functions as these pieces do not need to move.

How I changed the generate piece method

  1. Changed the pieces array to an object:

    a. Each piece now has a name attribute as its key.

    b. Each piece now uses an array of arrays consisting 1 and 0s to indicate the shape of each piece, instead of holding the exact positions.

    c. Each piece has a color attribute as before.

    d. Each piece has a centerIndex attribute for rotation. If the centerIndex is null then it cannot rotate, e.g. a Square piece.

    Now the Pieces object is a constant, and can be reused. In this way, Hold and Queue only need to hold the piece name and search in the Pieces object using the name for the desired information of the piece.

  2. If the piece name is known, placePieceOnGrid function can return a piece with calculated positions on the grid

    a. It gets all information of the piece by searching its name in the Pieces constant.

    b. It uses getPiecePositionsOnGrid method which gets the piece shape and calculates the initial positions of the piece on the grid according to the grid width and height.

    In this case, a piece can be placed in any sized grid only using its name. This function is very useful as Queue is just an array of piece names, I can easily pop out the top piece name from the Queue and place it on the Main Grid.

  3. generatePiece function uses getRandomPieceName function to pick a random piece name from Pieces object keys array, and then place it on the Main Grid using placePieceOnGrid.

What are the advantages of the new methood

  1. The functions are more flexible and reusable, so it obeys the DRY principle.

  2. Piece should always have the same shape so it should be a constant for easy maintenance as it is now.

  3. Only hold the minimum essential information for better memory performance.