diff --git a/2024/06/Cargo.toml b/2024/06/Cargo.toml new file mode 100644 index 0000000..6b4c91b --- /dev/null +++ b/2024/06/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "aoc-2024-06" +version = "0.1.0" +authors = ["MÃ¥rten Kongstad "] +edition = "2021" + +[dependencies] +anyhow = "1.0" +aoc = { path = "../../aoc" } +rustc-hash = "2.1.0" diff --git a/2024/06/src/input.txt b/2024/06/src/input.txt new file mode 100644 index 0000000..3c8989d --- /dev/null +++ b/2024/06/src/input.txt @@ -0,0 +1,130 @@ +..#.....................#............#....#...........#...............................#.....#..................................... +.................#............................#.............##..#...............................#....#..#.........#............... +.............................................##.........................................#....................#...............#...# +...##....................#...............#.....#....................#......##..............#............................#....#.... +.................................#..#..............#...........#.............#..#........................#............#........... +.................#.........................#...........................#........................#........................#........ +...#....................................#....#.........#................#...............#.....#................#.....#............ +.............#.#..........................................................#...#..................#....#.......#.....#...#......... +.....#........................#....##...#............................................................#............................ +..................#...#.........................................#..................#.............................#.#........#..... +......#...............................#.#..........##..#...........#.........................#.......#....................#....... +.................................#..............#...............#........#..........#.........#............#.........#.......#...# +..#..#............#...#.....................#...............#............#.#........................#........#...............#.... +..............#..#.#........................#.........#...........##.......#..........#.....................#..............#...#.. +..........................#.................##...................................#....#.........#................................. +..................#..#........#....#...............#..............#.......#.......#......................................#..#...#. +..........#.#.................#.........#...................#.......................##......#....................#.......#........ +..........#.........#...#......................................................................#.....#............#........#...... +...##.............#...........................................................#..#....................##.#...#.#..#.........#..#.. +.....#......#.............................#.......#...#...#...............#.....#............#........#..#.#...................... +........#................#.........#.......................................................................#..........#........... +.......#........................................#..........#...............................#..#................................... +..................##.......#.......#.....#............#.......#...#.........#....##...............#..#.............#..........#... +.......#...........#...........#...........................#.............#.........#..#........................#.##............... +.....................................................................#........#....#...........................................#.. +....#...........#......#.........#....................................#.................................#......#.................. +...#........................................#..#...............................#.....................#.#......#................... +..#.....#.................................#.................#....#............................................#......#............ +...................................................##...........#.......#.............#.................#.......#................. +..........................................................##..............#....#....#.............#............................... +........................................................#.....................................#................................#.. +..............##....#..#..........#...........#......#..#....#.......#................#............................#..#...#....... +..........................#....................#.................................................#................................ +#................................................#.....................#..#...............##........#...#...#.........#........... +...........#.................................#..#....................#.#.......#..........................#.......#.......#....... +..............................#......#......#.................#.................#.................#.#.............#..#.#.......... +.......................#....................#....................................#.....#.#.......#............................#... +...............................................................................................#.#................................ +#..................#.....#...............................#..............#...#..................................................... +..........................................................#.................................................#..................... +..........#.........................#.....................................................#.........#..........#................#. +........#..............#..#......................................#.........#............#.................................#....... +.......#.........................................................#.........#................#...............................#..... +...........#............................................#...#.............................#.....^................................# +................#.............#...#..............................#..................................#............................. +.........................................................................................................#........................ +.................................................#........#.......................#.#.....#......................#................ +.........#.........#...#....................................................#..................................................... +##.##..#...................................#...................................................................................... +.................#...........................................................................................#........#........... +.........................................................................#........................#....#......................#... +..............#......................#........#..........................#.........#.............................................. +.......................#............................................................................##............................ +.....#.................#........#...#...............#.............................#......................#........................ +....#...................................................................................#............##........................... +................#............................#............................................#....................................... +.......................................................................................................#......#................... +......................................................................................#...#....................................... +...............................................#........#..........#............................#..............#.......#.......... +..............#.....................#........#..#............................#...#..#.#...................................#....... +..........#...............................#............................#...........................................#.............. +....#............#.#....#......................................................................#.................................. +.......................#.......................#................................#..............#.....................#.........#.. +...........#.........................#.............#.#........#........#..........................................#............... +.......#......................#....................#...............................#......................#...........#........... +............#..................................................................................................................... +....#.......#............................................................#.........#.............#..........#....#..........#..... +.......#.........................................................................#..................#..#....#.......#............. +............................#....#.......#......#.......#.....................#.................#................................. +.......................................................#.............#..........................#................................. +....................................#.....................................##......................#............................#.. +..............#...............#....................#.......................#................#......................#.............. +....................#...........................#...................................................................#............. +...#..........................#...........................#............................................................#.......... +..............#.................#.............................#..#.......#.......................#.##............................. +....................#.....#...#..............................................#......#...........#.................#..#....#....... +#......................................#.....................#..#..#.#...........#.............#.................................# +.....................#...........................................................#..........#............##..........#............ +.......#..................................#...............#..........#....#...................................................#... +.............#.................#...........................#..............#.................................................#..... +...............................#......................................##...................................#.#......#..........#.. +.................##....................#.................................................#......................#................# +........#....................................#..........#.........................#..................#......................#..... +...#....#...........................#..............................#.#..........................#................................. +.#...................................#..#......#.................................................................#................ +.................................#...........#................#.#........................#....................................##.. +#..#.....##...............#................................................................#....#......#.........................# +.#....#......................................................#.........................#.......................................#.. +.#..............................................#.................................................................#............... +...............#..........................................#...#...............................#.#..#.#........#................... +..............#................................#.......#..................................#.........................#........#.... +.......................##..................................................#...................................................... +..............................#...............................##.................................................................. +#....................#...........................................................#.............................#.................. +#..................................................................#...#.......................................................... +#..#........#...................................#..#..........##..............#................................................... +.......................#.....................#.................................................................................... +.....................#...........#.............................................................#........................#....#.... +...............#............................................................................##...#..........................#..... +...#......................................#....................................................................................... +....#...........................#.........#.................................................#..........#...#........#....#........ +......#....#.#............................#..........................................#........................................#... +...........#...#.............................................#......................#..................#.....................#.... +...#..........#........#..........#.......#..............#.............................#.......................#................#. +...........#...............#...........................................................#.......................................... +..#..........##.................................................#...#...............#.......................#...............##.... +.......................#..............#.............#......................................................#..................#... +..............#..#........##..........#...................................................#.............##....................#... +...................#..................................................#................#......#.....#.........#.#...#............. +..................#.................................................#.................................................#.........#. +......................................#.#........#.....#...#..........#..............#.........................#...#.............. +.................................#..............#..#.....................#................#.............#..#..#................... +.........#.......#.#..............#..#...............#.................#..................................#..#.................... +.............................#....#.......##..................................................................................##.. +.....................................................................................#........#.......#......#.................... +........#...........#..........#..........#............................#...............#........#.#...........................#... +.#.................#...#..............#...#...................#........#...............#.......................................... +.........#............................................##........#......#.....................#.......................#............ +.......................................#..........#..#......#........#..........#..........................#....................#. +....#......#..........................#....................#.......................................#.....###.......#.............. +.......#..................#....#.......................................................................#.......................... +....#........................#.............................................................#.......#..........................#... +......................#.................................#..........#................#..#.........................#................ +...........#....................................................#..............#...........................#...................... +.....#................#........#...#....#........#............#...............#.......................#..#.........#.............. +#..................................................#...........................#....#...........#................................. +....#.#.....................................#.#...............#................#....................................#............. +............#....................#.#.#...............................................#...................##....................... +...##..............#........................#.............#.......#...........#.#.##..............................#....##......... +......#...........#....................................................#.........................##............................... diff --git a/2024/06/src/main.rs b/2024/06/src/main.rs new file mode 100644 index 0000000..9efd7b3 --- /dev/null +++ b/2024/06/src/main.rs @@ -0,0 +1,188 @@ +use anyhow::{anyhow, bail, ensure, Result}; +use rustc_hash::FxHashSet; + +fn main() -> Result<()> { + let input = include_str!("input.txt"); + aoc::run!(part_one(input), 4722)?; + aoc::run!(part_two(input), 1602)?; + Ok(()) +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] +struct XY { + x: i32, + y: i32, +} + +impl From<(i32, i32)> for XY { + fn from(value: (i32, i32)) -> Self { + Self { + x: value.0, + y: value.1, + } + } +} + +impl XY { + fn north(&self) -> XY { + (self.x, self.y - 1).into() + } + + fn south(&self) -> XY { + (self.x, self.y + 1).into() + } + + fn west(&self) -> XY { + (self.x - 1, self.y).into() + } + + fn east(&self) -> XY { + (self.x + 1, self.y).into() + } + + fn forward(&self, direction: Direction) -> XY { + match direction { + Direction::North => self.north(), + Direction::East => self.east(), + Direction::South => self.south(), + Direction::West => self.west(), + } + } +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] +enum Direction { + North, + East, + South, + West, +} + +impl Direction { + fn ninety_degrees_right(&self) -> Direction { + match self { + Direction::North => Direction::East, + Direction::East => Direction::South, + Direction::South => Direction::West, + Direction::West => Direction::North, + } + } +} + +struct Grid { + bounding_box: (XY, XY), + obstacles: FxHashSet, +} + +fn parse(input: &str) -> Result<(Grid, XY)> { + let mut x = 0; + let mut y = 0; + let mut max = (0, 0); + let mut start: Option = None; + let mut obstacles = FxHashSet::default(); + for ch in input.chars() { + match ch { + '\n' => { + max = (x - 1, y); + x = 0; + y += 1; + } + '.' => { + x += 1; + } + '#' => { + obstacles.insert((x, y).into()); + x += 1; + } + '^' => { + start = Some((x, y).into()); + x += 1; + } + _ => bail!("unexpected char '{}'", ch), + } + } + Ok(( + Grid { + bounding_box: ((0, 0).into(), (max).into()), + obstacles, + }, + start.ok_or_else(|| anyhow!("no start position found"))?, + )) +} + +// Return all visited squares, or None if the pattern loops +fn simulate_patrol(grid: &Grid, mut position: XY) -> Option> { + let mut direction = Direction::North; + let mut seen = FxHashSet::default(); + loop { + if position.x < grid.bounding_box.0.x + || position.x > grid.bounding_box.1.x + || position.y < grid.bounding_box.0.y + || position.y > grid.bounding_box.1.y + { + break; + } + if !seen.insert((position, direction)) { + // loop detected + return None; + } + while grid.obstacles.contains(&position.forward(direction)) { + direction = direction.ninety_degrees_right(); + } + position = position.forward(direction); + } + Some(seen.into_iter().map(|(xy, _)| xy).collect()) +} + +fn part_one(input: &str) -> Result { + let (grid, start) = parse(input)?; + simulate_patrol(&grid, start) + .map(|set| set.len()) + .ok_or_else(|| anyhow!("unexpected loop detected")) +} + +fn part_two(input: &str) -> Result { + let (mut grid, start) = parse(input)?; + let mut visited = + simulate_patrol(&grid, start).ok_or_else(|| anyhow!("unexpected loop detected"))?; + ensure!(visited.remove(&start)); + + let mut count = 0; + for candidate in visited.into_iter() { + debug_assert!(!grid.obstacles.contains(&candidate)); + grid.obstacles.insert(candidate); + if simulate_patrol(&grid, start).is_none() { + count += 1; + } + grid.obstacles.remove(&candidate); + } + + Ok(count) +} + +#[cfg(test)] +mod tests { + use super::*; + + const INPUT: &str = include_str!("test-input.txt"); + + #[test] + fn test_parse() { + let (grid, start) = parse(INPUT).unwrap(); + assert_eq!(start, (4, 6).into()); + assert_eq!(grid.obstacles.len(), 8); + assert!(grid.obstacles.contains(&(4, 0).into())); + assert!(!grid.obstacles.contains(&(0, 0).into())); + assert_eq!(grid.bounding_box, ((0, 0).into(), (9, 9).into())); + } + + #[test] + fn test_part_one() { + assert_eq!(part_one(INPUT).unwrap(), 41); + } + + #[test] + fn test_part_two() { + assert_eq!(part_two(INPUT).unwrap(), 6); + } +} diff --git a/2024/06/src/test-input.txt b/2024/06/src/test-input.txt new file mode 100644 index 0000000..a4eb402 --- /dev/null +++ b/2024/06/src/test-input.txt @@ -0,0 +1,10 @@ +....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#... diff --git a/Cargo.lock b/Cargo.lock index 739454b..688cc1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ dependencies = [ "anyhow", "atty", "regex", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -136,7 +136,7 @@ version = "0.1.0" name = "aoc-2015-18" version = "0.1.0" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -258,7 +258,7 @@ dependencies = [ name = "aoc-2020-15" version = "0.1.0" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -369,7 +369,7 @@ version = "0.1.0" name = "aoc-2021-15" version = "0.1.0" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -414,7 +414,7 @@ name = "aoc-2021-23" version = "0.1.0" dependencies = [ "lazy_static", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -558,7 +558,7 @@ dependencies = [ "aoc", "itertools 0.10.5", "regex", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -575,7 +575,7 @@ version = "0.1.0" dependencies = [ "anyhow", "aoc", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -586,7 +586,7 @@ dependencies = [ "aoc", "rayon", "regex", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -620,7 +620,7 @@ version = "0.1.0" dependencies = [ "anyhow", "aoc", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -860,6 +860,15 @@ dependencies = [ "aoc", ] +[[package]] +name = "aoc-2024-06" +version = "0.1.0" +dependencies = [ + "anyhow", + "aoc", + "rustc-hash 2.1.0", +] + [[package]] name = "ascii" version = "1.1.0" @@ -1196,6 +1205,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "ryu" version = "1.0.5"