diff --git a/advent_of_code_2024/src/day6/part2.rs b/advent_of_code_2024/src/day6/part2.rs index 6197ad3..de28226 100644 --- a/advent_of_code_2024/src/day6/part2.rs +++ b/advent_of_code_2024/src/day6/part2.rs @@ -1,4 +1,109 @@ +use std::collections::{HashMap, HashSet}; + +const DIRECTIONS: [(i64, i64); 4] = [(0, -1), (1, 0), (0, 1), (-1, 0)]; // up right down left + +fn find_start(grid: &[Vec]) -> (i64, i64) { + for (ypos, row) in grid.iter().enumerate() { + let Some(xpos) = row.iter().position(|ch| *ch == b'^') else { + continue; + }; + return (xpos as i64, ypos as i64); + } + + panic!("No starting position found"); +} + +fn detect_loop(grid: &[Vec], start_pos: (i64, i64), start_dir: usize) -> (bool, HashSet<(i64, i64, usize)>) { + let width = grid[0].len() as i64; + let height = grid.len() as i64; + let mut position = start_pos; + let mut direction = start_dir; + + let mut tensors: HashSet<(i64, i64, usize)> = HashSet::new(); + + loop { + tensors.insert((position.0, position.1, direction)); + + let new_position = (position.0 + DIRECTIONS[direction].0, position.1 + DIRECTIONS[direction].1); + + if new_position.0 < 0 || new_position.0 >= width || new_position.1 < 0 || new_position.1 >= height { + return (false, Default::default()); // new position is off the map, so no loop + } + + let new_direction = if grid[new_position.1 as usize][new_position.0 as usize] == b'#' { + (direction + 1) % DIRECTIONS.len() + } else { + direction + }; + + if tensors.contains(&(new_position.0, new_position.1, new_direction)) { + // we are at the exact same position again, so we are in a loop + return (true, tensors); + } + + let next_step = grid[new_position.1 as usize][new_position.0 as usize]; + if next_step == b'#' || next_step == b'@' { + direction = (direction + 1) % DIRECTIONS.len(); + } else { + position = new_position; + } + } +} + +pub fn draw_walked_grid(grid: &[Vec], steps: &HashSet<(i64, i64, usize)>) { + let steps = steps.iter().map(|tup| ((tup.0, tup.1), tup.2)).collect::>(); + + for (ypos, line) in grid.iter().enumerate() { + for (xpos, step) in line.iter().enumerate() { + if *step == b'.' { + let pos = &(xpos as i64, ypos as i64); + if steps.contains_key(pos) { + let char = if steps.get(pos).unwrap() % 2 == 0 { "|" } else { "-" }; + print!("{}", char); + } else { + print!("."); + } + } else { + print!("{}", *step as char); + } + } + println!(); + } +} pub fn solve(input: &str) { + let grid = input.lines().map(|line| line.as_bytes().to_vec()).collect::>(); + let width = grid[0].len() as i64; + let height = grid.len() as i64; + let start = find_start(&grid); + let start_dir = 0; + + let mut position = start; + let mut direction = 0; + + let mut looping_blockades = HashSet::new(); + loop { + let new_position = (position.0 + DIRECTIONS[direction].0, position.1 + DIRECTIONS[direction].1); + if new_position.0 < 0 || new_position.0 >= width || new_position.1 < 0 || new_position.1 >= height { + break; // we're off the map + } + + if new_position != start { + let mut test_grid = grid.clone(); + test_grid[new_position.1 as usize][new_position.0 as usize] = b'@'; + let (looped, steps) = detect_loop(&test_grid, start, start_dir); + if looped { + looping_blockades.insert(new_position); + } + } + + if grid[new_position.1 as usize][new_position.0 as usize] == b'#' { + direction = (direction + 1) % DIRECTIONS.len(); + } else { + position = new_position; + } + } + + println!("Number of possible obstacles: {}", looping_blockades.len()); } \ No newline at end of file