Context
The Tetris example imports cougr_core::prelude::* but uses ECS in a superficial way — it creates an ephemeral World only inside try_move() for collision checking, then discards it. The rest of the game is a traditional state machine with plain structs and direct storage access.
This makes Tetris one of only two examples (alongside Asteroids) that don't properly demonstrate Cougr's ECS architecture. Other examples like Snake, Flappy Bird, and Tic Tac Toe show how to structure game logic around entities, components, and systems.
Current State
- Creates a
World inside try_move() only for collision — world is not persistent
- All game state lives in a monolithic
GameState struct stored directly
- No
ComponentTrait implementations
- No system functions — all logic is inline in contract methods
- Has 6 basic tests that work but don't exercise ECS
Goal
Scope: Smart contract logic only — no frontend, UI, or graphical interface is required.
Refactor Tetris to use Cougr ECS patterns while preserving identical game behavior. Tetris is a great ECS candidate because pieces, cells, and the board map cleanly to entities and components.
ECS Design
Components:
| Component |
Fields |
Purpose |
BoardComponent |
cells: Vec<u8>, width: u32, height: u32 |
The playfield grid (0 = empty, 1+ = filled with color) |
ActivePieceComponent |
shape: u8, rotation: u8, x: i32, y: i32 |
Currently falling tetromino |
NextPieceComponent |
shape: u8 |
Preview of next piece |
ScoreComponent |
score: u32, level: u32, lines_cleared: u32 |
Scoring and progression |
GameStatusComponent |
status: enum {Playing, GameOver} |
Game state flag |
Systems:
GravitySystem — moves active piece down one row per tick
MovementSystem — handles left/right/down movement and rotation with boundary checking
CollisionSystem — validates piece placement against board cells and boundaries
LineClearSystem — detects and removes completed rows, shifts rows down
SpawnSystem — places next piece at spawn position, detects game over if blocked
ScoreSystem — awards points based on lines cleared simultaneously (single, double, triple, tetris)
Reference: See examples/snake/ for a similar grid-based game with proper ECS.
Implementation Steps
-
Define the five components implementing ComponentTrait with serialize/deserialize.
-
Refactor the game state to use a persistent world entity with board, score, and status components. The active piece and next piece become separate components on the same entity (or separate entities).
-
Extract inline logic into named system functions. The GravitySystem and LineClearSystem are the core Tetris mechanics that benefit most from separation.
-
Update the 6 existing tests to work through the ECS API. Add tests for line clearing (single, double, triple, tetris), gravity, and spawn-blocked game over.
-
Verify cargo build, cargo test, cargo clippy, and stellar contract build all pass.
Acceptance Criteria
All game behavior must remain identical — same piece shapes, same rotation rules, same scoring, same line clearing. The refactor is structural, not functional. All game state must be managed through Cougr entities and components with ComponentTrait implementations. Game logic must be organized into discrete system functions. The existing 6 tests must be updated and pass. All standard build commands must pass without errors or warnings.
Context
The Tetris example imports
cougr_core::prelude::*but uses ECS in a superficial way — it creates an ephemeralWorldonly insidetry_move()for collision checking, then discards it. The rest of the game is a traditional state machine with plain structs and direct storage access.This makes Tetris one of only two examples (alongside Asteroids) that don't properly demonstrate Cougr's ECS architecture. Other examples like Snake, Flappy Bird, and Tic Tac Toe show how to structure game logic around entities, components, and systems.
Current State
Worldinsidetry_move()only for collision — world is not persistentGameStatestruct stored directlyComponentTraitimplementationsGoal
Refactor Tetris to use Cougr ECS patterns while preserving identical game behavior. Tetris is a great ECS candidate because pieces, cells, and the board map cleanly to entities and components.
ECS Design
Components:
BoardComponentcells: Vec<u8>, width: u32, height: u32ActivePieceComponentshape: u8, rotation: u8, x: i32, y: i32NextPieceComponentshape: u8ScoreComponentscore: u32, level: u32, lines_cleared: u32GameStatusComponentstatus: enum {Playing, GameOver}Systems:
GravitySystem— moves active piece down one row per tickMovementSystem— handles left/right/down movement and rotation with boundary checkingCollisionSystem— validates piece placement against board cells and boundariesLineClearSystem— detects and removes completed rows, shifts rows downSpawnSystem— places next piece at spawn position, detects game over if blockedScoreSystem— awards points based on lines cleared simultaneously (single, double, triple, tetris)Implementation Steps
Define the five components implementing
ComponentTraitwith serialize/deserialize.Refactor the game state to use a persistent world entity with board, score, and status components. The active piece and next piece become separate components on the same entity (or separate entities).
Extract inline logic into named system functions. The
GravitySystemandLineClearSystemare the core Tetris mechanics that benefit most from separation.Update the 6 existing tests to work through the ECS API. Add tests for line clearing (single, double, triple, tetris), gravity, and spawn-blocked game over.
Verify
cargo build,cargo test,cargo clippy, andstellar contract buildall pass.Acceptance Criteria
All game behavior must remain identical — same piece shapes, same rotation rules, same scoring, same line clearing. The refactor is structural, not functional. All game state must be managed through Cougr entities and components with
ComponentTraitimplementations. Game logic must be organized into discrete system functions. The existing 6 tests must be updated and pass. All standard build commands must pass without errors or warnings.