diff --git a/input/day16.txt b/input/day16.txt new file mode 100644 index 0000000..58b1d69 --- /dev/null +++ b/input/day16.txt @@ -0,0 +1,110 @@ +\.......................|..-.............../../.......|...............\.\.....|..../.............|............ +........................../....../..............................-............-.-..--.........-...........\/... +....\............../...........-...-......|.............................\...............-........-....|....... +......\....|................./.\................/..................../.......................|..\......-...... +.................../..................-./.................../.....-...................|......\.......|\...\./. +.....|........../....................\../..\.../.\.......-.............\...........\......|.\..-..........-... +..../............/.....\...................../..--\........|......\....-...|.-...../......-........../........ +..............\.-............./........./....|\.......\..........|.................|.|.................-...... +.....|..........-................-.../..........-........................\.......|.........................-.. +.|.-......./....................\........-.............../..\.|.-\...........\./.................-............ +................|/............................../..-.\..................-..../../...../.../..../..........|... +........................./.....................\..\....-....../-.....................\|.........././.-........ +...\.....................-...../|............--......-..|...../.....|......|.../.\....|.............\|.......\ +.........-...-.....|.........../...-/........|......./|............-.......-.....\.............\|....../...... +.....|...|.................|...../.............|.................../..........\|..\......|..|....-............ +...........................-.........\......\.............\...................-.....-.\.......-.....|......... +.................-.............-......./.............-..\./......|....-..-..........-....-............\....... +.\..\.......-......|........................\.............-.......................|.........|\.|..\......--/.. +..........-.....||--........|........-....../...........|../...-.........../.....-.\..........|.......-....... +..........\..........|..................\.................-..../............/..........|.......-........../... +..--......../..........-..|........./.........-...../........-.................|..\............../.....-...... +.....\.............|...../......../............./||..........................\............|................... +..-.................-|..-....................\.................|...\.....\............./......-.......\....... +............-../......\...../.-....-.....-....-./../......\..|..|............................|.../..|......... +-................./................................................|...............|....|.....-.....|....../.. +...........-...................|...........\.......-..\.......-...........|..-....../........|...............| +.........|...|-........../...-..........|.........\.....||......./....|...............\......-......\...../... +....|.........|............\.-.......................................-.......................|.-..|.\...\.-... +.|....|....-/....................\\..........................|........\|...|..............\..|......-.\../.... +..|.\......|..../.....|.......-....................|.\..\............/......................|.....\../../..... +.......|\\.\/......................./.............|................../.........|.....\-....................... +......................................../.../................\-..............-................./......\....... +............../............/\......./........................./......|............\/.......................... +......./................|......../.........-............\.../.|....../....|...../..../......../............... +...................|............-\........../...\.......\....\.....-.........-./....|......................... +.....-..-\.................|\...........................|..........\........-...|............................. +..............................-.............-.......\......................../.......\|.......|...-....-...... +\...................\..../.................\................|......-...-............./.-...................... +........................./.|./...|..\.-............|.-.....-..........\....-..../.....|.......|............... +.................../......../..................|.|...............|.......|\.....|......|...............\/..|.. +.........|....-......../........-./..|.../..|./...................-........|.................................. +..|../............-......-.........................-..|....-................-..\....../...........|........... +....................-...............|.../.....|..../......../...|.......\.....-.....\..............-..\.-..... +...........\.........../............................................\......-................-.......|.....-... +..-............./.......-\...........|-..-../............../................................../............... +.................\.......\............../.|.......-...\............................................\.-........ +.\....|....\......|........./.....--......................................|................\..|-.............. +......../...............-..........................|...........................-.............-\.-..|.......... +.......|......|/...\........./......../.....\.........\.......................-...........\..\................ +.-..-../.............|................./../.................\........-......|.\.....||...................\|... +/......../....\.....|-..........\..............-.....|............/\......\...//....................\...-/.... +................-...........-.-\-..........\.-./......../-................./../.\........................./... +-.........-.....|.....-..|..|.........|...................-..........\/.-..................................... +......./...../......\............-.|...............|..../.........|....\.................../..............|... +...........|.......|....|...............\........................\/..\......................................\. +......\........-.........................\..........\.............\......................\/.....\..|.......... +......\...........|.........../..-............./........................../...-......../...............\..|... +..|............\../........../............\...|.......................-...............\-../.|...|\.....\...... +.|....\.|....-|.........\......./.................../.|........|....../.--.\.....\..............-\\.........-. +......................./.......\...........|.\............-.....\.............\.........--......../.\..-.|../. +......../.............../......\.\....|.............../...........................-........-......../......... +.......|\.............|.../|/........../....\.....-....|.............-......./........\..\........\..|......-. +.............../...........-.....\..\....-...../...|......\...........................\...|...........|/...... +.............|....../.................../..|.....................|.......|....//..............\............... +......./....\............................-.........................-/......../|......-....|.............../... +...........................|...................\...............................-.................|...........\ +.............................-......./..../...................\.../...........-.|......................||..... +\....\....\...-./......../.........\................./................\...................|...........-....... +................-.../............/\..................\.\..-....../................./..........|............... +......../...\.......................\.......\..\......|.....|../..........\..........-.............|.......... +../.........................................-\..........-.........|-./.....-...|..|.......\........-...../../. +.....|..........-......../|-..............|.................-...........|...\.....................\........... +.......|..............\....\.....-............../..\\..\.......-........./.........-..|...|................../ +..........-.......-.-................../.........\\...../.....|..........\......./.|.............-...........\ +..................................-..................|...........\../\...../..../...\................/........ +...-.........................................................\.|..............\..................\............ +-.|..|...................../../.|.......\.....|.....\.\...\.........-.................................../..... +...\./....../........\.......-.................\.........|............-.........../...........\.|.........|.\. +..........-...\.............-.-............-.-................/.....................|........|............-... +|......./............/..|..............\...............|.......|\................/....|.........|.........\..\ +.....\../\./.....................-.............\..................|.|......................................... +............/......../.../.......\............/.........................\........................\............ +....../..|.............../....................-.......\................................................|.....\ +................................../.......././.......\.....|.\......-.........-..||......../........-.//...... +........................\.......|............-....-...../..............................-............-....|...- +.....-.......|......\..|.........-....|......\......../..../.......\..........|....\.............||..\........ +..........|...........-|.......\.......-....../...../..........||.......................\............-..|..... +.................../../..............................|....|................/........|-....|................/.. +.....................\................/............................/-........./...|.............\...|..|\..... +.....\..\..........\......../......|.........-....-..-..|...........\....|./....\.\..\............../......... +.......-...............-....../...........-.......................|../...............|...|.........../..../... +.............|.../..................\..\..........-........||................\/...........-|.................. +.............-..............-\.../.................|......\...../..........\...-.....-....../................\ +.....-....................................-.........\/............../.............................|........... +./.|../......\\..........................................|..............\|/..-\..........................\.... +...........-.........\............./....-........-....-....-.........\..\....-\...-...............--.........- +..\.............................\............................./\..........-.............-...-./........../.... +.................../........\....|..-....|||./..............-......-./....................../..|...|.......... +......\.........../............|\...|.-................../....................|\..|..\.............-./......|. +...........-...................-.|........................\...............|/..-...\...|/\...........|......... +............|..../..................................\.......................\........................-........ +.\..........................|......|......../.|....................../.......\......\.............../......... +..........-.../............/..........................|....-......................|.-................|.-...... +......../............-...|.....|......../-.....-|...|./.......-..................-\........................... +...............\.\/.-....././................-.../..../.............../-|.....-.......|......./..--........... +..........-\\.|-................./../..|.-.....--................../.................../.|.......-............ +..\.................-..............-...............\.....|......................./..\.....--........./..../..\ +.......-....../..............|..................\....|..|..........-.....|.|.-.........................\...... +..../..\...\....................................||.|......................................|.......\/.........- +................\-.-.....||....\.........................-...................................................| diff --git a/src/day16.rs b/src/day16.rs new file mode 100644 index 0000000..99bd898 --- /dev/null +++ b/src/day16.rs @@ -0,0 +1,388 @@ +use std::{ + collections::VecDeque, + fmt::{write, Debug}, +}; + +pub fn run() { + let input = include_str!("../input/day16.txt"); + // let input = r#" + // .|...\.... + // |.-.\..... + // .....|-... + // ........|. + // .......... + // .........\ + // ..../.\\.. + // .-.-/..|.. + // .|....-|.\ + // ..//.|.... + // "#; + let contraption: Contraption = input.into(); + + let visited = run_beam( + Beam { + row: 0, + col: -1, + direction: Direction::Right, + }, + &contraption, + ); + + dbg!(visited.count()); + + dbg!(max_visited(&contraption)); +} + +#[derive(Clone)] +struct Contraption { + tiles: Vec>, + width: usize, + height: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Tile { + Empty, + MirrorPos, + MirrorNeg, + SplitterVert, + SplitterHoriz, +} + +impl Tile { + fn tile_char(&self) -> char { + match self { + Tile::Empty => '.', + Tile::MirrorPos => '/', + Tile::MirrorNeg => '\\', + Tile::SplitterVert => '|', + Tile::SplitterHoriz => '-', + } + } +} + +impl Debug for Contraption { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Contraption(\n")?; + for row in self.tiles.iter() { + for tile in row { + write!(f, "{}", tile.tile_char())?; + } + } + write!(f, ")") + } +} + +impl From<&str> for Contraption { + fn from(value: &str) -> Self { + let tiles = value + .trim() + .lines() + .map(|l| { + l.trim() + .chars() + .map(|c| match c { + '.' => Tile::Empty, + '/' => Tile::MirrorPos, + '\\' => Tile::MirrorNeg, + '|' => Tile::SplitterVert, + '-' => Tile::SplitterHoriz, + _ => panic!("unexpected char {:?}", c), + }) + .collect::>() + }) + .collect::>(); + let width = tiles[0].len(); + let height = tiles.len(); + Self { + tiles, + width, + height, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct Beam { + row: isize, + col: isize, + direction: Direction, +} + +impl Beam { + fn move_current(&mut self) { + self.move_in(self.direction) + } + + fn move_in(&mut self, dir: Direction) { + match dir { + Direction::Up => { + self.row -= 1; + } + Direction::Down => { + self.row += 1; + } + Direction::Left => { + self.col -= 1; + } + Direction::Right => { + self.col += 1; + } + } + } + + fn in_bounds(&self, contraption: &Contraption) -> bool { + self.row >= 0 + && self.row < contraption.height as isize + && self.col >= 0 + && self.col < contraption.width as isize + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Direction { + Up, + Down, + Left, + Right, +} + +impl Direction { + fn is_vertical(&self) -> bool { + match self { + Direction::Up | Direction::Down => true, + _ => false, + } + } + + fn is_horizontal(&self) -> bool { + match self { + Direction::Left | Direction::Right => true, + _ => false, + } + } +} + +#[derive(Debug)] +struct Visited { + directions: Vec>, +} + +impl Visited { + fn new(width: usize, height: usize) -> Self { + Self { + directions: vec![vec![0; width]; height], + } + } + + fn visited_any(&self, row: usize, col: usize) -> bool { + self.directions[row][col] != 0 + } + + fn visited(&self, row: usize, col: usize, dir: Direction) -> bool { + (self.directions[row][col] >> (dir as usize)) & 1 == 1 + } + + fn visit(&mut self, row: usize, col: usize, dir: Direction) { + self.directions[row][col] |= 1 << dir as usize; + } + + fn count(&self) -> usize { + self.directions + .iter() + .map(|row| row.iter().filter(|&&x| x != 0).count()) + .sum() + } +} + +fn run_beam(initial: Beam, contraption: &Contraption) -> Visited { + let mut visited = Visited::new(contraption.width, contraption.height); + let mut beams = VecDeque::from([initial]); + + while let Some(mut beam) = beams.pop_front() { + beam.move_current(); + + while beam.in_bounds(contraption) { + if visited.visited(beam.row as usize, beam.col as usize, beam.direction) { + break; + } + + visited.visit(beam.row as usize, beam.col as usize, beam.direction); + + match contraption.tiles[beam.row as usize][beam.col as usize] { + Tile::Empty => (), + Tile::SplitterVert => { + if beam.direction.is_horizontal() { + beams.push_back(Beam { + row: beam.row, + col: beam.col, + direction: Direction::Up, + }); + beam.direction = Direction::Down; + } + } + Tile::SplitterHoriz => { + if beam.direction.is_vertical() { + beams.push_back(Beam { + row: beam.row, + col: beam.col, + direction: Direction::Left, + }); + beam.direction = Direction::Right; + } + } + Tile::MirrorPos => { + let new_dir = match beam.direction { + Direction::Up => Direction::Right, + Direction::Down => Direction::Left, + Direction::Left => Direction::Down, + Direction::Right => Direction::Up, + }; + beam.direction = new_dir; + } + Tile::MirrorNeg => { + let new_dir = match beam.direction { + Direction::Up => Direction::Left, + Direction::Down => Direction::Right, + Direction::Left => Direction::Up, + Direction::Right => Direction::Down, + }; + beam.direction = new_dir; + } + } + + beam.move_current(); + } + } + + visited +} + +fn debug_beams(contraption: &Contraption, visited: &Visited, beams: &VecDeque) { + for row in 0..contraption.height { + for col in 0..contraption.width { + if let Some(beam) = beams + .iter() + .find(|b| b.row == row as isize && b.col == col as isize) + { + let c = match beam.direction { + Direction::Up => '^', + Direction::Down => 'V', + Direction::Left => '<', + Direction::Right => '>', + }; + print!("{}", c); + } else if visited.visited_any(row, col) { + print!("#"); + } else { + print!("{}", contraption.tiles[row][col].tile_char()); + } + } + println!(); + } +} + +fn max_visited(contraption: &Contraption) -> usize { + let mut max = 0; + for col in 0..contraption.width { + max = max.max( + run_beam( + Beam { + row: -1, + col: col as isize, + direction: Direction::Down, + }, + contraption, + ) + .count(), + ); + max = max.max( + run_beam( + Beam { + row: contraption.height as isize, + col: col as isize, + direction: Direction::Up, + }, + contraption, + ) + .count(), + ); + } + for row in 0..contraption.height { + max = max.max( + run_beam( + Beam { + row: row as isize, + col: -1, + direction: Direction::Right, + }, + contraption, + ) + .count(), + ); + max = max.max( + run_beam( + Beam { + row: row as isize, + col: contraption.width as isize, + direction: Direction::Left, + }, + contraption, + ) + .count(), + ); + } + max +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_run_beam() { + let contraption: Contraption = r#" +.|...\.... +|.-.\..... +.....|-... +........|. +.......... +.........\ +..../.\\.. +.-.-/..|.. +.|....-|.\ +..//.|.... + "# + .into(); + + let visited = run_beam( + Beam { + row: 0, + col: -1, + direction: Direction::Right, + }, + &contraption, + ); + + assert_eq!(visited.count(), 46); + } + + #[test] + fn test_max_visited() { + let contraption: Contraption = r#" +.|...\.... +|.-.\..... +.....|-... +........|. +.......... +.........\ +..../.\\.. +.-.-/..|.. +.|....-|.\ +..//.|.... + "# + .into(); + + assert_eq!(max_visited(&contraption), 51); + } +} diff --git a/src/main.rs b/src/main.rs index 9b93b48..0f727c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,8 @@ mod day12; mod day13; mod day14; mod day15; +mod day16; fn main() { - day15::run(); + day16::run(); }