# Tetris

> 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.

- Difficulty: advanced
- Tags: useState, useEffect, game
- Estimated time: 120 minutes
- Tests: 30
- Requires subscription: yes

## 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 a `ROW x COL` grid 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.tsx` with a canvas, `Start` and `Reset` buttons, and a points counter. Core game logic such as piece generation, board updates, collision detection, row removal, and scoring should be complete in `utils.ts`.
- The board size is calculated from `WIDTH / CELL_SIZE` (columns) and `HEIGHT / 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_SIZE` for 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

01. renders the app title
02. drawBoard draws filled cells
03. drawPiece draws piece at correct position
04. drawPiece does not draw zero cells
05. drawPiece sets the correct fillStyle for piece color
06. drawBoard sets fillStyle to black for filled cells
07. drawBoard and drawPiece do not draw zeros

08. creates an empty board
09. detects collision with board boundaries
10. solidifies piece on board correctly
11. removes completed rows
12. rotates piece correctly
13. randomPiece returns a valid piece
14. solidify + removeCompletedRows integration
15. detects collision after rotation
16. detects lateral collisions
17. detects collision with existing blocks on board
18. does not detect collision when piece is adjacent to blocks
19. solidifyPiece does not mutate original board
20. does not remove rows that are not fully completed

21. moves piece left
22. moves piece right with ArrowRight
23. moves piece down with ArrowDown
24. does not move piece left if collision
25. does not move piece right if collision

26. increments points when rows are completed
27. sets game over when a new piece collides immediately
28. startGame initializes board, piece, points, and isGameStarted
29. resetGame clears board, points, and game state
30. shows Game Over when board is already full


