Architecture

Architecture

Module Dependency Graph

main.rs
  ├── game.rs ──→ world.rs
  │             ├→ player.rs
  │             ├→ encounter.rs
  │             └→ audio.rs
  └── ui.rs ───→ game.rs (reads state)
               ├→ world.rs (reads map)
               └→ player.rs (reads stats)

Design Principles

Renderer isolation

ui.rs only reads game state via &Game. Game logic never calls rendering functions. This separation enables swapping the terminal renderer for a graphical one (Bevy, wgpu) without touching game logic.

Event-driven audio

Sound effects are triggered by SoundEvent enum variants. The AudioEngine is optional (Option<AudioEngine>) — the game runs silently if no audio hardware is available.

Content separation

All educational content lives in encounter.rs as data. The challenge format is extensible — add a Challenge struct to a floor function to add content. Future: load from YAML/JSON for hot-reload.

Procedural generation

BSP (Binary Space Partitioning) produces unique dungeon layouts every run. Features (terminals, traps, chests, locked doors) are placed probabilistically per floor.

File Sizes

File Lines Responsibility

main.rs

47

Terminal setup, game loop

game.rs

497

State machine, input, game logic

world.rs

500

BSP dungeon gen, tiles, FOV

player.rs

112

Player state, inventory, items

encounter.rs

2,813

107 challenges, answer checking

audio.rs

218

Synthesized sound via rodio

ui.rs

1,305

ratatui rendering, minimap, animations

Scale Path

Layer Current Future

Renderer

ratatui (terminal)

Bevy 2D/3D or wgpu

Input

crossterm keys

Gamepad, mouse, touch

Audio

Sine wave synthesis

Asset pipeline (OGG/WAV)

Content

Hardcoded Rust

YAML/JSON hot-load

World

Single-player local

Networked multiplayer

State

In-memory only

Save/load (serde + JSON)