The most beatiful code ever

This commit is contained in:
Jan-Bulthuis 2024-12-15 07:35:57 +01:00
parent fdbbd934a4
commit 4ce7184b1e
2 changed files with 418 additions and 0 deletions

417
aoc_2024/src/day15.rs Normal file
View File

@ -0,0 +1,417 @@
use aoc_runner_derive::{aoc, aoc_generator};
use hashbrown::HashSet;
use nom::branch::alt;
use nom::character::complete::{multispace0, one_of};
use nom::combinator::map;
use nom::error::Error;
use nom::multi::many1;
use nom::sequence::preceded;
use nom::{character::complete::newline, multi::separated_list0, sequence::separated_pair};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Cell {
Wall,
Empty,
Box,
Sub,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Cell2 {
Wall,
Empty,
BoxLeft,
BoxRight,
Sub,
}
type Input = (Vec<Vec<Cell>>, Vec<(i32, i32)>);
#[aoc_generator(day15)]
fn parse(input: &str) -> Input {
separated_pair(
separated_list0(
newline::<&str, Error<&str>>,
many1(map(one_of("#.O@"), |c| match c {
'#' => Cell::Wall,
'.' => Cell::Empty,
'O' => Cell::Box,
'@' => Cell::Sub,
_ => panic!("Invalid cell"),
})),
),
multispace0,
many1(map(
alt((preceded(newline, one_of("^v<>")), one_of("^v<>"))),
|c| match c {
'^' => (0, -1),
'v' => (0, 1),
'<' => (-1, 0),
'>' => (1, 0),
_ => panic!("Invalid direction"),
},
)),
)(input)
.unwrap()
.1
}
#[aoc(day15, part1)]
fn part1(input: &Input) -> usize {
let mut map = input.0.clone();
let steps = input.1.clone();
let (mut x, mut y): (usize, usize) = map
.iter()
.enumerate()
.find_map(|(y, row)| {
row.iter().enumerate().find_map(|(x, cell)| match cell {
Cell::Sub => Some((x, y)),
_ => None,
})
})
.unwrap();
for step in steps {
let (dx, dy) = step;
let (nx, ny) = ((x as i32 + dx) as usize, (y as i32 + dy) as usize);
match map[ny][nx] {
Cell::Wall => continue,
Cell::Box => {
let (mut bx, mut by) = ((nx as i32 + dx) as usize, (ny as i32 + dy) as usize);
while map[by][bx] == Cell::Box {
(bx, by) = ((bx as i32 + dx) as usize, (by as i32 + dy) as usize);
}
match map[by][bx] {
Cell::Box => unreachable!(),
Cell::Sub => unreachable!(),
Cell::Empty => {
map[ny][nx] = Cell::Sub;
map[by][bx] = Cell::Box;
map[y][x] = Cell::Empty;
y = ny;
x = nx;
}
Cell::Wall => continue,
}
}
Cell::Empty => {
map[y][x] = Cell::Empty;
map[ny][nx] = Cell::Sub;
x = nx;
y = ny;
}
Cell::Sub => unreachable!(),
};
}
map.iter()
.enumerate()
.map(|(y, line)| {
line.iter()
.enumerate()
.map(|(x, cell)| match cell {
Cell::Box => x + 100 * y,
_ => 0,
})
.sum::<usize>()
})
.sum()
}
#[aoc(day15, part2)]
fn part2(input: &Input) -> usize {
let mut map = input
.0
.clone()
.iter()
.map(|line| {
line.iter()
.flat_map(|cell| match cell {
Cell::Wall => vec![Cell2::Wall, Cell2::Wall],
Cell::Empty => vec![Cell2::Empty, Cell2::Empty],
Cell::Box => vec![Cell2::BoxLeft, Cell2::BoxRight],
Cell::Sub => vec![Cell2::Sub, Cell2::Empty],
})
.collect()
})
.collect::<Vec<Vec<Cell2>>>();
let steps = input.1.clone();
let (mut x, mut y): (usize, usize) = map
.iter()
.enumerate()
.find_map(|(y, row)| {
row.iter().enumerate().find_map(|(x, cell)| match cell {
Cell2::Sub => Some((x, y)),
_ => None,
})
})
.unwrap();
// for line in &map {
// for cell in line {
// print!(
// "{}",
// match cell {
// Cell2::Wall => '#',
// Cell2::Empty => ' ',
// Cell2::BoxLeft => '[',
// Cell2::BoxRight => ']',
// Cell2::Sub => '@',
// }
// );
// }
// println!();
// }
for step in steps {
let (dx, dy) = step;
let (nx, ny) = ((x as i32 + dx) as usize, (y as i32 + dy) as usize);
match map[ny][nx] {
Cell2::Wall => continue,
Cell2::Empty => {
map[y][x] = Cell2::Empty;
map[ny][nx] = Cell2::Sub;
x = nx;
y = ny;
}
Cell2::Sub => unreachable!(),
Cell2::BoxLeft => {
if dy == 0 {
let (mut bx, mut by) = ((x as i32 + dx) as usize, (y as i32 + dy) as usize);
while map[by][bx] == Cell2::BoxLeft {
(bx, by) = ((bx as i32 + 2 * dx) as usize, (by as i32 + 2 * dy) as usize);
}
match map[by][bx] {
Cell2::BoxLeft | Cell2::BoxRight => unreachable!(),
Cell2::Sub => unreachable!(),
Cell2::Empty => {
for i in nx..bx {
map[y][bx + nx - i] = map[y][bx + nx - i - 1];
}
map[ny][nx] = Cell2::Sub;
map[y][x] = Cell2::Empty;
y = ny;
x = nx;
}
Cell2::Wall => continue,
}
} else {
let mut pushing = vec![(x, y)];
let mut pushed = HashSet::new();
let mut pushable = true;
while let Some(test) = pushing.pop() {
match map[(test.1 as i32 + dy) as usize][test.0] {
Cell2::Sub => unreachable!(),
Cell2::Wall => {
pushable = false;
break;
}
Cell2::Empty => {
pushed.insert(test);
}
Cell2::BoxLeft => {
pushed.insert(test);
pushing.push((test.0, (test.1 as i32 + dy) as usize));
pushing.push((test.0 + 1, (test.1 as i32 + dy) as usize));
}
Cell2::BoxRight => {
pushed.insert(test);
pushing.push((test.0, (test.1 as i32 + dy) as usize));
pushing.push((test.0 - 1, (test.1 as i32 + dy) as usize));
}
}
}
if !pushable {
continue;
} else {
let moved = pushed.clone();
let mut pushed = pushed.into_iter().collect::<Vec<(usize, usize)>>();
pushed.sort_by(|a, b| (b.1 as i32 * dy).cmp(&(a.1 as i32 * dy)));
pushed.into_iter().for_each(|(x, y)| {
map[(y as i32 + dy) as usize][x] = map[y][x];
if !moved.contains(&(x, (y as i32 - dy) as usize)) {
map[y][x] = Cell2::Empty;
}
});
y = ny;
x = nx;
}
}
}
Cell2::BoxRight => {
if dy == 0 {
let (mut bx, mut by) = ((x as i32 + dx) as usize, (y as i32 + dy) as usize);
while map[by][bx] == Cell2::BoxRight {
(bx, by) = ((bx as i32 + 2 * dx) as usize, (by as i32 + 2 * dy) as usize);
}
match map[by][bx] {
Cell2::BoxLeft | Cell2::BoxRight => unreachable!(),
Cell2::Sub => unreachable!(),
Cell2::Empty => {
for i in bx..nx {
map[y][i] = map[y][i + 1];
}
map[ny][nx] = Cell2::Sub;
map[y][x] = Cell2::Empty;
y = ny;
x = nx;
}
Cell2::Wall => continue,
}
} else {
let mut pushing = vec![(x, y)];
let mut pushed = HashSet::new();
let mut pushable = true;
while let Some(test) = pushing.pop() {
match map[(test.1 as i32 + dy) as usize][test.0] {
Cell2::Sub => unreachable!(),
Cell2::Wall => {
pushable = false;
break;
}
Cell2::Empty => {
pushed.insert(test);
}
Cell2::BoxLeft => {
pushed.insert(test);
pushing.push((test.0, (test.1 as i32 + dy) as usize));
pushing.push((test.0 + 1, (test.1 as i32 + dy) as usize));
}
Cell2::BoxRight => {
pushed.insert(test);
pushing.push((test.0, (test.1 as i32 + dy) as usize));
pushing.push((test.0 - 1, (test.1 as i32 + dy) as usize));
}
}
}
if !pushable {
continue;
} else {
let moved = pushed.clone();
let mut pushed = pushed.into_iter().collect::<Vec<(usize, usize)>>();
pushed.sort_by(|a, b| (b.1 as i32 * dy).cmp(&(a.1 as i32 * dy)));
pushed.into_iter().for_each(|(x, y)| {
map[(y as i32 + dy) as usize][x] = map[y][x];
if !moved.contains(&(x, (y as i32 - dy) as usize)) {
map[y][x] = Cell2::Empty;
}
});
y = ny;
x = nx;
}
}
}
};
// println!("\nStep: {:?}", step);
// for line in &map {
// for cell in line {
// print!(
// "{}",
// match cell {
// Cell2::Wall => '#',
// Cell2::Empty => ' ',
// Cell2::BoxLeft => '[',
// Cell2::BoxRight => ']',
// Cell2::Sub => '@',
// }
// );
// }
// println!();
// }
}
map.iter()
.enumerate()
.map(|(y, line)| {
line.iter()
.enumerate()
.map(|(x, cell)| match cell {
Cell2::BoxLeft => x + 100 * y,
_ => 0,
})
.sum::<usize>()
})
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example() {
assert_eq!(
part1(&parse(
"########
#..O.O.#
##@.O..#
#...O..#
#.#.O..#
#...O..#
#......#
########
<^^>>>vv<v>>v<<"
)),
2028
);
assert_eq!(
part1(&parse(
"##########
#..O..O.O#
#......O.#
#.OO..O.O#
#..O@..O.#
#O#..O...#
#O..O..O.#
#.OO.O.OO#
#....O...#
##########
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>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^<<^"
)),
10092
);
}
#[test]
fn part2_example() {
assert_eq!(
part2(&parse(
"##########
#..O..O.O#
#......O.#
#.OO..O.O#
#..O@..O.#
#O#..O...#
#O..O..O.#
#.OO.O.OO#
#....O...#
##########
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>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^<<^"
)),
9021
);
}
}

View File

@ -4,6 +4,7 @@ mod day11;
mod day12; mod day12;
mod day13; mod day13;
mod day14; mod day14;
mod day15;
mod day2; mod day2;
mod day3; mod day3;
mod day4; mod day4;