#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DevelopmentalPhase {
Genesis,
Exposure,
Differentiation,
Crystallization,
}
impl DevelopmentalPhase {
pub fn name(self) -> &'static str {
match self {
Self::Genesis => "genesis",
Self::Exposure => "exposure",
Self::Differentiation => "differentiation",
Self::Crystallization => "crystallization",
}
}
}
#[derive(Clone, Debug)]
pub struct PhaseConfig {
pub genesis_frames: u64,
pub exposure_frames: u64,
pub differentiation_frames: u64,
pub crystallization_frames: u64,
}
impl Default for PhaseConfig {
fn default() -> Self {
Self {
genesis_frames: 500,
exposure_frames: 2000,
differentiation_frames: 1000,
crystallization_frames: 1000,
}
}
}
impl PhaseConfig {
pub fn total_frames(&self) -> u64 {
self.genesis_frames
+ self.exposure_frames
+ self.differentiation_frames
+ self.crystallization_frames
}
}
#[derive(Clone, Debug)]
pub struct PhaseController {
pub current_phase: DevelopmentalPhase,
pub phase_frame: u64,
pub total_frame: u64,
config: PhaseConfig,
}
impl PhaseController {
pub fn new(config: PhaseConfig) -> Self {
Self {
current_phase: DevelopmentalPhase::Genesis,
phase_frame: 0,
total_frame: 0,
config,
}
}
pub fn advance(&mut self) -> bool {
self.phase_frame += 1;
self.total_frame += 1;
let limit = match self.current_phase {
DevelopmentalPhase::Genesis => self.config.genesis_frames,
DevelopmentalPhase::Exposure => self.config.exposure_frames,
DevelopmentalPhase::Differentiation => self.config.differentiation_frames,
DevelopmentalPhase::Crystallization => self.config.crystallization_frames,
};
if self.phase_frame >= limit {
let next = match self.current_phase {
DevelopmentalPhase::Genesis => Some(DevelopmentalPhase::Exposure),
DevelopmentalPhase::Exposure => Some(DevelopmentalPhase::Differentiation),
DevelopmentalPhase::Differentiation => Some(DevelopmentalPhase::Crystallization),
DevelopmentalPhase::Crystallization => None, };
if let Some(next_phase) = next {
self.current_phase = next_phase;
self.phase_frame = 0;
return true;
}
}
false
}
pub fn is_mature(&self) -> bool {
self.current_phase == DevelopmentalPhase::Crystallization
&& self.phase_frame >= self.config.crystallization_frames
}
pub fn phase_progress(&self) -> f32 {
let limit = match self.current_phase {
DevelopmentalPhase::Genesis => self.config.genesis_frames,
DevelopmentalPhase::Exposure => self.config.exposure_frames,
DevelopmentalPhase::Differentiation => self.config.differentiation_frames,
DevelopmentalPhase::Crystallization => self.config.crystallization_frames,
};
if limit == 0 { return 1.0; }
(self.phase_frame as f32 / limit as f32).min(1.0)
}
pub fn overall_progress(&self) -> f32 {
let total = self.config.total_frames();
if total == 0 { return 1.0; }
(self.total_frame as f32 / total as f32).min(1.0)
}
pub fn migration_rate(&self) -> f32 {
match self.current_phase {
DevelopmentalPhase::Genesis => 2.0, DevelopmentalPhase::Exposure => 1.0, DevelopmentalPhase::Differentiation => 0.5, DevelopmentalPhase::Crystallization => 0.1, }
}
pub fn plasticity_rate(&self) -> f32 {
match self.current_phase {
DevelopmentalPhase::Genesis => 1.5, DevelopmentalPhase::Exposure => 1.0, DevelopmentalPhase::Differentiation => 1.2, DevelopmentalPhase::Crystallization => 0.2, }
}
pub fn wiring_radius(&self) -> f32 {
match self.current_phase {
DevelopmentalPhase::Genesis => 2.0, DevelopmentalPhase::Exposure => 1.0, DevelopmentalPhase::Differentiation => 1.5, DevelopmentalPhase::Crystallization => 0.5, }
}
pub fn discs_accumulate(&self) -> bool {
matches!(
self.current_phase,
DevelopmentalPhase::Exposure | DevelopmentalPhase::Differentiation
)
}
pub fn discs_differentiate(&self) -> bool {
self.current_phase == DevelopmentalPhase::Differentiation
}
pub fn mastery_active(&self) -> bool {
!matches!(self.current_phase, DevelopmentalPhase::Genesis)
}
pub fn config(&self) -> &PhaseConfig {
&self.config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn phase_progression() {
let config = PhaseConfig {
genesis_frames: 10,
exposure_frames: 10,
differentiation_frames: 10,
crystallization_frames: 10,
};
let mut ctrl = PhaseController::new(config);
assert_eq!(ctrl.current_phase, DevelopmentalPhase::Genesis);
for _ in 0..9 {
assert!(!ctrl.advance());
}
assert!(ctrl.advance()); assert_eq!(ctrl.current_phase, DevelopmentalPhase::Exposure);
for _ in 0..9 { ctrl.advance(); }
assert!(ctrl.advance());
assert_eq!(ctrl.current_phase, DevelopmentalPhase::Differentiation);
for _ in 0..9 { ctrl.advance(); }
assert!(ctrl.advance());
assert_eq!(ctrl.current_phase, DevelopmentalPhase::Crystallization);
for _ in 0..9 { ctrl.advance(); }
assert!(!ctrl.advance()); assert!(ctrl.is_mature());
}
#[test]
fn phase_progress_tracking() {
let config = PhaseConfig {
genesis_frames: 100,
exposure_frames: 100,
differentiation_frames: 100,
crystallization_frames: 100,
};
let mut ctrl = PhaseController::new(config);
for _ in 0..50 {
ctrl.advance();
}
assert!((ctrl.phase_progress() - 0.5).abs() < 0.02);
assert!((ctrl.overall_progress() - 0.125).abs() < 0.02);
}
#[test]
fn phase_multipliers() {
let ctrl = PhaseController::new(PhaseConfig::default());
assert!(ctrl.migration_rate() > 1.0);
assert!(ctrl.wiring_radius() > 1.0);
assert!(!ctrl.mastery_active());
assert!(!ctrl.discs_accumulate());
}
}