From c1abd8d8f8d7508cc91a4de90f3090d553d959d2 Mon Sep 17 00:00:00 2001 From: Johannes Date: Sun, 15 Dec 2024 13:20:15 +0100 Subject: [PATCH] day 15 part 2 --- src/day15.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++-- src/utils/grid.rs | 9 +++ 2 files changed, 142 insertions(+), 5 deletions(-) diff --git a/src/day15.rs b/src/day15.rs index 40f6880..aa45ee8 100644 --- a/src/day15.rs +++ b/src/day15.rs @@ -1,6 +1,8 @@ -use std::fs::read_to_string; +use std::{collections::HashSet, fs::read_to_string}; -use crate::utils::grid::Grid; +use itertools::Itertools; + +use crate::utils::grid::{Coord, Grid}; pub fn day_main() { let input = read_to_string("input/day15.txt").unwrap(); @@ -44,8 +46,111 @@ fn part1(input: &str) -> RiddleResult { .sum() } -fn part2(_input: &str) -> RiddleResult { - 0 +fn part2(input: &str) -> RiddleResult { + let (grid, movements) = input.split_once("\n\n").unwrap(); + let grid = grid + .lines() + .map(|line| { + { + line.chars().flat_map(|c| { + match c { + '.' => "..", + '@' => "@.", + '#' => "##", + 'O' => "[]", + _ => panic!(), + } + .chars() + }) + } + .join("") + }) + .join("\n"); + + let mut grid = Grid::parse(grid.as_str()); + + let mut robot = grid.entries().find(|(_r, c)| **c == '@').unwrap().0; + let directions = |d| match d { + '^' => (0, -1), + 'v' => (0, 1), + '<' => (-1, 0), + '>' => (1, 0), + _ => panic!(), + }; + for m in movements.chars().filter(|c| *c != '\n') { + let dir = directions(m); + if let Some(tiles_to_move) = movable(robot, dir, &grid, false) { + let old = tiles_to_move + .iter() + .map(|tile| (*tile, grid[*tile])) + .collect_vec(); + tiles_to_move.iter().for_each(|tile| grid[*tile] = '.'); + old.into_iter() + .for_each(|(tile, c)| grid[(tile.0 + dir.0, tile.1 + dir.1)] = c); + robot = (robot.0 + dir.0, robot.1 + dir.1); + } + } + grid.entries() + .filter(|(_, c)| **c == '[') + .map(|((x, y), _)| y * 100 + x) + .sum() +} + +fn movable( + from: (i64, i64), + dir: (i64, i64), + grid: &Grid, + ignore_other_half: bool, +) -> Option> { + match grid[from] { + '.' => Some(HashSet::new()), + '@' => { + let next = movable((from.0 + dir.0, from.1 + dir.1), dir, grid, false); + next.map(|mut v| { + v.insert(from); + v + }) + } + '[' => { + if dir.0 != 0 { + // sideway movement is "regular" + let next = movable((from.0 + dir.0, from.1 + dir.1), dir, grid, false); + next.map(|mut v| { + v.insert(from); + v + }) + } else { + // up/down always means the other part of the crate has to move in parallel + let mut next1 = movable((from.0 + dir.0, from.1 + dir.1), dir, grid, false)?; + if !ignore_other_half { + let next2 = movable((from.0 + 1, from.1), dir, grid, true)?; + next1.extend(next2); + } + next1.insert(from); + Some(next1) + } + } + ']' => { + if dir.0 != 0 { + // sideway movement is "regular" + let next = movable((from.0 + dir.0, from.1 + dir.1), dir, grid, false); + next.map(|mut v| { + v.insert(from); + v + }) + } else { + // up/down always means the other part of the crate has to move in parallel + let mut next1 = movable((from.0 + dir.0, from.1 + dir.1), dir, grid, false)?; + if !ignore_other_half { + let next2 = movable((from.0 - 1, from.1), dir, grid, true)?; + next1.extend(next2); + } + next1.insert(from); + Some(next1) + } + } + _ => None, + } } #[cfg(test)] @@ -63,6 +168,29 @@ mod test { <^^>>>vv>v<<"; + const TEST_LARGE: &str = r"########## +#..O..O.O# +#......O.# +#.OO..O.O# +#..O@..O.# +#O#..O...# +#O..O..O.# +#.OO.O.OO# +#....O...# +########## + +^v>^vv^v>v<>v^v<<><>>v^v^>^<<<><^ +vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<^<^^>>>^<>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^v^^<^^vv< +<>^^^^>>>v^<>vvv^>^^^vv^^>v<^^^^v<>^>vvvv><>>v^<<^^^^^ +^><^><>>><>^^<<^^v>>><^^>v>>>^v><>^v><<<>vvvv>^<><<>^>< +^>><>^v<><^vvv<^^<><^v<<<><<<^^<^>>^<<<^>>^v^>>^v>vv>^<<^v<>><<><<>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^ +<><^^>^^^<>^vv<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<> +^^>vv<^v^v^<>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<>< +v^^>>><<^^<>>^v^v^<<>^<^v^v><^<<<><<^vv>>v>v^<<^ +"; + #[test] fn test1() { assert_eq!(part1(TEST_INPUT), 2028); @@ -70,6 +198,6 @@ mod test { #[test] fn test2() { - assert_eq!(part2(TEST_INPUT), 0); + assert_eq!(part2(TEST_LARGE), 9021); } } diff --git a/src/utils/grid.rs b/src/utils/grid.rs index 0be35dd..2142c9a 100644 --- a/src/utils/grid.rs +++ b/src/utils/grid.rs @@ -130,6 +130,15 @@ impl Grid { content, } } + + pub fn print(&self) { + for line in &self.content.iter().chunks(self.content_width as usize) { + for c in line.into_iter() { + print!("{c}"); + } + println!(); + } + } } impl Index for Grid {