From 055946115a277250062e70cceaa7620f64925d65 Mon Sep 17 00:00:00 2001 From: Andrew Coleman Date: Thu, 28 Dec 2023 22:20:46 -0500 Subject: [PATCH] day16 solution --- 2023/src/day16.rs | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 2023/src/lib.rs | 1 + 2 files changed, 221 insertions(+) create mode 100644 2023/src/day16.rs diff --git a/2023/src/day16.rs b/2023/src/day16.rs new file mode 100644 index 0000000..9850c99 --- /dev/null +++ b/2023/src/day16.rs @@ -0,0 +1,220 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use std::collections::HashSet; + +#[aoc_generator(day16)] +fn parse(input: &str) -> Vec> { + input + .lines() + .filter_map(|line| { + if !line.is_empty() { + Some(line.chars().collect()) + } else { + None + } + }) + .collect() +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +enum Dir { + North, + East, + South, + West, +} + +fn visited_spaces( + map: &[Vec], + visited: &mut HashSet<(i64, i64, Dir)>, + start_x: i64, + start_y: i64, + start_dir: Dir, + depth: usize, +) { + if start_x < 0 + || start_y < 0 + || start_x as usize > (map.len() - 1) + || start_y as usize > (map[0].len() - 1) + { + return; + } + let mut x = start_x; + let mut y = start_y; + let mut dir = start_dir; + if visited.contains(&(x, y, dir)) { + return; + } + loop { + let now = (x, y, dir); + if visited.contains(&now) { + return; + } else { + visited.insert((x, y, dir)); + } + match dir { + Dir::North => match map[x as usize][y as usize] { + '/' => dir = Dir::East, + '\\' => dir = Dir::West, + '|' => {} + '-' => { + visited_spaces(map, visited, x, y, Dir::West, depth + 1); + dir = Dir::East; + } + '.' => {} + n @ _ => panic!("unknown map piece {}", n), + }, + Dir::South => match map[x as usize][y as usize] { + '/' => dir = Dir::West, + '\\' => dir = Dir::East, + '|' => {} + '-' => { + visited_spaces(map, visited, x, y, Dir::West, depth + 1); + dir = Dir::East; + } + '.' => {} + n @ _ => panic!("unknown map piece {}", n), + }, + Dir::East => match map[x as usize][y as usize] { + '/' => dir = Dir::North, + '\\' => dir = Dir::South, + '|' => { + visited_spaces(map, visited, x, y, Dir::North, depth + 1); + dir = Dir::South; + } + '-' => {} + '.' => {} + n @ _ => panic!("unknown map piece {}", n), + }, + Dir::West => match map[x as usize][y as usize] { + '/' => dir = Dir::South, + '\\' => dir = Dir::North, + '|' => { + visited_spaces(map, visited, x, y, Dir::North, depth + 1); + dir = Dir::South; + } + '-' => {} + '.' => {} + n @ _ => panic!("unknown map piece {}", n), + }, + } + match dir { + Dir::North => { + x -= 1; + if x < 0 { + return; + } + } + Dir::South => { + x += 1; + if x as usize >= map.len() { + return; + } + } + Dir::East => { + y += 1; + if y as usize >= map[0].len() { + return; + } + } + Dir::West => { + y -= 1; + if y < 0 { + return; + } + } + } + } +} + +fn energized_squares(visited: &HashSet<(i64, i64, Dir)>) -> usize { + let mut t: HashSet<(i64, i64)> = HashSet::new(); + for i in visited.iter() { + t.insert((i.0, i.1)); + } + t.len() +} + +#[aoc(day16, part1)] +fn part1(input: &[Vec]) -> usize { + let mut visited: HashSet<(i64, i64, Dir)> = HashSet::new(); + visited_spaces(input, &mut visited, 0, 0, Dir::East, 0); + energized_squares(&visited) +} + +#[aoc(day16, part2)] +fn part2(input: &[Vec]) -> usize { + let mut max = 0; + let xlen = input.len() - 1; + let ylen = input[0].len() - 1; + + for t in 0..=xlen { + let mut evisited: HashSet<(i64, i64, Dir)> = HashSet::new(); + visited_spaces(input, &mut evisited, t as i64, 0, Dir::East, 0); + let emax = energized_squares(&evisited); + if emax > max { + max = emax; + } + + let mut wvisited: HashSet<(i64, i64, Dir)> = HashSet::new(); + visited_spaces( + input, + &mut wvisited, + xlen as i64, + (ylen - t) as i64, + Dir::West, + 0, + ); + let wmax = energized_squares(&wvisited); + if wmax > max { + max = wmax; + } + } + + for t in 0..=ylen { + let mut svisited: HashSet<(i64, i64, Dir)> = HashSet::new(); + visited_spaces(input, &mut svisited, 0, t as i64, Dir::South, 0); + let smax = energized_squares(&svisited); + if smax > max { + max = smax; + } + + let mut nvisited: HashSet<(i64, i64, Dir)> = HashSet::new(); + visited_spaces( + input, + &mut nvisited, + xlen as i64, + (ylen - t) as i64, + Dir::North, + 0, + ); + let nmax = energized_squares(&nvisited); + if nmax > max { + max = nmax; + } + } + + max +} + +#[cfg(test)] +mod tests { + use super::*; + + const SAMPLE_DATA: &'static str = r#".|...\.... +|.-.\..... +.....|-... +........|. +.......... +.........\ +..../.\\.. +.-.-/..|.. +.|....-|.\ +..//.|...."#; + + #[test] + fn sample_data() { + let input = parse(&SAMPLE_DATA); + assert_eq!(part1(&input), 46); + assert_eq!(part2(&input), 51); + } +} diff --git a/2023/src/lib.rs b/2023/src/lib.rs index 8376a12..bd848b8 100644 --- a/2023/src/lib.rs +++ b/2023/src/lib.rs @@ -15,5 +15,6 @@ mod day12; mod day13; mod day14; mod day15; +mod day16; aoc_lib! { year = 2023 }