diff --git a/aoc2024/src/day06.rs b/aoc2024/src/day06.rs index 0782ba9..05788df 100644 --- a/aoc2024/src/day06.rs +++ b/aoc2024/src/day06.rs @@ -1,13 +1,95 @@ +use std::{collections::HashSet, isize}; + +use itertools::Itertools; use shared::{Solution, Answer}; pub struct Day06; impl Solution for Day06 { fn part_1(&self, input: &str) -> Answer { - Answer::Unimplemented + let line = input.find("\n").unwrap() as isize; + let (map, mut guard) = parse(input); + + let mut facings = [-line, 1, line, -1].into_iter().cycle().peekable(); + + let mut seen = HashSet::new(); + + while let Some(&obstacle) = map.get((guard + facings.peek().unwrap()) as usize) { + seen.insert(guard); + if obstacle { facings.next(); } + else { guard += facings.peek().unwrap(); } + }; + seen.insert(guard); + + Answer::Number(seen.len() as u64) } fn part_2(&self, input: &str) -> Answer { - Answer::Unimplemented + let line = input.find("\n").unwrap() as isize; + let (map, mut guard) = parse(input); + + let start = guard; + + let mut facings = [-line, 1, line, -1].into_iter().cycle().peekable(); + + let mut seen: HashSet = HashSet::new(); + while let Some(&obstacle) = map.get((guard + facings.peek().unwrap()) as usize) { + seen.insert(guard); + if obstacle { facings.next(); } + else { guard += facings.peek().unwrap(); } + }; + seen.insert(guard); + + let mut loops = 0; + + for i in seen.iter() { + let mut new_map = map.clone(); + if new_map[*i as usize] {break;} else {new_map[*i as usize] = true;} + let mut new_guard = start; + let mut new_facings = [-line, 1, line, -1].into_iter().cycle().peekable(); + + let mut new_seen: HashSet<(isize, isize)> = HashSet::new(); + + while let Some(&obstacle) = new_map.get((new_guard + new_facings.peek().unwrap()) as usize) { + // wraparound protection + if new_facings.peek().unwrap().abs() == 1 && new_guard / line != (new_guard + new_facings.peek().unwrap()) / line { break; } + + if new_seen.contains(&(new_guard, *new_facings.peek().unwrap())) { + // debug_print(&new_map, &new_seen, line, Some(*i)); + loops += 1; + println!("{loops}"); + break + } + + new_seen.insert((new_guard, *new_facings.peek().unwrap())); + if obstacle { new_facings.next(); } + else { new_guard += new_facings.peek().unwrap(); } + }; + } + Answer::Number(loops) } } + +fn debug_print(map: &[bool], seen: &HashSet<(isize, isize)>, line: isize, new: Option) { + let path = seen.iter().collect_vec(); + let mut out = map.iter().map(|&x| if x {"#"} else {"."}).join(""); + for &(i, c) in path { + if out[i as usize..=i as usize] == *"." { + out.replace_range(i as usize..=i as usize, if c.abs() == 1 {"-"} else {"|"}); + } else { + out.replace_range(i as usize..=i as usize, "+"); + } + } + if let Some(x) = new { out.replace_range(x as usize..=x as usize, "O"); } + for mut chunk in out.chars().chunks(line as usize).into_iter() { + println!("{}", chunk.join("")) + } +} + +fn parse(input: &str) -> (Vec, isize) { + let flat = input.trim().replace("\n", ""); + let guard = flat.find("^").unwrap(); + let map = flat.chars().map(|c| c == '#').collect_vec(); + + (map, guard as isize) +}