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 day13;
|
||||
mod day14;
|
||||
mod day15;
|
||||
mod day2;
|
||||
mod day3;
|
||||
mod day4;
|
||||
|
|
Loading…
Reference in New Issue