9f3296b027f55b4f23b12045009f29b706d5cafc
[advent_of_code_2024.git] / src / day14.rs
1 use std::io::BufRead;
2
3 use nalgebra::{DMatrix, Point2, Vector2};
4 use regex::Regex;
5
6 type Position = Point2<i64>;
7 type Velocity = Vector2<i64>;
8
9 pub fn read(reader: &mut dyn BufRead) -> Vec<(Position, Velocity)> {
10 let regex_line = Regex::new(r#"([+-]?\d+),([+-]?\d+).*?([+-]?\d+),([+-]?\d+)"#).unwrap();
11
12 reader
13 .lines()
14 .map(|l| {
15 let l = l.unwrap();
16 let captures = regex_line.captures(&l).unwrap();
17 (
18 Position::new(
19 captures[1].parse::<i64>().unwrap(),
20 captures[2].parse::<i64>().unwrap(),
21 ),
22 Velocity::new(
23 captures[3].parse::<i64>().unwrap(),
24 captures[4].parse::<i64>().unwrap(),
25 ),
26 )
27 })
28 .collect()
29 }
30
31 fn robot_positions<'a>(
32 robots: &'a [(Position, Velocity)],
33 area_size: (i64, i64),
34 seconds: i64,
35 ) -> impl Iterator<Item = (i64, i64)> + use<'a> {
36 robots.into_iter().map(move |(pos, vel)| {
37 let pos = pos + vel * seconds;
38 (
39 pos[0].rem_euclid(area_size.0),
40 pos[1].rem_euclid(area_size.1),
41 )
42 })
43 }
44
45 pub fn safety_factor(robots: &[(Position, Velocity)], area_size: (i64, i64), seconds: i64) -> u32 {
46 let quadrants = robot_positions(robots, area_size, seconds).fold(
47 (0, 0, 0, 0),
48 |(q1, q2, q3, q4), (x, y)| {
49 if x > area_size.0 / 2 {
50 if y < area_size.1 / 2 {
51 return (q1 + 1, q2, q3, q4);
52 } else if y > area_size.1 / 2 {
53 return (q1, q2, q3, q4 + 1);
54 }
55 } else if x < area_size.0 / 2 {
56 if y < area_size.1 / 2 {
57 return (q1, q2 + 1, q3, q4);
58 } else if y > area_size.1 / 2 {
59 return (q1, q2, q3 + 1, q4);
60 }
61 }
62 (q1, q2, q3, q4)
63 },
64 );
65 quadrants.0 * quadrants.1 * quadrants.2 * quadrants.3
66 }
67
68 pub fn format_robots(
69 robots: &[(Position, Velocity)],
70 area_size: (i64, i64),
71 seconds: i64,
72 ) -> String {
73 let mut area = DMatrix::<u32>::repeat(area_size.1 as usize, area_size.0 as usize, 0);
74 for (x, y) in robot_positions(robots, area_size, seconds) {
75 area[(y as usize, x as usize)] += 1;
76 }
77 let mut str = String::new();
78 for i in 0..area.nrows() {
79 for j in 0..area.ncols() {
80 let n = area[(i, j)];
81 if n > 0 {
82 str.push('#');
83 } else {
84 str.push(' ');
85 }
86 }
87 str.push('\n');
88 }
89 str
90 }
91
92 #[cfg(test)]
93 mod test {
94 use super::*;
95
96 static POSITIONS_AND_VELOCITIES: &str = "p=0,4 v=3,-3
97 p=6,3 v=-1,-3
98 p=10,3 v=-1,2
99 p=2,0 v=2,-1
100 p=0,0 v=1,3
101 p=3,0 v=-2,-2
102 p=7,6 v=-1,-3
103 p=3,0 v=-1,-2
104 p=9,3 v=2,3
105 p=7,3 v=-1,2
106 p=2,4 v=2,-3
107 p=9,5 v=-3,-3";
108
109 #[test]
110 fn part1() {
111 let robots = read(&mut POSITIONS_AND_VELOCITIES.as_bytes());
112 assert_eq!(safety_factor(&robots, (11, 7), 100), 12);
113 }
114 }