summaryrefslogtreecommitdiff
path: root/src/bin/day11.rs
blob: ca5f481e28a1a6cd6f229e036d6a539ca572936b (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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
static DAY: u8 = 11;

fn main() {
    let input = advent::read_lines(DAY);
    println!("{DAY}a: {}", sum_path_lengths(&input));
    println!("{DAY}b: {}", 0);
}

#[derive(PartialEq, Eq)]
struct Position {
    x: isize,
    y: isize,
}

struct GalaxyMap {
    galaxies: Vec<Position>,
    width: isize,
    height: isize,
}

impl GalaxyMap {
    fn new(input: &[String]) -> GalaxyMap {
        let mut galaxies = Vec::new();
        for (y, line) in input.iter().enumerate() {
            for (x, c) in line.chars().enumerate() {
                let pos = Position { x: x as isize, y: y as isize };
                if c == '#' {
                    galaxies.push(pos);
                }
            }
        }
        let width = input[0].len() as isize;
        let height = input.len() as isize;
        GalaxyMap { galaxies, width, height }
    }

    fn expand_space(&mut self) {
        let mut columns = Vec::new();
        for x in 0 .. self.width {
            if !self.galaxies.iter().any(|pos| pos.x == x) {
                columns.push(x);
            }
        }
        let mut rows = Vec::new();
        for y in 0 .. self.height {
            if !self.galaxies.iter().any(|pos| pos.y == y) {
                rows.push(y);
            }
        }
        for x in columns.iter().rev() {
            for galaxy in self.galaxies.iter_mut().filter(|pos| pos.x > *x) {
                galaxy.x += 1;
            }
            self.width += 1;
        }
        for y in rows.iter().rev() {
            for galaxy in self.galaxies.iter_mut().filter(|pos| pos.y > *y) {
                galaxy.y += 1;
            }
            self.height += 1;
        }
    }

    fn _print_map(&self) {
        for y in 0 .. self.height {
            for x in 0 .. self.width {
                if self.galaxies.iter().any(|pos| *pos == Position { x, y }) {
                    print!("#");
                } else {
                    print!(".");
                }
            }
            println!();
        }
    }

    fn calculate_distances(&self) -> Vec<isize> {
        let mut distances = Vec::new();
        for (i, pos1) in self.galaxies.iter().enumerate() {
            for pos2 in self.galaxies.iter().skip(i+1) {
                let distance = pos1.x.abs_diff(pos2.x) + pos1.y.abs_diff(pos2.y);
                distances.push(distance as isize);
            }
        }
        distances
    }
}

fn sum_path_lengths(input: &[String]) -> isize {
    let mut galaxymap = GalaxyMap::new(input);
    galaxymap.expand_space();
    galaxymap.calculate_distances()
             .iter()
             .sum()
}

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

    #[test]
    fn test() {
        let input = [
            "...#......",
            ".......#..",
            "#.........",
            "..........",
            "......#...",
            ".#........",
            ".........#",
            "..........",
            ".......#..",
            "#...#.....",
        ].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
        assert_eq!(sum_path_lengths(&input), 374);
    }
}