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);
    }
}