Day 16: The Floor Will Be Lava
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
Rust
use std::fs; use std::path::PathBuf; use clap::Parser; use rayon::prelude::*; #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Cli { input_file: PathBuf, } #[derive(Copy, Clone)] enum TileState { None, Energized(BeamState), } #[derive(Default, Copy, Clone)] struct BeamState { up: bool, down: bool, left: bool, right: bool, } fn main() { // Parse CLI arguments let cli = Cli::parse(); // Read file let input_text = fs::read_to_string(&cli.input_file) .expect(format!("File \"{}\" not found", cli.input_file.display()).as_str()); let tiles: Vec> = input_text.lines().map(|l| l.chars().collect()).collect(); // Part 1 let part_1 = test_beam(&tiles, (0, 0), (0, 1)); println!("Part 1: {}", part_1); // Part 2 let part_2: usize = (0..4) .into_par_iter() .map(|dir| { (0..tiles.len()) .into_par_iter() .map(move |x| (dir.clone(), x)) }) .flatten() .map(|(dir, x)| match dir { 0 => ((0, x), (1, 0)), 1 => ((x, tiles[0].len() - 1), (0, -1)), 2 => ((tiles.len() - 1, x), (-1, 0)), 3 => ((x, 0), (0, 1)), _ => unreachable!(), }) .map(|(loc, dir)| test_beam(&tiles, loc, dir)) .max() .unwrap(); println!("Part 2: {}", part_2); } fn test_beam( tiles: &Vec>, start_location: (usize, usize), start_direction: (i64, i64), ) -> usize { let mut energized: Vec> = vec![vec![TileState::None; tiles[0].len()]; tiles.len()]; continue_beam( &mut energized, &tiles, start_location, start_direction, true, 0, ); energized .iter() .map(|r| { r.iter() .filter(|t| matches!(t, TileState::Energized(_))) .count() }) .sum() } fn continue_beam( energized: &mut Vec>, tiles: &Vec>, beam_location: (usize, usize), beam_direction: (i64, i64), start_hack: bool, depth: usize, ) { assert_ne!(beam_direction, (0, 0)); // Set current tile to energized with the direction let current_state = energized[beam_location.0][beam_location.1]; if !start_hack { energized[beam_location.0][beam_location.1] = match current_state { TileState::None => TileState::Energized(match beam_direction { (0, 1) => BeamState { right: true, ..BeamState::default() }, (0, -1) => BeamState { left: true, ..BeamState::default() }, (1, 0) => BeamState { down: true, ..BeamState::default() }, (-1, 0) => BeamState { up: true, ..BeamState::default() }, _ => unreachable!(), }), TileState::Energized(state) => TileState::Energized(match beam_direction { (0, 1) => { if state.right { return; } BeamState { right: true, ..state } } (0, -1) => { if state.left { return; } BeamState { left: true, ..state } } (1, 0) => { if state.down { return; } BeamState { down: true, ..state } } (-1, 0) => { if state.up { return; } BeamState { up: true, ..state } } _ => unreachable!(), }), }; } // energized[beam_location.0][beam_location.1] = TileState::Energized(BeamState { up: , down: , left: , right: }); let next_beam_location = { let loc = ( (beam_location.0 as i64 + beam_direction.0), (beam_location.1 as i64 + beam_direction.1), ); if start_hack { beam_location } else if loc.0 < 0 || loc.0 >= tiles.len() as i64 || loc.1 < 0 || loc.1 >= tiles[0].len() as i64 { return; } else { (loc.0 as usize, loc.1 as usize) } }; let next_beam_tile = tiles[next_beam_location.0][next_beam_location.1]; let next_beam_directions: Vec<(i64, i64)> = match next_beam_tile { '.' => vec![beam_direction], '/' => match beam_direction { (0, 1) => vec![(-1, 0)], (0, -1) => vec![(1, 0)], (1, 0) => vec![(0, -1)], (-1, 0) => vec![(0, 1)], _ => unreachable!(), }, '\\' => match beam_direction { (0, 1) => vec![(1, 0)], (0, -1) => vec![(-1, 0)], (1, 0) => vec![(0, 1)], (-1, 0) => vec![(0, -1)], _ => unreachable!(), }, '|' => match beam_direction { (0, 1) => vec![(1, 0), (-1, 0)], (0, -1) => vec![(1, 0), (-1, 0)], (1, 0) => vec![(1, 0)], (-1, 0) => vec![(-1, 0)], _ => unreachable!(), }, '-' => match beam_direction { (0, 1) => vec![(0, 1)], (0, -1) => vec![(0, -1)], (1, 0) => vec![(0, 1), (0, -1)], (-1, 0) => vec![(0, 1), (0, -1)], _ => unreachable!(), }, _ => unreachable!(), }; for dir in next_beam_directions { continue_beam(energized, tiles, next_beam_location, dir, false, depth + 1); } }
26.28 line-seconds