-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday14.rs
121 lines (109 loc) · 3.09 KB
/
day14.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
use aoc_runner_derive::aoc;
#[aoc(day14, part1)]
#[must_use]
pub fn part1(input: &str) -> i32 {
let mut problem = Environment::parse(input);
problem
.robots
.iter_mut()
.for_each(|x| x.step(problem.limits, 100));
problem.safety_factor()
}
#[aoc(day14, part2)]
#[must_use]
pub fn part2(input: &str) -> usize {
let mut problem = Environment::parse(input);
for i in 0.. {
problem
.robots
.iter_mut()
.for_each(|x| x.step(problem.limits, 1));
if problem
.robots
.iter()
.map(|x| (x.pos - problem.limits / 2).abs().sum())
.sum::<i32>()
< 2_i32.pow(14)
{
return i + 1;
}
}
unreachable!()
}
struct Environment {
robots: smallvec::SmallVec<[Robot; 512]>,
limits: nalgebra::Vector2<i32>,
}
impl Environment {
fn parse(input: &str) -> Self {
let robots: smallvec::SmallVec<[Robot; 512]> = input.lines().map(Robot::parse).collect();
let limits = robots
.iter()
.fold(nalgebra::Vector2::new(0, 0), |mut limits, robot| {
limits.x = limits.x.max(robot.pos.x);
limits.y = limits.y.max(robot.pos.y);
limits
})
+ nalgebra::Vector2::new(1, 1);
Self { robots, limits }
}
fn safety_factor(&self) -> i32 {
let mut quad = [0; 4];
for pos in self.robots.iter().map(|robot| robot.pos) {
if pos.x == (self.limits / 2).x || pos.y == (self.limits / 2).y {
continue;
}
quad[(2 * usize::from((0..=(self.limits / 2).x).contains(&pos.x)))
| usize::from((0..=(self.limits / 2).y).contains(&pos.y))] += 1;
}
quad.iter().product()
}
}
struct Robot {
pos: nalgebra::Vector2<i32>,
vel: nalgebra::Vector2<i32>,
}
impl Robot {
fn parse(input: &str) -> Self {
fn parse_coordinates(input: &str) -> nalgebra::Vector2<i32> {
let (x, y) = input.split_once(',').unwrap();
nalgebra::Vector2::new(x.parse().unwrap(), y.parse().unwrap())
}
let (pos, vel) = input.split_once(' ').unwrap();
let pos = parse_coordinates(&pos[2..]);
let vel = parse_coordinates(&vel[2..]);
Self { pos, vel }
}
fn step(&mut self, bounds: nalgebra::Vector2<i32>, dt: i32) {
self.pos += dt * self.vel;
self.pos.x = (self.pos.x % bounds.x + bounds.x) % bounds.x;
self.pos.y = (self.pos.y % bounds.y + bounds.y) % bounds.y;
}
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
const SAMPLE: &str = indoc! {"
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
"};
#[test]
pub fn part1_example() {
assert_eq!(part1(SAMPLE), 12);
}
#[test]
pub fn part2_example() {
assert_eq!(part2(SAMPLE), 1);
}
}