# Tetris II

> This is the second part of the Tetris challenge series. In this version, the user interface, game loop, and React components are already implemented for you. Your goal is to focus purely on the game logic by completing the utility functions in `src/utils.ts`. You will implement piece generation, movement, collision detection, and row clearing to make the game functional.

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

## Overview

This is the second part of the Tetris challenge series. In this version, the user interface, game loop, and React components are already implemented for you. Your goal is to focus purely on the game logic by completing the utility functions in `src/utils.ts`. You will implement piece generation, movement, collision detection, and row clearing to make the game functional.


## Requirements

### Application Logic (Provided in `App.tsx`)

The main application component is already implemented and handles:
- Game state management (board, piece, score, game over).
- The game loop.
- Canvas rendering (calling `drawBoard` and `drawPiece`).
- Keyboard event listeners.

### Utilities (`src/utils.ts`)

You must implement the following functions marked with `// complete function` (and `checkCollision` which is required by them):

1.  **`randomPiece()`**:
    - Select a random piece shape and color from the `PIECES` array.
    - Set its initial position to the horizontal center of the board and the top row (`y=0`).

2.  **`checkCollision(board, piece)`**:
    - Return `true` if any part of the `piece` overlaps with:
        - The board boundaries (left, right, bottom).
        - Existing solidified blocks on the board.
    - Return `false` otherwise.

3.  **`solidifyPiece(board, piece)`**:
    - Merge the `piece` into the `board`.
    - Return a **new** board grid with the piece's shape permanently added (using non-zero values).

4.  **`removeCompletedRows(board)`**:
    - Identify rows that are completely filled (no zeros).
    - Remove those rows.
    - Add an equivalent number of new empty rows to the top of the board.
    - Return an object: `{ board: number[][], removed: number }` (where `removed` is the count of cleared rows).

5.  **`movePiece(board, piece, direction)`**:
    - Handle directions: `"left"`, `"right"`, `"down"`, `"rotate"`.
    - Calculate the new candidate position/shape.
    - Use `checkCollision` to verify if the move is valid.
    - Return the new piece state if valid, or the original piece if invalid.

6.  **`rotatePiece(shape)`**:
    - Rotate the 2D array `shape` 90 degrees clockwise.
    - Return the new rotated shape.


## Notes

- **Focus on `src/utils.ts`**: The `App.tsx` file is already complete. It handles the React state, game loop (`requestAnimationFrame`), and canvas rendering. Your task is to implement the logic functions it calls.
- **Board Dimensions**: The board size is defined by `ROW` and `COL` constants derived from `WIDTH`, `HEIGHT`, and `CELL_SIZE`.
- **Coordinate System**:
  - `x` corresponds to columns (horizontal).
  - `y` corresponds to rows (vertical).
  - The top-left corner is `(0, 0)`.
- **Immutability**: Functions like `solidifyPiece` and `removeCompletedRows` should return new copies of the board/state, avoiding direct mutation of the arguments.
- **Collision Detection**:
  - Check boundaries: `x` must be within `[0, COL-1]` and `y` within `[0, ROW-1]`.
  - Check existing blocks: The board cell at `(y, x)` must be `0` (empty).
- **Rotation**: Standard Tetris rotation is 90 degrees clockwise.
- **Row Clearing**: When a row is full (all cells are non-zero), it is removed, and all rows above it shift down. New empty rows are added at the top.


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


