Phase 2: Entities, Organization & Movement¶
Summary¶
Phase 2 defines what simulation entities ARE (personnel, equipment, unit types), how they're organized (military hierarchy, task organization), and how they move across all domains (ground, aerial, naval, submarine, amphibious, airborne). This is the largest phase by module count (28 source modules + 13 YAML data files) and the first to introduce YAML-loaded data definitions.
Test count: 424 new tests (74 entity foundation + 81 unit classes + 39 loader/capabilities + 74 organization + 58 core movement + 79 specialized movement + 23 integration) = 791 total (367 existing + 424 new).
What Was Built¶
Step 1: Entity Foundation (4 files)¶
- core/types.py: Added
Domain(IntEnum: GROUND/AERIAL/NAVAL/SUBMARINE/AMPHIBIOUS) andSide(str Enum: BLUE/RED/NEUTRAL/CIVILIAN) - entities/personnel.py:
CrewMemberdataclass with role, skill, injury, fatigue;PersonnelManagerstatic methods for casualties, effectiveness, experience gain - entities/equipment.py:
EquipmentItemdataclass with condition, reliability, temperature range;EquipmentManagerfor degradation, breakdown, environment stress - entities/events.py: Frozen dataclass events (
UnitCreatedEvent,UnitDestroyedEvent,PersonnelCasualtyEvent,EquipmentBreakdownEvent) - entities/base.py: Expanded with
UnitStatusenum andUnitclass extendingEntitywith personnel, equipment, domain, status
Step 2: Unit Class Definitions (5 files)¶
- ground.py:
GroundUnitwithGroundUnitType,Posture, armor values, mounted state - aerial.py:
AerialUnitwithAerialUnitType,FlightState, fuel, service ceiling, UAV data link - air_defense.py:
AirDefenseUnitwithADUnitType,RadarState, engagement envelope,can_engage()method - naval.py:
NavalUnitwithNavalUnitType, hull integrity, draft, displacement, submarine depth/noise; auto-detects domain from type - support.py:
SupportUnitwithSupportUnitType, cargo capacity
Step 3: YAML Loader & Capabilities (2 modules + 11 YAML files)¶
- loader.py:
UnitDefinitionpydantic model,UnitLoaderfactory class — load YAML definitions, create appropriate Unit subclasses - capabilities.py:
CombatPowerCalculator— assess unit combat power from personnel strength, equipment readiness, training, fatigue, leadership - 11 YAML unit definition files covering armor, infantry, artillery, fixed-wing, rotary-wing, UAV, air defense, surface combatant, submarine, amphibious ship, and logistics truck
Step 4: Organization System (7 files + 2 YAML)¶
- echelons.py:
EchelonLevel(INDIVIDUAL through THEATER), standard definitions with span of control - hierarchy.py:
HierarchyTreeadjacency-list tree with CRUD, chain of command, recursive subordinates - task_org.py:
TaskOrgManager— dynamic command relationship overlays (OPCON, TACON, etc.) - staff.py:
StaffCapabilities— S1–S6 staff section effectiveness modeling - orbat.py:
OrbatLoader— build hierarchy from YAML TO&E definitions - special_org.py:
SpecialOrgManager— SOF, irregular, coalition traits - events.py:
OrgAttachEvent,OrgDetachEvent
Step 5: Core Movement (5 files)¶
- engine.py:
MovementEngine— terrain-aware speed computation (terrain × slope × road × weather × fatigue × night), stochastic noise, move-toward-target - pathfinding.py:
Pathfinder— A* with 8-connectivity, terrain cost, threat avoidance - fatigue.py:
FatigueManager— physical/mental fatigue, sleep debt, altitude penalty, speed/accuracy modifiers - formation.py:
FormationManager— 10 formation types (COLUMN through FILE), position computation, coherence, frontage - events.py:
UnitMovedEvent,FormationChangedEvent,FatigueChangedEvent
Step 6: Specialized Movement (6 files)¶
- obstacles.py:
ObstacleInteraction— assess/bypass/breach/clear/cross, minefield transit risk - mount_dismount.py:
MountDismountManager— state machine for mount/dismount transitions - naval_movement.py:
NavalMovementEngine— sea state speed reduction, fuel cubic law, draft check - submarine_movement.py:
SubmarineMovementEngine— speed-noise curve (20log10), depth bands, snorkel exposure - amphibious_movement.py:
AmphibiousMovementEngine— 6-phase operation (LOADING→INLAND), beach assessment - airborne.py:
AirborneMovementEngine— Gaussian drop scatter, DZ assessment, helicopter insertion
Step 7: Integration Tests & Visualization¶
- 23 integration tests covering full entity stack, organization, movement, pathfinding, naval, submarine, amphibious, airborne, deterministic replay, checkpoint/restore
- Visualization script with unit positions, movement paths, formations, org hierarchy
Design Decisions¶
- Composition over inheritance: Entity → Unit → domain-specific (GroundUnit, etc.). Personnel and equipment are composed as lists, not inherited.
- Dataclass MRO: Entity has required fields (entity_id, position); Unit adds fields with defaults — maintains backward compatibility.
- Domain auto-detection: NavalUnit.post_init sets domain based on naval_type (SSN→SUBMARINE, LHD→AMPHIBIOUS, etc.).
- YAML unit definitions: Data-driven design — adding new unit types = adding YAML, no code changes. Pydantic validates at load time.
- Task org overlay: Separate from organic hierarchy — queries check overlay first, fall back to organic tree.
- Movement constructor injection: MovementEngine receives terrain/environment modules as constructor parameters. No tight coupling.
- Cubic fuel law: Naval fuel ∝ v³t — standard naval engineering relationship.
- Speed-noise curve: Submarine noise = base + 20·log₁₀(speed/quiet_speed) — standard acoustic relationship.
- A* with heapq: No new dependencies. Grid-based with configurable resolution and threat avoidance.
- Stochastic speed: Gaussian noise on movement speed, controlled by config.noise_std, deterministic from seed.
Deviations from Plan¶
- Test count slightly below plan estimate (~520 planned, ~424 achieved) but all exit criteria met
- Visualization is a standalone script rather than part of the test suite
Lessons Learned¶
- Dataclass inheritance ordering: Python requires all fields without defaults before fields with defaults across the entire MRO chain. Entity's required fields (entity_id, position) must come first.
__post_init__for domain forcing: Domain-specific subclasses use__post_init__to override domain regardless of what was passed, ensuring consistency.- SimpleNamespace for mock objects: Test mocks for terrain/environment modules use
types.SimpleNamespaceto avoid importing heavy Phase 1 modules in unit tests. - Pydantic validation at YAML load: Catches errors early — bad unit definitions fail fast with clear messages.
File Count Summary¶
| Category | Files |
|---|---|
| Source modules (new) | 28 |
| Source modules (expanded) | 2 (core/types.py, entities/base.py) |
| YAML data files | 13 |
| Test files | 14 (new) + 1 (expanded) |
| Visualization | 1 |
| Total | 59 |