summaryrefslogtreecommitdiff
path: root/src/bin/day14.rs
blob: 8df62e4b93d8efc15f0941267f451a8ec6ed7a30 (plain)
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
75
76
77
78
79
use std::collections::HashMap;
use regex::Regex;

fn main() {
    let input = advent::read_lines(14);
    println!("14a: {}", winning_distance(&input, 2503));
    println!("14b: {}", winning_points(&input, 2503));
}

struct Reindeer {
    name: String,
    speed: u32,
    duration: u32,
    rest: u32,
}

impl Reindeer {
    fn new(input: &str) -> Reindeer {
        let re = Regex::new(r"^([A-Za-z]+) can fly ([0-9]+) km/s for ([0-9]+) seconds, but then must rest for ([0-9]+) seconds.$").unwrap();
        let cap = re.captures(input).unwrap();
        let name = cap[1].to_string();
        let speed = cap[2].parse::<u32>().unwrap();
        let duration = cap[3].parse::<u32>().unwrap();
        let rest = cap[4].parse::<u32>().unwrap();

        Reindeer { name, speed, duration, rest }
    }

    fn distance(&self, time: u32) -> u32 {
        let cycle_time = self.duration + self.rest;

        let time_flown = (time / cycle_time) * self.duration
                       + std::cmp::min(self.duration, time % cycle_time);

        time_flown * self.speed
    }
}

fn winning_distance(input: &[String], time: u32) -> u32 {
    input.iter()
         .map(|line| Reindeer::new(line))
         .map(|reindeer| reindeer.distance(time))
         .max()
         .unwrap()
}

fn winning_points(input: &[String], time: u32) -> u32 {
    let reindeers = input.iter()
                         .map(|line| Reindeer::new(line))
                         .collect::<Vec<Reindeer>>();
    let mut scores = HashMap::new();

    for t in 1..=time {
        let mut winner = ("", 0);
        for reindeer in &reindeers {
            let distance = reindeer.distance(t);
            if distance >= winner.1 {
                winner = (&reindeer.name, distance);
            }
        }
        *scores.entry(winner.0).or_insert(0) += 1;
    }
    *scores.values().max().unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let input = [
            "Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds.".to_string(),
            "Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds.".to_string(),
        ];
        assert_eq!(winning_distance(&input, 1000), 1120);
        assert_eq!(winning_points(&input, 1000), 689);
    }
}