Day 14
authorGreg Burri <greg.burri@gmail.com>
Sat, 14 Dec 2024 21:26:35 +0000 (22:26 +0100)
committerGreg Burri <greg.burri@gmail.com>
Sat, 14 Dec 2024 21:26:35 +0000 (22:26 +0100)
src/day13.rs
src/day14.rs [new file with mode: 0644]
src/days.rs
src/main.rs

index 7de4a3f..e84087d 100644 (file)
@@ -16,20 +16,20 @@ pub fn read(reader: &mut dyn BufRead) -> Equations {
         if let Some(Ok(line1)) = iter.next() {
             let a_cap = button_a.captures(&line1).unwrap();
             let a_factors = Vector2::new(
-                a_cap.get(1).unwrap().as_str().parse::<i64>().unwrap(),
-                a_cap.get(2).unwrap().as_str().parse::<i64>().unwrap(),
+                a_cap[1].parse::<i64>().unwrap(),
+                a_cap[2].parse::<i64>().unwrap(),
             );
             let line2 = iter.next().unwrap().unwrap();
             let b_cap = button_b.captures(&line2).unwrap();
             let b_factors = Vector2::new(
-                b_cap.get(1).unwrap().as_str().parse::<i64>().unwrap(),
-                b_cap.get(2).unwrap().as_str().parse::<i64>().unwrap(),
+                b_cap[1].parse::<i64>().unwrap(),
+                b_cap[2].parse::<i64>().unwrap(),
             );
             let line3 = iter.next().unwrap().unwrap();
             let prize_cap = prize.captures(&line3).unwrap();
             let prize_xy = Vector2::new(
-                prize_cap.get(1).unwrap().as_str().parse::<i64>().unwrap(),
-                prize_cap.get(2).unwrap().as_str().parse::<i64>().unwrap(),
+                prize_cap[1].parse::<i64>().unwrap(),
+                prize_cap[2].parse::<i64>().unwrap(),
             );
             let _ = iter.next();
             equations.push((a_factors, b_factors, prize_xy));
diff --git a/src/day14.rs b/src/day14.rs
new file mode 100644 (file)
index 0000000..5d422ba
--- /dev/null
@@ -0,0 +1,114 @@
+use std::io::BufRead;
+
+use nalgebra::{DMatrix, Point2, Vector2};
+use regex::Regex;
+
+type Position = Point2<i64>;
+type Velocity = Vector2<i64>;
+
+pub fn read(reader: &mut dyn BufRead) -> Vec<(Position, Velocity)> {
+    let regex_line = { Regex::new(r#"([+-]?\d+),([+-]?\d+).*?([+-]?\d+),([+-]?\d+)"#).unwrap() };
+
+    reader
+        .lines()
+        .map(|l| {
+            let l = l.unwrap();
+            let captures = regex_line.captures(&l).unwrap();
+            (
+                Position::new(
+                    captures[1].parse::<i64>().unwrap(),
+                    captures[2].parse::<i64>().unwrap(),
+                ),
+                Velocity::new(
+                    captures[3].parse::<i64>().unwrap(),
+                    captures[4].parse::<i64>().unwrap(),
+                ),
+            )
+        })
+        .collect()
+}
+
+fn robot_positions<'a>(
+    robots: &'a [(Position, Velocity)],
+    area_size: (i64, i64),
+    seconds: i64,
+) -> impl Iterator<Item = (i64, i64)> + use<'a> {
+    robots.into_iter().map(move |(pos, vel)| {
+        let pos = pos + vel * seconds;
+        (
+            pos[0].rem_euclid(area_size.0),
+            pos[1].rem_euclid(area_size.1),
+        )
+    })
+}
+
+pub fn safety_factor(robots: &[(Position, Velocity)], area_size: (i64, i64), seconds: i64) -> u32 {
+    let quadrants = robot_positions(robots, area_size, seconds).fold(
+        (0, 0, 0, 0),
+        |(q1, q2, q3, q4), (x, y)| {
+            if x > area_size.0 / 2 {
+                if y < area_size.1 / 2 {
+                    return (q1 + 1, q2, q3, q4);
+                } else if y > area_size.1 / 2 {
+                    return (q1, q2, q3, q4 + 1);
+                }
+            } else if x < area_size.0 / 2 {
+                if y < area_size.1 / 2 {
+                    return (q1, q2 + 1, q3, q4);
+                } else if y > area_size.1 / 2 {
+                    return (q1, q2, q3 + 1, q4);
+                }
+            }
+            (q1, q2, q3, q4)
+        },
+    );
+    quadrants.0 * quadrants.1 * quadrants.2 * quadrants.3
+}
+
+pub fn format_robots(
+    robots: &[(Position, Velocity)],
+    area_size: (i64, i64),
+    seconds: i64,
+) -> String {
+    let mut area = DMatrix::<u32>::repeat(area_size.1 as usize, area_size.0 as usize, 0);
+    for (x, y) in robot_positions(robots, area_size, seconds) {
+        area[(y as usize, x as usize)] += 1;
+    }
+    let mut str = String::new();
+    for i in 0..area.nrows() {
+        for j in 0..area.ncols() {
+            let n = area[(i, j)];
+            if n > 0 {
+                str.push('#');
+            } else {
+                str.push(' ');
+            }
+        }
+        str.push('\n');
+    }
+    str
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    static POSITIONS_AND_VELOCITIES: &str = "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]
+    fn part1() {
+        let robots = read(&mut POSITIONS_AND_VELOCITIES.as_bytes());
+        assert_eq!(safety_factor(&robots, (11, 7), 100), 12);
+    }
+}
index 0ff4d85..2932a11 100644 (file)
@@ -123,3 +123,14 @@ pub fn day13(reader: &mut dyn BufRead) -> String {
         day13::nb_tokens(&day13::add_10000000000000_to_xy(equations))
     )
 }
+
+pub fn day14(reader: &mut dyn BufRead) -> String {
+    let robots = day14::read(reader);
+    format!(
+        "part1: {}, part2: {}",
+        day14::safety_factor(&robots, (101, 103), 100),
+        // Found by displaying each robot positions where seconds = i * 100 + 46 + i
+        // and i in 0..100.
+        day14::format_robots(&robots, (101, 103), 7520)
+    )
+}
index 1b92c94..e7d4c43 100644 (file)
@@ -15,7 +15,7 @@ mod day10;
 mod day11;
 mod day12;
 mod day13;
-// mod day14;
+mod day14;
 // mod day15;
 // mod day16;
 // mod day17;
@@ -46,7 +46,7 @@ fn main() {
         days::day11,
         days::day12,
         days::day13,
-        // days::day14,
+        days::day14,
         // days::day15,
         // days::day16,
         // days::day17,