The most beatiful code ever
This commit is contained in:
parent
fdbbd934a4
commit
4ce7184b1e
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue