]> aoc.elinar.fr Git - aoc_2023/commitdiff
Day21 - part 1
authoralex <null>
Thu, 21 Dec 2023 21:12:23 +0000 (22:12 +0100)
committeralex <null>
Thu, 21 Dec 2023 21:12:23 +0000 (22:12 +0100)
src/day21.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day21.rs b/src/day21.rs
new file mode 100644 (file)
index 0000000..3806719
--- /dev/null
@@ -0,0 +1,161 @@
+use std::io::Read;
+use std::error::Error;
+use std::fs::File;
+
+use std::collections::VecDeque;
+
+const END_STEP: u32 = 64;
+
+pub fn run(input_file: &str) -> Result<(), Box<dyn Error>> {
+    let mut f = File::open(input_file)?;
+    let mut input = String::new();
+    f.read_to_string(&mut input)?;
+
+    let res = run_part1(&input, END_STEP)?;
+    println!("{res}");
+
+    let res = run_part2(&input)?;
+    println!("{res}");
+
+    Ok(())
+}
+
+#[derive(Debug)]
+struct Puzzle {
+    map: Vec<Vec<char>>,
+    seen_at_step: Vec<Vec<u32>>,
+    start: (usize, usize),
+}
+
+impl Puzzle {
+    pub fn new(input: &str) -> Self {
+        let mut map: Vec<Vec<char>> = Vec::new();
+        let mut start: (usize, usize) = (0, 0);
+
+        input.lines()
+            .filter(|l| !l.is_empty())
+            .enumerate()
+            .for_each(|(i, l)| {
+                let mut c: Vec<char> = Vec::new();
+
+                c.push(' ');
+                c.append(&mut l.chars().collect::<Vec<char>>());
+                c.push(' ');
+
+                match c.iter().position(|&a| a == 'S') {
+                    Some(p) => start = (i + 1, p),
+                    None => {},
+                }
+
+
+                if i == 0 {
+                    map.push(vec![' '; c.len()]);
+                }
+                map.push(c);
+
+            });
+
+        map.push(vec![' '; map[0].len()]);
+
+        let seen_at_step: Vec<Vec<u32>> = vec![
+            vec![0 ; map[0].len()]
+            ;
+            map.len()
+        ];
+
+        Self {
+            map,
+            seen_at_step,
+            start,
+        }
+    }
+
+    // une fois visitées les cases clignotes
+    //   '.' -> 'O' -> '.' -> 'O'
+    pub fn travel(&mut self, end_step: u32) -> u32 {
+        let mut queue: VecDeque<(usize, usize)> = VecDeque::new();
+        queue.push_back(self.start);
+
+        let mut step: u32 = 1;
+
+        while step <= end_step {
+            let mut queue_next: VecDeque<(usize, usize)> = VecDeque::new();
+            while let Some(q) = queue.pop_front() {
+                let neighbours = [
+                    (q.0, q.1 - 1),
+                    (q.0, q.1 + 1),
+                    (q.0 - 1, q.1),
+                    (q.0 + 1, q.1),
+                ];
+                for n in neighbours {
+                    if self.can_travel_to(n) {
+                        self.seen_at_step[n.0][n.1] = step;
+                        queue_next.push_back(n);
+                    }
+                }
+            }
+
+            step += 1;
+            queue = queue_next.clone();
+        }
+
+        self.seen_at_step.iter()
+            .map(|r| {
+                r.iter().filter(|&&s| {
+                    s > 0 && s % 2 == end_step % 2
+                })
+                .count()
+            })
+            .sum::<usize>() as u32
+    }
+
+    fn can_travel_to(&self, n: (usize, usize)) -> bool {
+        self.seen_at_step[n.0][n.1] == 0 && ['.', 'S'].contains(&self.map[n.0][n.1])
+    }
+}
+
+fn run_part1(input: &str, end_step: u32) -> Result<u32, Box<dyn Error>> {
+    println!("Running day21 - part 1");
+
+    let mut puzzle = Puzzle::new(input);
+    //println!("{:?}", puzzle);
+    let res = puzzle.travel(end_step);
+    Ok(res)
+}
+
+fn run_part2(input: &str) -> Result<u32, Box<dyn Error>> {
+    println!("Running day21 - part 2");
+    let res = 0;
+    Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    static TEXT_INPUT: &str = "\
+...........
+.....###.#.
+.###.##..#.
+..#.#...#..
+....#.#....
+.##..S####.
+.##..#...#.
+.......##..
+.##.#.####.
+.##..##.##.
+...........";
+
+    #[test]
+    fn day21_part1() {
+        // N = 6
+        let res = run_part1(TEXT_INPUT, 6);
+        assert_eq!(16, res.unwrap());
+    }
+
+    #[test]
+    fn day21_part2() {
+        let res = run_part2(TEXT_INPUT);
+        assert_eq!(0, res.unwrap());
+    }
+}
index e15fe5bc976359cb381a14a71fdc39ed59ec4421..34d88dfb2a97dab605a2153b91987aa6d8c30a0e 100644 (file)
@@ -20,6 +20,7 @@ pub mod day16;
 pub mod day18;
 pub mod day19;
 pub mod day20;
+pub mod day21;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
@@ -55,6 +56,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
         "day18" => day18::run(input_file)?,
         "day19" => day19::run(input_file)?,
         "day20" => day20::run(input_file)?,
+        "day21" => day21::run(input_file)?,
         _ => return Err(format!("unknown day \"{day}\"").into()),
     }
     Ok(())