#43Tetris
Overview
This is a classic Tetris game implemented in React using a canvas for rendering. The game allows players to move, rotate, and drop pieces, complete rows to earn points, and ends when new pieces cannot be placed on the board.
Requirements
Application logic (App.tsx)
-
Manage game state:
- Board
- Current piece
- Game running state
- Game over state
- Points
-
Implement a game loop (using
requestAnimationFrame) to move the piece down automatically. -
Handle user interactions:
- Start: initialize board, piece, points, and start the game loop.
- Reset: reset the game to its initial state.
-
When a piece can no longer move down:
- Solidify it into the board
- Remove completed rows
- Update points (e.g. 100 points per row)
- Spawn a new piece
-
Detect Game Over when a new piece collides immediately on spawn.
-
When the game is over:
- Stop the game loop
- Show the
Game Over!overlay (data-testid="game-over")
Utilities (utils.ts)
- Implement
createEmptyBoard()to return aROW x COLgrid filled with zeros. - Implement
randomPiece()to return a random piece with an initial position at the top of the board. - Implement
checkCollision()to detect collisions with:- Board boundaries
- Existing solidified blocks
- Implement
solidifyPiece()to merge the current piece into the board. - Implement
removeCompletedRows()to:- Remove full rows
- Shift remaining rows down
- Return how many rows were removed
- Implement
rotatePiece()to rotate a piece clockwise. - Implement
movePiece()to move or rotate a piece while preventing invalid moves. - Implement
drawBoard()to render the board on the canvas. - Implement
drawPiece()to render the active piece on the canvas.
Notes
- The starting point is a simple
App.tsxwith a canvas,StartandResetbuttons, and a points counter. Core game logic such as piece generation, board updates, collision detection, row removal, and scoring should be complete inutils.ts. - The board size is calculated from
WIDTH / CELL_SIZE(columns) andHEIGHT / CELL_SIZE(rows). Avoid off-by-one errors. - Pieces should start at the horizontal middle (
Math.floor(COL / 2)) and top (y = 0) when spawned. - Collision checks must consider both the board edges and solidified blocks.
- Solidifying a piece should not mutate the original board (always return a new board).
- Removing completed rows should maintain the total number of rows (
ROW) by adding empty rows at the top. - Rotations may cause collisions; ensure
movePiece()prevents invalid rotations. - Rendering on the canvas must respect
CELL_SIZEfor correct scaling. - Game over is triggered when a new piece collides immediately on spawn.
- Points are calculated based on rows removed and updated after each piece is solidified.
Tests
- renders the app title
- drawBoard draws filled cells
- drawPiece draws piece at correct position
- drawPiece does not draw zero cells
- drawPiece sets the correct fillStyle for piece color
- drawBoard sets fillStyle to black for filled cells
- drawBoard and drawPiece do not draw zeros
- creates an empty board
- detects collision with board boundaries
- solidifies piece on board correctly
- removes completed rows
- rotates piece correctly
- randomPiece returns a valid piece
- solidify + removeCompletedRows integration
- detects collision after rotation
- detects lateral collisions
- detects collision with existing blocks on board
- does not detect collision when piece is adjacent to blocks
- solidifyPiece does not mutate original board
- does not remove rows that are not fully completed
- moves piece left
- moves piece right with ArrowRight
- moves piece down with ArrowDown
- does not move piece left if collision
- does not move piece right if collision
- increments points when rows are completed
- sets game over when a new piece collides immediately
- startGame initializes board, piece, points, and isGameStarted
- resetGame clears board, points, and game state
- shows Game Over when board is already full