generated from fspoettel/advent-of-code-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
11.rs
124 lines (94 loc) · 2.98 KB
/
11.rs
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
118
119
120
121
122
123
124
use std::collections::HashSet;
advent_of_code::solution!(11);
pub fn part_one(input: &str) -> Option<usize> {
let grid = GalaxyGrid::from_input(input);
Some(grid.sum_of_galaxy_distances(2))
}
pub fn part_two(input: &str) -> Option<usize> {
let grid = GalaxyGrid::from_input(input);
Some(grid.sum_of_galaxy_distances(1_000_000))
}
struct GalaxyGrid<'a> {
grid: Vec<&'a str>,
}
impl GalaxyGrid<'_> {
fn from_input(input: &str) -> GalaxyGrid {
GalaxyGrid {
grid: input.lines().collect(),
}
}
fn sum_of_galaxy_distances(&self, expansion_factor: usize) -> usize {
let mut processed_galaxies = Vec::new();
let mut distances_sum = 0;
for galaxy in self.galaxies(expansion_factor) {
for processed_galaxy in processed_galaxies.iter() {
distances_sum += galaxy.distance(processed_galaxy);
}
processed_galaxies.push(galaxy);
}
distances_sum
}
fn galaxies(&self, expansion_factor: usize) -> Vec<Galaxy> {
let mut galaxies = Vec::new();
let xs_without_galaxies: HashSet<_> = self.xs_without_galaxies().collect();
let mut current_y = 0;
for line in self.grid.iter() {
let mut current_x = 0;
let mut y_has_galaxies = false;
for (x_index, character) in line.as_bytes().iter().enumerate() {
if xs_without_galaxies.contains(&x_index) {
current_x += expansion_factor;
continue;
}
if *character == b'#' {
galaxies.push(Galaxy::new(current_x, current_y));
y_has_galaxies = true;
}
current_x += 1;
}
current_y += if y_has_galaxies { 1 } else { expansion_factor };
}
galaxies
}
fn xs_without_galaxies(&self) -> impl Iterator<Item = usize> + '_ {
// Assuming every line has the same length
let x_count = self.grid[0].len();
(0..x_count).filter(|&y| self.grid.iter().all(|line| line.as_bytes()[y] == b'.'))
}
}
struct Galaxy {
x: usize,
y: usize,
}
impl Galaxy {
fn new(x: usize, y: usize) -> Galaxy {
Galaxy { x, y }
}
fn distance(&self, other: &Galaxy) -> usize {
let distance_x = if self.x < other.x {
other.x - self.x
} else {
self.x - other.x
};
let distance_y = if self.y < other.y {
other.y - self.y
} else {
self.y - other.y
};
distance_x + distance_y
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(374));
}
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(82000210));
}
}