1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
use pdqsort::sort_by_key; use super::ComparisonGenerator; use {Attempt, Segment, TimeSpan, TimingMethod}; #[derive(Copy, Clone, Debug)] pub struct AverageSegments; pub const NAME: &'static str = "Average Segments"; const WEIGHT: f64 = 0.75; fn calculate_weight(index: usize, count: usize) -> f64 { WEIGHT.powi((count - index - 1) as i32) } fn calculate_average(times: &[(i32, TimeSpan)]) -> TimeSpan { let (mut total_weights, mut total_time) = (0.0, 0.0); for (i, &(_, time)) in times.iter().enumerate() { let weight = calculate_weight(i, times.len()); total_weights += weight; total_time += weight * time.total_seconds(); } TimeSpan::from_seconds(total_time / total_weights) } fn generate(buf: &mut Vec<(i32, TimeSpan)>, segments: &mut [Segment], method: TimingMethod) { let mut total_time = Some(TimeSpan::zero()); for i in 0..segments.len() { if total_time.is_some() { buf.clear(); for (&id, time) in segments[i].segment_history() { if let Some(time) = time[method] { let keep = id > 0 && i.checked_sub(1) .and_then(|i| { segments[i].segment_history().get(id).map(|t| t[method].is_some()) }) .unwrap_or(true); if keep { buf.push((id, time)); } } } sort_by_key(buf, |&(id, _)| id); if buf.is_empty() { total_time = None; } if let Some(ref mut total_time) = total_time { *total_time = *total_time + calculate_average(&buf); } } segments[i].comparison_mut(NAME)[method] = total_time; } } impl ComparisonGenerator for AverageSegments { fn name(&self) -> &str { NAME } fn generate(&mut self, segments: &mut [Segment], _: &[Attempt]) { let mut times = Vec::new(); generate(&mut times, segments, TimingMethod::RealTime); generate(&mut times, segments, TimingMethod::GameTime); } }