# Spacetris — Challenge Mode (Asteroids) Implementation Spec for VS Code AI Agent

> Goal: Implement/extend **CHALLENGE** gameplay in Spacetris (not a separate mode), based on 100 levels with **asteroid** prefilled blocks that must be destroyed to advance.

---

## 1) High-level Requirements

### Modes
- Existing mode remains **ENDLESS**.
- Add/extend **CHALLENGE** mode with **100 levels**.

### Core Challenge Loop
- Each level starts with **prefilled obstacle blocks** called **Asteroids**.
- **Level N** starts with **N asteroids** (placed increasingly higher as level increases).
- Player advances to the next level when **ALL asteroids are destroyed**.
- Gravity (and optionally lock pressure) increases per level.

### Asteroid concept
Asteroids are special blocks placed into the grid at level start:
- They are **not** player-controlled pieces.
- They have **types** and **hit points** (how many times they must be cleared via line clears).

---

## 2) Asteroid Types & Rules

Define asteroid types and their behavior:

### A) Normal Asteroid
- `hitsRemaining = 1`
- Removed when its row is cleared once.
- Never moves (no gravity).

### B) Armored Asteroid
- `hitsRemaining = 2`
- On first line clear that includes it: decrement hits and change to cracked visual state.
- On second clear: removed.
- Never moves (no gravity).

### C) Falling Asteroid
- `hitsRemaining = 2`
- On first clear: decrement hits, then **becomes gravity-enabled** (drops until resting).
- On second clear: removed.

### D) Core Asteroid (late levels)
- `hitsRemaining = 3`
- On each clear: decrement hits and change visual state.
- After first hit (or after any hit — choose consistent rule) it becomes gravity-enabled.
- On final clear: removed (optionally trigger bigger VFX).

**Important:** These are all within the same CHALLENGE mode.

---

## 3) Level Progression Rules (100 Levels)

### Asteroid Count
- `asteroidsToPlace = level` (Level 1 -> 1 asteroid, Level 2 -> 2 asteroids, …)
- Recommendation for implementation safety:
  - If `level` becomes too large to place comfortably, still place `level` but distribute across more rows and allow overlaps only if empty.
  - If needed, implement a soft cap for placement attempts (avoid infinite loops). If cannot place all, place as many as possible and log/telemetry.

### Placement Height / Region
- Early levels: place in bottom 2–4 rows.
- Mid levels: bottom 6–10 rows.
- Late levels: up to ~half board height.
- Use a function to define a `minRow..maxRow` region based on `level`.

Example guidance:
- `maxRow = boardHeight - 1`
- `minRow = boardHeight - 1 - clamp(2 + level/3, 2, boardHeight/2)`

### Type Distribution by Level (suggested)
- Levels 1–9: Normal only
- Levels 10–19: add Armored (small %)
- Levels 20–59: add Falling (increasing %)
- Levels 60–100: add Core (increasing %)

---

## 4) Difficulty Scaling

### Gravity Speed Scaling
Implement per-level gravity scale:
- `gravity = baseGravity * (1.0f + level * 0.02f)` (tune)
- Or use a curve/table.

Optional additional scaling:
- Reduced lock delay slightly at higher levels
- Slightly faster DAS/ARR (if implemented)

---

## 5) Win/Lose Conditions

### Level Completion
- Level completes when: `asteroidsRemaining == 0`
- Then:
  - Clear board (or keep board — choose one consistent behavior; recommended: **clear board** for clean progression).
  - Show short transition (optional).
  - Load next level, until level 100.
- After level 100 completion: show completion screen + stats.

### Game Over
- Standard Spacetris game over: stack reaches spawn/top (existing behavior).

---

## 6) Rendering / UI Requirements

### Visual Differentiation
Asteroids must be visually distinct from normal tetromino blocks.

Provide visual states:
- Normal: rock texture
- Armored: plated / darker
- Cracked: visible cracks
- Falling: glow rim / hazard stripes
- Core: pulsing inner core

Minimum UI additions (Challenge):
- Display `LEVEL: X/100`
- Display `ASTEROIDS REMAINING: N` (or an icon counter)

---

## 7) Data Structures (C++ Guidance)

### Cell Representation
Each grid cell must store:
- Whether occupied
- If occupied: is it part of normal tetromino or an asteroid
- If asteroid: type + hitsRemaining + gravityEnabled + visualState

Suggested enums:
```cpp
enum class CellKind { Empty, Tetromino, Asteroid };

enum class AsteroidType { Normal, Armored, Falling, Core };

struct AsteroidCell {
    AsteroidType type;
    uint8_t hitsRemaining;
    bool gravityEnabled;
    uint8_t visualState; // optional (e.g. 0..n)
};

struct Cell {
    CellKind kind;
    // For Tetromino: color/type id
    // For Asteroid: AsteroidCell data
};
````

---

## 8) Line Clear Processing Rules (Important)

When a line is cleared:

1. Detect full rows (existing).
2. For each cleared row:

   * For each cell:

     * If `kind == Asteroid`:

       * `hitsRemaining--`
       * If `hitsRemaining == 0`: remove (cell becomes Empty)
       * Else:

         * Update its visual state (cracked/damaged)
         * If asteroid type is Falling/Core and rule says it becomes gravity-enabled on first hit:

           * `gravityEnabled = true`
3. After clearing rows and collapsing the grid:

   * Apply **asteroid gravity step**:

     * For all gravity-enabled asteroid cells: let them fall until resting.
     * Ensure stable iteration (bottom-up scan).
4. Recount asteroids remaining; if 0 -> level complete.

**Note:** Decide whether gravity-enabled asteroids fall immediately after the first hit (recommended) and whether they fall as individual cells (recommended) or as clusters (optional later).

---

## 9) Asteroid Gravity Algorithm (Simple + Stable)

Implement a pass:

* Iterate from bottom-2 to top (bottom-up).
* If cell is gravity-enabled asteroid and below is empty:

  * Move down by one
* Repeat passes until no movement OR do a while-loop per cell to drop fully.

Be careful to avoid skipping cells when moving:

* Use bottom-up iteration and drop-to-bottom logic.

---

## 10) Level Generation (Deterministic Option)

To make challenge reproducible:

* Use a seed: `seed = baseSeed + level`
* Place asteroids with RNG based on level seed.

Placement constraints:

* Avoid placing asteroids in the spawn zone/top rows.
* Avoid creating impossible scenarios too early:

  * For early levels, ensure at least one vertical shaft exists.

---

## 11) Tasks Checklist for AI Agent

### A) Add Challenge Level System

* [ ] Add `currentLevel (1..100)` and `mode == CHALLENGE`.
* [ ] Add `StartChallengeLevel(level)` function.
* [ ] Reset/prepare board state for each level (recommended: clear board).

### B) Asteroid Placement

* [ ] Implement `PlaceAsteroids(level)`:

  * Determine region of rows
  * Choose type distribution
  * Place `level` asteroid cells into empty spots

### C) Line Clear Hook

* [ ] Modify existing line clear code:

  * Apply asteroid hit logic
  * Update visuals
  * Enable gravity where required

### D) Gravity-enabled Asteroids

* [ ] Implement `ApplyAsteroidGravity()` after line clears and board collapse.

### E) Level Completion

* [ ] Track `asteroidsRemaining`.
* [ ] When 0: trigger level transition and `StartChallengeLevel(level+1)`.

### F) UI

* [ ] Add level & asteroids remaining display.

---

## 12) Acceptance Criteria

* Level 1 spawns exactly 1 asteroid.
* Level N spawns N asteroids.
* Destroying asteroids requires:

  * Normal: 1 clear
  * Armored: 2 clears
  * Falling: 2 clears + becomes gravity-enabled after first hit
  * Core: 3 clears (+ gravity-enabled rule)
* Player advances only when all asteroids are destroyed.
* Gravity increases by level and is clearly noticeable by mid-levels.
* No infinite loops in placement or gravity.
* Challenge works end-to-end through level 100.

---

## 13) Notes / Tuning Hooks

Expose tuning constants:

* `baseGravity`
* `gravityPerLevel`
* `minAsteroidRow(level)`
* `typeDistribution(level)` weights
* `coreGravityOnHit` rule

---