]> aoc.elinar.fr Git - aoc_2023/commitdiff
Day16 - part 1
authoralex <null>
Sun, 17 Dec 2023 00:05:43 +0000 (01:05 +0100)
committeralex <null>
Sun, 17 Dec 2023 00:09:08 +0000 (01:09 +0100)
src/day16.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day16.rs b/src/day16.rs
new file mode 100644 (file)
index 0000000..a126ab2
--- /dev/null
@@ -0,0 +1,242 @@
+use std::io::Read;
+use std::error::Error;
+use std::fs::File;
+
+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)?;
+    println!("{res}");
+
+    let res = run_part2(&input)?;
+    println!("{res}");
+
+    Ok(())
+}
+
+#[derive(Debug, Copy, Clone)]
+enum Direction {
+    ToTheLeft,
+    ToTheRight,
+    ToTheTop,
+    ToTheBottom,
+}
+
+#[derive(Clone, Debug)]
+struct Seen {
+    top: bool,
+    right: bool,
+    bottom: bool,
+    left: bool,
+}
+
+struct Puzzle {
+    map: Vec<Vec<char>>,
+    height: usize,
+    width: usize,
+    seen: Vec<Vec<Seen>>,
+}
+
+impl Puzzle {
+    pub fn new(input: &str) -> Self {
+        let mut map: Vec<Vec<char>> = Vec::new();
+        let mut width = 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(' ');
+                if i == 0 {
+                    width = c.len();
+                    map.push(vec![' '; width]);
+                }
+                map.push(c);
+            });
+        map.push(vec![' '; width]);
+
+        let height = map.len();
+
+        let seen: Vec<Vec<Seen>> = vec![
+            vec![ Seen { top: false, right: false, bottom: false, left: false }; width]
+            ;
+            height
+        ];
+
+        Self {
+            map,
+            height,
+            width,
+            seen,
+        }
+    }
+
+    pub fn print(&self) {
+        self.map.iter()
+            .for_each(|r| {
+                println!("{:?}", r.iter().collect::<String>());
+            });
+    }
+
+    pub fn get_next_from_left(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+        //println!("gn_from_left: {:?} {}", pos, self.map[pos.0][pos.1 + 1]);
+        match self.map[pos.0][pos.1 + 1] {
+            '.' | '-' => vec![(Direction::ToTheRight, (pos.0, pos.1 + 1))],
+            '\\' => vec![(Direction::ToTheBottom, (pos.0, pos.1 + 1))],
+            '/'  => vec![(Direction::ToTheTop, (pos.0, pos.1 + 1))],
+            '|'  => vec![(Direction::ToTheBottom, (pos.0, pos.1 + 1)), (Direction::ToTheTop, (pos.0, pos.1 + 1))],
+            ' ' => vec![(Direction::ToTheRight, pos)],
+            _ => unreachable!(),
+        }
+    }
+
+    pub fn get_next_from_right(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+        //println!("gn_from_left: {:?} {}", pos, self.map[pos.0][pos.1 - 1]);
+        match self.map[pos.0][pos.1 - 1] {
+            '.' | '-' => vec![(Direction::ToTheLeft, (pos.0, pos.1 - 1))],
+            '\\' => vec![(Direction::ToTheTop, (pos.0, pos.1 - 1))],
+            '/'  => vec![(Direction::ToTheBottom, (pos.0, pos.1 - 1))],
+            '|'  => vec![(Direction::ToTheTop, (pos.0, pos.1 - 1)), (Direction::ToTheBottom, (pos.0, pos.1 - 1))],
+            ' ' => vec![(Direction::ToTheLeft, pos)],
+            _ => unreachable!(),
+        }
+    }
+
+    pub fn get_next_from_top(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+        //println!("gn_from_left: {:?} {}", pos, self.map[pos.0 + 1][pos.1]);
+        match self.map[pos.0 + 1][pos.1] {
+            '.' | '|' => vec![(Direction::ToTheBottom, (pos.0 + 1, pos.1))],
+            '\\' => vec![(Direction::ToTheRight, (pos.0 + 1, pos.1))],
+            '/'  => vec![(Direction::ToTheLeft, (pos.0 + 1, pos.1))],
+            '-'  => vec![(Direction::ToTheLeft, (pos.0 + 1, pos.1)), (Direction::ToTheRight, (pos.0 + 1, pos.1))],
+            ' ' => vec![(Direction::ToTheBottom, pos)],
+            _ => unreachable!(),
+        }
+    }
+
+    pub fn get_next_from_bottom(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+        //println!("gn_from_left: {:?} {}", pos, self.map[pos.0 - 1][pos.1]);
+        match self.map[pos.0 - 1][pos.1] {
+            '.' | '|' => vec![(Direction::ToTheTop, (pos.0 - 1, pos.1))],
+            '\\' => vec![(Direction::ToTheLeft, (pos.0 - 1, pos.1))],
+            '/'  => vec![(Direction::ToTheRight, (pos.0 - 1, pos.1))],
+            '-'  => vec![(Direction::ToTheLeft, (pos.0 - 1, pos.1)), (Direction::ToTheRight, (pos.0 - 1, pos.1))],
+            ' ' => vec![(Direction::ToTheTop, pos)],
+            _ => unreachable!(),
+        }
+    }
+
+    pub fn update_seen(&mut self, pos: (usize, usize), direction: Direction) {
+        match direction {
+            Direction::ToTheTop => self.seen[pos.0][pos.1].top = true,
+            Direction::ToTheRight => self.seen[pos.0][pos.1].right = true,
+            Direction::ToTheBottom => self.seen[pos.0][pos.1].bottom = true,
+            Direction::ToTheLeft => self.seen[pos.0][pos.1].left = true,
+        }
+    }
+
+    pub fn get_seen(& self, pos: (usize, usize), direction: Direction) -> bool {
+        match direction {
+            Direction::ToTheTop => self.seen[pos.0][pos.1].top,
+            Direction::ToTheRight => self.seen[pos.0][pos.1].right,
+            Direction::ToTheBottom => self.seen[pos.0][pos.1].bottom,
+            Direction::ToTheLeft => self.seen[pos.0][pos.1].left,
+        }
+    }
+
+    pub fn move_beam(&mut self, start: (usize, usize), start_direction: Direction) {
+        let mut pos: (usize, usize) = start;
+        let mut direction: Direction = start_direction;
+        //println!("start: {:?} {:?}", direction, pos);
+        loop {
+            if self.map[pos.0][pos.1] == ' ' {
+                break;
+            }
+            self.update_seen(pos, direction);
+            let new_pos: Vec<(Direction, (usize, usize))> = match direction {
+                Direction::ToTheRight => self.get_next_from_left(pos),
+                Direction::ToTheLeft => self.get_next_from_right(pos),
+                Direction::ToTheBottom => self.get_next_from_top(pos),
+                Direction::ToTheTop => self.get_next_from_bottom(pos),
+            };
+            (direction, pos) = new_pos[0];
+            //println!("next: {:?} {:?}", direction, pos);
+            if self.get_seen(pos, direction) {
+                break;
+            }
+            (1..new_pos.len()).for_each(|i| {
+                let (d, p) = new_pos[i];
+                if !self.get_seen(p, d) {
+                    self.move_beam(p, d);
+                }
+            });
+        }
+    }
+
+    pub fn energized_tiles(&self) -> u64 {
+        let res: u64 = self.seen.iter()
+            .flatten()
+            .map(|b| {
+                if b.top || b.right || b.bottom || b.left {
+                    1
+                } else {
+                    0
+                }
+            })
+            .sum();
+
+        res
+    }
+}
+
+fn run_part1(input: &str) -> Result<u64, Box<dyn Error>> {
+    println!("Running day16 - part 1");
+
+    let mut puzzle = Puzzle::new(input);
+    //puzzle.print();
+
+    // le rayon vient de la gauche (va vers la droite)
+    let (direction, pos) = puzzle.get_next_from_left((1,0))[0];
+    puzzle.move_beam(pos, direction);
+
+    let res = puzzle.energized_tiles();
+    Ok(res)
+}
+
+fn run_part2(input: &str) -> Result<u64, Box<dyn Error>> {
+    println!("Running day16 - part 2");
+    let res = 0;
+    Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    static TEXT_INPUT: &str = r".|...\....
+|.-.\.....
+.....|-...
+........|.
+..........
+.........\
+..../.\\..
+.-.-/..|..
+.|....-|.\
+..//.|....";
+
+    #[test]
+    fn day16_part1() {
+        let res = run_part1(TEXT_INPUT);
+        assert_eq!(46, res.unwrap());
+    }
+
+    #[test]
+    fn day16_part2() {
+        let res = run_part2(TEXT_INPUT);
+        assert_eq!(0, res.unwrap());
+    }
+}
index 76cdbe2db56e35c14f5c047d78a017da9ae93286..5e567b50954f5bc7bb349a80cb42e352e10fc544 100644 (file)
@@ -16,6 +16,7 @@ pub mod day10;
 pub mod day11;
 pub mod day14;
 pub mod day15;
+pub mod day16;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
@@ -47,6 +48,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
         "day11" => day11::run(input_file)?,
         "day14" => day14::run(input_file)?,
         "day15" => day15::run(input_file)?,
+        "day16" => day16::run(input_file)?,
         _ => return Err(format!("unknown day \"{day}\"").into()),
     }
     Ok(())