Files
spacetris/challenge_mode.md

287 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 24 rows.
- Mid levels: bottom 610 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 19: Normal only
- Levels 1019: add Armored (small %)
- Levels 2059: add Falling (increasing %)
- Levels 60100: 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
---