This commit is contained in:
Fabian Schmidt 2024-12-16 10:11:47 +01:00
parent 86c52a1a59
commit 312460ffa5

View File

@ -3,17 +3,54 @@ use std::error::Error;
use itertools::Itertools; use itertools::Itertools;
pub fn process_part1(input: &str) -> u32 { pub fn process_part1(input: &str) -> u32 {
let (grid, movements) = input.split_once("\n").unwrap(); let (grid, movements) = input.split_once("\n\n").unwrap();
let grid = parse_grid(grid); let (mut grid, mut robot) = parse_grid(grid);
let movements = parse_movements(movements); let movements = parse_movements(movements);
for movement in movements {} for movement in movements {
match movement {
Movement::Up => move_up(&mut robot, &mut grid),
Movement::Down => move_down(&mut robot, &mut grid),
Movement::Left => move_left(&mut robot, &mut grid),
Movement::Right => move_right(&mut robot, &mut grid),
}
}
log_grid(grid.clone());
grid.concat().iter().map(|tile| tile.get_gps()).sum()
} }
pub fn process_part2(input: &str) -> u32 { pub fn process_part2(input: &str) -> u32 {
0 let (grid, movements) = input.split_once("\n\n").unwrap();
let (mut grid, mut robot) = parse_large_grid(grid);
let movements = parse_movements(movements);
for movement in movements {
match movement {
Movement::Up => move_up_large(&mut robot, &mut grid),
Movement::Down => move_down_large(&mut robot, &mut grid),
Movement::Left => move_left_large(&mut robot, &mut grid),
Movement::Right => move_right_large(&mut robot, &mut grid),
}
}
log_grid(grid.clone());
grid.concat().iter().map(|tile| tile.get_gps()).sum()
} }
fn parse_grid(input: &str) -> Vec<Vec<GridTile>> { fn log_grid(grid: Vec<Vec<GridTile>>) {
for row in grid {
for tile in row {
match tile.entity {
GridTileType::Robot => print!("@"),
GridTileType::Crate => print!("O"),
GridTileType::Wall => print!("#"),
GridTileType::Nothing => print!("."),
GridTileType::BigCrateLeft => print!("["),
GridTileType::BigCrateRight => print!("]"),
}
}
println!();
}
}
fn parse_large_grid(input: &str) -> (Vec<Vec<GridTile>>, GridTile) {
let mut grid_entities = Vec::new(); let mut grid_entities = Vec::new();
let mut robot = GridTile { let mut robot = GridTile {
entity: GridTileType::Robot, entity: GridTileType::Robot,
@ -23,12 +60,79 @@ fn parse_grid(input: &str) -> Vec<Vec<GridTile>> {
let mut row_entities = Vec::new(); let mut row_entities = Vec::new();
line.chars().enumerate().for_each(|(xidx, chara)| { line.chars().enumerate().for_each(|(xidx, chara)| {
if let Ok(entity) = GridTileType::from_character(chara) { if let Ok(entity) = GridTileType::from_character(chara) {
match entity {} match entity {
GridTileType::Robot => {
robot.coords = (xidx as u32 * 2, yidx as u32);
row_entities.push(robot);
row_entities.push(GridTile::default());
}
GridTileType::Crate => {
let entity = GridTile {
entity: GridTileType::BigCrateLeft,
coords: (xidx as u32 * 2, yidx as u32),
};
row_entities.push(entity);
let entity = GridTile {
entity: GridTileType::BigCrateRight,
coords: (xidx as u32 * 2 + 1, yidx as u32),
};
row_entities.push(entity);
}
GridTileType::Wall => {
let entity = GridTile {
entity,
coords: (xidx as u32 * 2, yidx as u32),
};
row_entities.push(entity);
let entity = GridTile {
entity: GridTileType::Wall,
coords: (xidx as u32 * 2 + 1, yidx as u32),
};
row_entities.push(entity);
}
GridTileType::Nothing => {
row_entities.push(GridTile::default());
row_entities.push(GridTile::default());
}
GridTileType::BigCrateLeft | GridTileType::BigCrateRight => (),
}
} }
}); });
grid_entities.push(row_entities); grid_entities.push(row_entities);
}); });
grid_entities (grid_entities, robot)
}
fn parse_grid(input: &str) -> (Vec<Vec<GridTile>>, GridTile) {
let mut grid_entities = Vec::new();
let mut robot = GridTile {
entity: GridTileType::Robot,
..Default::default()
};
input.lines().enumerate().for_each(|(yidx, line)| {
let mut row_entities = Vec::new();
line.chars().enumerate().for_each(|(xidx, chara)| {
if let Ok(entity) = GridTileType::from_character(chara) {
match entity {
GridTileType::Robot => {
robot.coords = (xidx as u32, yidx as u32);
row_entities.push(robot);
}
GridTileType::Crate | GridTileType::Wall => {
let entity = GridTile {
entity,
coords: (xidx as u32, yidx as u32),
};
row_entities.push(entity);
}
GridTileType::Nothing => row_entities.push(GridTile::default()),
GridTileType::BigCrateLeft | GridTileType::BigCrateRight => (),
}
}
});
grid_entities.push(row_entities);
});
(grid_entities, robot)
} }
fn parse_movements(input: &str) -> Vec<Movement> { fn parse_movements(input: &str) -> Vec<Movement> {
@ -42,18 +146,277 @@ fn parse_movements(input: &str) -> Vec<Movement> {
.concat() .concat()
} }
fn move_up(robot: &mut GridTile, grid: &mut Vec<Vec<GridTile>>) {} fn move_up(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let (robot_x, robot_y) = robot.coords;
let mut moving_tiles = Vec::new();
for above in (0..robot_y).rev() {
let tile = grid[above as usize][robot_x as usize];
match tile.entity {
GridTileType::Robot => (),
GridTileType::Crate => moving_tiles.push(tile),
GridTileType::Wall => return,
GridTileType::Nothing => break,
GridTileType::BigCrateLeft | GridTileType::BigCrateRight => (),
}
}
for tile in moving_tiles.iter_mut() {
tile.coords.1 -= 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.1 -= 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
fn move_down(robot: &mut GridTile, grid: &mut Vec<Vec<GridTile>>) {} fn move_down(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let (robot_x, robot_y) = robot.coords;
let height = grid.len();
let mut moving_tiles = Vec::new();
for below in robot_y..height as u32 {
let tile = grid[below as usize][robot_x as usize];
match tile.entity {
GridTileType::Robot => (),
GridTileType::Crate => moving_tiles.push(tile),
GridTileType::Wall => return,
GridTileType::Nothing => break,
GridTileType::BigCrateLeft | GridTileType::BigCrateRight => (),
}
}
for tile in moving_tiles.iter_mut() {
tile.coords.1 += 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.1 += 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
fn move_left(robot: &mut GridTile, grid: &mut Vec<Vec<GridTile>>) {} fn move_left(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let (robot_x, robot_y) = robot.coords;
let mut moving_tiles = Vec::new();
for left in (0..robot_x).rev() {
let tile = grid[robot_y as usize][left as usize];
match tile.entity {
GridTileType::Robot => (),
GridTileType::Crate => moving_tiles.push(tile),
GridTileType::Wall => return,
GridTileType::Nothing => break,
GridTileType::BigCrateLeft | GridTileType::BigCrateRight => (),
}
}
for tile in moving_tiles.iter_mut() {
tile.coords.0 -= 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.0 -= 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
fn move_right(robot: &mut GridTile, grid: &mut Vec<Vec<GridTile>>) {} fn move_right(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let (robot_x, robot_y) = robot.coords;
let mut moving_tiles = Vec::new();
let width = grid[0].len();
for right in robot_x..width as u32 {
let tile = grid[robot_y as usize][right as usize];
match tile.entity {
GridTileType::Robot => (),
GridTileType::Crate => moving_tiles.push(tile),
GridTileType::Wall => return,
GridTileType::Nothing => break,
GridTileType::BigCrateLeft | GridTileType::BigCrateRight => (),
}
}
for tile in moving_tiles.iter_mut() {
tile.coords.0 += 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.0 += 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
fn get_above(tile: &GridTile, grid: &[Vec<GridTile>]) -> Vec<GridTile> {
let (tile_x, tile_y) = tile.coords;
let mut above_tiles = Vec::new();
let above = grid[tile_y as usize - 1][tile_x as usize];
match above.entity {
GridTileType::Robot => (),
GridTileType::Crate => {
above_tiles.push(above);
above_tiles.extend_from_slice(&get_above(&above, grid));
}
GridTileType::BigCrateLeft => {
above_tiles.push(above);
let right = grid[above.coords.1 as usize][above.coords.0 as usize + 1];
above_tiles.push(above);
above_tiles.push(right);
above_tiles.extend_from_slice(&get_above(&above, grid));
above_tiles.extend_from_slice(&get_above(&right, grid));
}
GridTileType::BigCrateRight => {
above_tiles.push(above);
let left = grid[above.coords.1 as usize][above.coords.0 as usize - 1];
above_tiles.push(above);
above_tiles.push(left);
above_tiles.extend_from_slice(&get_above(&above, grid));
above_tiles.extend_from_slice(&get_above(&left, grid));
}
GridTileType::Wall => above_tiles.push(above),
GridTileType::Nothing => (),
}
above_tiles
}
fn get_below(tile: &GridTile, grid: &[Vec<GridTile>]) -> Vec<GridTile> {
let (tile_x, tile_y) = tile.coords;
let mut below_tiles = Vec::new();
let below = grid[tile_y as usize + 1][tile_x as usize];
match below.entity {
GridTileType::Robot => (),
GridTileType::Crate => {
below_tiles.push(below);
below_tiles.extend_from_slice(&get_below(&below, grid));
}
GridTileType::BigCrateLeft => {
below_tiles.push(below);
let right = grid[below.coords.1 as usize][below.coords.0 as usize + 1];
below_tiles.push(below);
below_tiles.push(right);
below_tiles.extend_from_slice(&get_below(&below, grid));
below_tiles.extend_from_slice(&get_below(&right, grid));
}
GridTileType::BigCrateRight => {
below_tiles.push(below);
let left = grid[below.coords.1 as usize][below.coords.0 as usize - 1];
below_tiles.push(below);
below_tiles.push(left);
below_tiles.extend_from_slice(&get_below(&below, grid));
below_tiles.extend_from_slice(&get_below(&left, grid));
}
GridTileType::Wall => below_tiles.push(below),
GridTileType::Nothing => (),
}
below_tiles
}
fn get_left(tile: &GridTile, grid: &[Vec<GridTile>]) -> Vec<GridTile> {
let (tile_x, tile_y) = tile.coords;
let mut left_tiles = Vec::new();
let left = grid[tile_y as usize][tile_x as usize - 1];
match left.entity {
GridTileType::Robot => (),
GridTileType::Crate | GridTileType::BigCrateLeft | GridTileType::BigCrateRight => {
left_tiles.push(left);
left_tiles.extend_from_slice(&get_left(&left, grid));
}
GridTileType::Wall => left_tiles.push(left),
GridTileType::Nothing => (),
}
left_tiles
}
fn get_right(tile: &GridTile, grid: &[Vec<GridTile>]) -> Vec<GridTile> {
let (tile_x, tile_y) = tile.coords;
let mut right_tiles = Vec::new();
let right = grid[tile_y as usize][tile_x as usize + 1];
match right.entity {
GridTileType::Robot => (),
GridTileType::Crate | GridTileType::BigCrateLeft | GridTileType::BigCrateRight => {
right_tiles.push(right);
right_tiles.extend_from_slice(&get_right(&right, grid));
}
GridTileType::Wall => right_tiles.push(right),
GridTileType::Nothing => (),
}
right_tiles
}
fn move_up_large(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let mut moving_tiles = get_above(robot, grid);
if moving_tiles
.iter()
.map(|tile| tile.entity)
.contains(&GridTileType::Wall)
{
return;
}
moving_tiles.sort_by(|tile_a, tile_b| tile_a.coords.1.cmp(&tile_b.coords.1));
for tile in moving_tiles.iter_mut() {
grid[tile.coords.1 as usize][tile.coords.0 as usize] = GridTile::default();
tile.coords.1 -= 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.1 -= 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
fn move_down_large(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let mut moving_tiles = get_below(robot, grid);
if moving_tiles
.iter()
.map(|tile| tile.entity)
.contains(&GridTileType::Wall)
{
return;
}
moving_tiles.sort_by(|tile_a, tile_b| tile_b.coords.1.cmp(&tile_a.coords.1));
for tile in moving_tiles.iter_mut() {
grid[tile.coords.1 as usize][tile.coords.0 as usize] = GridTile::default();
tile.coords.1 += 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.1 += 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
fn move_left_large(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let mut moving_tiles = get_left(robot, grid);
if moving_tiles
.iter()
.map(|tile| tile.entity)
.contains(&GridTileType::Wall)
{
return;
}
for tile in moving_tiles.iter_mut() {
tile.coords.0 -= 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.0 -= 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
fn move_right_large(robot: &mut GridTile, grid: &mut [Vec<GridTile>]) {
let mut moving_tiles = get_right(robot, grid);
if moving_tiles
.iter()
.map(|tile| tile.entity)
.contains(&GridTileType::Wall)
{
return;
}
for tile in moving_tiles.iter_mut() {
tile.coords.0 += 1;
grid[tile.coords.1 as usize][tile.coords.0 as usize] = *tile;
}
grid[robot.coords.1 as usize][robot.coords.0 as usize] = GridTile::default();
robot.coords.0 += 1;
grid[robot.coords.1 as usize][robot.coords.0 as usize] = *robot;
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum GridTileType { enum GridTileType {
Robot, Robot,
Crate, Crate,
BigCrateLeft,
BigCrateRight,
Wall, Wall,
#[default] #[default]
Nothing, Nothing,
@ -79,7 +442,7 @@ struct GridTile {
impl GridTile { impl GridTile {
fn get_gps(&self) -> u32 { fn get_gps(&self) -> u32 {
if self.entity == GridTileType::Crate { if self.entity == GridTileType::Crate || self.entity == GridTileType::BigCrateLeft {
self.coords.0 + self.coords.1 * 100 self.coords.0 + self.coords.1 * 100
} else { } else {
0 0
@ -150,9 +513,25 @@ vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v> ^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^"; v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^";
const INPUT_LARGE_BOX_SIMPLE: &str = "#####
#..O.
#....";
const INPUT_LARGE_BOX_FULL: &str = "#######
#...#.#
#.....#
#..OO@#
#..O..#
#.....#
#######
<vv<<^^<<^^";
#[test] #[test]
fn part1_small() { fn part1_small() {
let result = process_part1(INPUT_SMALL); let (grid, _) = parse_grid(INPUT_SMALL);
let flat_grid = grid.concat();
let result: u32 = flat_grid.iter().map(|tile| tile.get_gps()).sum();
assert_eq!(result, 104); assert_eq!(result, 104);
} }
@ -169,8 +548,22 @@ v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^";
} }
#[test] #[test]
fn part2() { fn part2_simple() {
let result = process_part2(INPUT_SMALL); let (grid, _) = parse_large_grid(INPUT_LARGE_BOX_SIMPLE);
assert_eq!(result, 0); let flat_grid = grid.concat();
let result: u32 = flat_grid.iter().map(|tile| tile.get_gps()).sum();
assert_eq!(result, 106);
}
#[test]
fn part2_full() {
let result = process_part2(INPUT_LARGE_BOX_FULL);
assert_eq!(result, 618);
}
#[test]
fn part2_large() {
let result = process_part2(INPUT_LARGE);
assert_eq!(result, 9021);
} }
} }