Skip to content

refactor: migrate Tetris to full ECS patterns #63

@salazarsebas

Description

@salazarsebas

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

  1. Define the five components implementing ComponentTrait with serialize/deserialize.

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

  3. Extract inline logic into named system functions. The GravitySystem and LineClearSystem are the core Tetris mechanics that benefit most from separation.

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

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Stellar WaveIssues in the Stellar wave program

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions