From: alex Date: Sun, 17 Dec 2023 00:05:43 +0000 (+0100) Subject: Day16 - part 1 X-Git-Url: https://aoc.elinar.fr/?a=commitdiff_plain;h=79bebee34822b18418cdaaf058fef8dcdf10a690;p=aoc_2023 Day16 - part 1 --- diff --git a/src/day16.rs b/src/day16.rs new file mode 100644 index 0000000..a126ab2 --- /dev/null +++ b/src/day16.rs @@ -0,0 +1,242 @@ +use std::io::Read; +use std::error::Error; +use std::fs::File; + +pub fn run(input_file: &str) -> Result<(), Box> { + 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>, + height: usize, + width: usize, + seen: Vec>, +} + +impl Puzzle { + pub fn new(input: &str) -> Self { + let mut map: Vec> = Vec::new(); + let mut width = 0; + input.lines() + .filter(|l| !l.is_empty()) + .enumerate() + .for_each(|(i,l)| { + let mut c: Vec = Vec::new(); + c.push(' '); + c.append(&mut l.chars().collect::>()); + 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![ + 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::()); + }); + } + + 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> { + 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> { + 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()); + } +} diff --git a/src/main.rs b/src/main.rs index 76cdbe2..5e567b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ pub mod day10; pub mod day11; pub mod day14; pub mod day15; +pub mod day16; fn main() { let args: Vec = env::args().collect(); @@ -47,6 +48,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box> { "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(())