summaryrefslogtreecommitdiff
path: root/src/bin/day14.rs
blob: 531e1b4221c42b0c95e129d25e3a4f0343e78e49 (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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use regex::Regex;
use std::collections::HashMap;

static DAY: u8 = 14;

fn main() {
    let input = advent::read_lines(DAY);
    println!("{DAY}a: {}", safety_factor(&input, Position { x: 101, y: 103 }));
    println!("{DAY}b: {}", 0);
}

struct Position {
    x: isize,
    y: isize,
}

struct Robot {
    pos: Position,
    velocity: Position,
}

impl Robot {
    fn new(input: &str) -> Robot {
        let re = Regex::new(r"p=([0-9]+),([0-9]+) v=([-0-9]+),([-0-9]+)").unwrap();
        let caps = re.captures(input).unwrap();
        let x = caps.get(1).unwrap().as_str().parse::<isize>().unwrap();
        let y = caps.get(2).unwrap().as_str().parse::<isize>().unwrap();
        let dx = caps.get(3).unwrap().as_str().parse::<isize>().unwrap();
        let dy = caps.get(4).unwrap().as_str().parse::<isize>().unwrap();

        Robot {
            pos: Position { x, y },
            velocity: Position { x: dx, y: dy },
        }
    }

    fn travel(&mut self, area: &Position) {
        self.pos.x = (self.pos.x + self.velocity.x + area.x) % area.x;
        self.pos.y = (self.pos.y + self.velocity.y + area.y) % area.y;
    }

    fn quadrant(&self, area: &Position) -> u8 {
        if self.pos.x < area.x / 2 && self.pos.y < area.y / 2 {
            1
        } else if self.pos.x < area.x / 2 && self.pos.y > area.y / 2 {
            2
        } else if self.pos.x > area.x / 2 && self.pos.y < area.y / 2 {
            3
        } else if self.pos.x > area.x / 2 && self.pos.y > area.y / 2 {
            4
        } else {
            0
        }
    }
}

fn safety_factor(input: &[String], area: Position) -> u32 {
    let mut robots = input.iter()
                           .map(|line| Robot::new(line))
                           .collect::<Vec<_>>();
    for _ in 0 .. 100 {
        for robot in robots.iter_mut() {
            robot.travel(&area);
        }
    }

    let mut quadrants = HashMap::new();
    for robot in &robots {
        let quadrant = robot.quadrant(&area);
        if quadrant != 0 {
            let entry = quadrants.entry(quadrant).or_insert(0);
            *entry += 1;
        }
    }
    quadrants.values().product()
}

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

    #[test]
    fn test() {
        let input = [
            "p=0,4 v=3,-3",
            "p=6,3 v=-1,-3",
            "p=10,3 v=-1,2",
            "p=2,0 v=2,-1",
            "p=0,0 v=1,3",
            "p=3,0 v=-2,-2",
            "p=7,6 v=-1,-3",
            "p=3,0 v=-1,-2",
            "p=9,3 v=2,3",
            "p=7,3 v=-1,2",
            "p=2,4 v=2,-3",
            "p=9,5 v=-3,-3",
        ].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
        assert_eq!(safety_factor(&input, Position { x: 11, y: 7}), 12);
    }
}