use crate::koi::{KoiDevelopment, RecentStreak};
const STREAK_FIN_FULL_WEEKS: f64 = 13.0;
const FADE_RATE_PER_WEEK: f64 = 0.5;
const FADE_WEEKS: f64 = 6.5;
const RECORD_CURVE_WEEKS: f64 = 0.6;
const NORMAL_COLOR_WEEKS: f64 = 4.0;
const VIVID_COLOR_WEEKS: f64 = 52.0;
const FULL_GLIMMER_WEEKS: f64 = 208.0;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct StreakMarks {
pub streak_fin_strength: f64,
pub color_vibrancy: f64,
pub glimmer_strength: f64,
}
pub fn calculate_streak_marks(koi_development: &KoiDevelopment) -> StreakMarks {
let streak_fin_strength = match &koi_development.streaks.recent {
None => 0.0,
Some(RecentStreak::Current(streak_weeks)) => calculate_fin_build(streak_weeks.len()),
Some(RecentStreak::Ended {
weeks: streak_weeks,
ended_on,
}) => {
let weeks_since_end =
(koi_development.observed_on - *ended_on).num_days().max(0) as f64 / 7.0;
calculate_fin_build(streak_weeks.len()) * calculate_fade(weeks_since_end)
}
};
let record_strength = calculate_record_strength(koi_development.streaks.longest.len() as f64);
let normal_strength = calculate_record_strength(NORMAL_COLOR_WEEKS);
let vivid_strength = calculate_record_strength(VIVID_COLOR_WEEKS);
let color_vibrancy = if record_strength < normal_strength {
record_strength / normal_strength
} else {
1.0 + ((record_strength - normal_strength) / (vivid_strength - normal_strength)).min(1.0)
};
StreakMarks {
streak_fin_strength,
color_vibrancy,
glimmer_strength: ((record_strength - vivid_strength) / (1.0 - vivid_strength))
.clamp(0.0, 1.0),
}
}
fn calculate_fin_build(streak_week_count: usize) -> f64 {
(streak_week_count as f64 / STREAK_FIN_FULL_WEEKS).min(1.0)
}
fn calculate_fade(weeks_since_end: f64) -> f64 {
let fade_floor = (-FADE_RATE_PER_WEEK * FADE_WEEKS).exp();
(((-FADE_RATE_PER_WEEK * weeks_since_end).exp() - fade_floor) / (1.0 - fade_floor)).max(0.0)
}
fn calculate_record_strength(longest_weeks: f64) -> f64 {
((1.0 + longest_weeks / RECORD_CURVE_WEEKS).ln()
/ (1.0 + FULL_GLIMMER_WEEKS / RECORD_CURVE_WEEKS).ln())
.min(1.0)
}