1use crate::koi::{KoiDevelopment, RecentStreak};
4
5const STREAK_FIN_FULL_WEEKS: f64 = 13.0;
6const FADE_RATE_PER_WEEK: f64 = 0.5;
7const FADE_WEEKS: f64 = 6.5;
8const RECORD_CURVE_WEEKS: f64 = 0.6;
10const NORMAL_COLOR_WEEKS: f64 = 4.0;
11const VIVID_COLOR_WEEKS: f64 = 52.0;
12const FULL_GLIMMER_WEEKS: f64 = 208.0;
14
15#[derive(Clone, Copy, Debug, PartialEq)]
17pub struct StreakMarks {
18 pub streak_fin_strength: f64,
20 pub color_vibrancy: f64,
22 pub glimmer_strength: f64,
24}
25
26pub fn calculate_streak_marks(koi_development: &KoiDevelopment) -> StreakMarks {
37 let streak_fin_strength = match &koi_development.streaks.recent {
38 None => 0.0,
39 Some(RecentStreak::Current(streak_weeks)) => calculate_fin_build(streak_weeks.len()),
40 Some(RecentStreak::Ended {
41 weeks: streak_weeks,
42 ended_on,
43 }) => {
44 let weeks_since_end =
45 (koi_development.observed_on - *ended_on).num_days().max(0) as f64 / 7.0;
46 calculate_fin_build(streak_weeks.len()) * calculate_fade(weeks_since_end)
47 }
48 };
49 let record_strength = calculate_record_strength(koi_development.streaks.longest.len() as f64);
50 let normal_strength = calculate_record_strength(NORMAL_COLOR_WEEKS);
51 let vivid_strength = calculate_record_strength(VIVID_COLOR_WEEKS);
52 let color_vibrancy = if record_strength < normal_strength {
53 record_strength / normal_strength
54 } else {
55 1.0 + ((record_strength - normal_strength) / (vivid_strength - normal_strength)).min(1.0)
56 };
57 StreakMarks {
58 streak_fin_strength,
59 color_vibrancy,
60 glimmer_strength: ((record_strength - vivid_strength) / (1.0 - vivid_strength))
61 .clamp(0.0, 1.0),
62 }
63}
64
65fn calculate_fin_build(streak_week_count: usize) -> f64 {
66 (streak_week_count as f64 / STREAK_FIN_FULL_WEEKS).min(1.0)
67}
68
69fn calculate_fade(weeks_since_end: f64) -> f64 {
72 let fade_floor = (-FADE_RATE_PER_WEEK * FADE_WEEKS).exp();
73 (((-FADE_RATE_PER_WEEK * weeks_since_end).exp() - fade_floor) / (1.0 - fade_floor)).max(0.0)
74}
75
76fn calculate_record_strength(longest_weeks: f64) -> f64 {
77 ((1.0 + longest_weeks / RECORD_CURVE_WEEKS).ln()
78 / (1.0 + FULL_GLIMMER_WEEKS / RECORD_CURVE_WEEKS).ln())
79 .min(1.0)
80}