day15: cleanup & use the same implementation for both parts
Some checks failed
test / AoC 2024 (push) Failing after 2m17s

This commit is contained in:
Keenan Tims 2024-12-15 00:55:59 -08:00
parent c2c0145219
commit 411d6aa26d
Signed by: ktims
GPG Key ID: 11230674D69038D4

View File

@ -1,14 +1,7 @@
use std::{
cmp,
fmt::Display,
io::{BufRead, Cursor, Lines},
iter,
str::FromStr,
};
use aoc_runner_derive::aoc; use aoc_runner_derive::aoc;
use grid::{AsCoord2d, Coord2d, Grid}; use grid::{AsCoord2d, Coord2d, Grid};
use itertools::{rev, Itertools}; use itertools::Itertools;
use std::{fmt::Display, io::Cursor, str::FromStr};
struct Warehouse { struct Warehouse {
map: Grid<u8>, map: Grid<u8>,
@ -22,118 +15,7 @@ impl Display for Warehouse {
} }
impl Warehouse { impl Warehouse {
fn step_robot(&mut self, m: Move) { fn step_robot(&mut self, dir: Move) {
match m {
Move::Left => {
let to_left = &self.map.row(self.robot_pos.y()).unwrap()[0..self.robot_pos.x() as usize];
let left_chunks = to_left
.chunk_by(|a, b| a == b || (*a == b'[' && *b == b']'))
.collect_vec();
match left_chunks.last().unwrap().last().unwrap() {
b'.' => {
self.map
.swap(&self.robot_pos, (self.robot_pos.x() - 1, self.robot_pos.y()));
self.robot_pos.x -= 1
}
b'O' | b'[' | b']' => {
if left_chunks[left_chunks.len() - 2].last().unwrap() == &b'.' {
let y = self.robot_pos.y();
// swap the whole chunk left
for x_target in self.robot_pos.x() - left_chunks.last().unwrap().len() as i64
..=self.robot_pos.x() as i64
{
self.map.swap((x_target, y), (x_target - 1, y));
}
self.robot_pos.x -= 1;
}
}
b'#' => {}
c => panic!("unexpected char {}", c),
}
}
Move::Right => {
let to_right =
&self.map.row(self.robot_pos.y()).unwrap()[self.robot_pos.x() as usize + 1..self.map.width()];
let right_chunks = to_right
.chunk_by(|a, b| a == b || (*a == b'[' && *b == b']'))
.collect_vec();
match right_chunks[0][0] {
b'.' => {
self.map
.swap(&self.robot_pos, (self.robot_pos.x() + 1, self.robot_pos.y()));
self.robot_pos.x += 1
}
b'O' | b'[' | b']' => {
if right_chunks[1][0] == b'.' {
let y = self.robot_pos.y();
// swap the whole chunk right
for x_target in
(self.robot_pos.x() + 1..=self.robot_pos.x() + 1 + right_chunks[0].len() as i64).rev()
{
self.map.swap((x_target, y), (x_target - 1, y));
}
self.robot_pos.x += 1;
}
}
b'#' => {}
c => panic!("unexpected char {}", c),
}
}
Move::Up => {
let to_up = &self.map.col(self.robot_pos.x()).unwrap()[0..self.robot_pos.y() as usize];
let up_chunks = to_up.chunk_by(|a, b| a == b).collect_vec();
match up_chunks.last().unwrap().last().unwrap() {
b'.' => {
self.map
.swap(&self.robot_pos, (self.robot_pos.x(), self.robot_pos.y() - 1));
self.robot_pos.y -= 1
}
b'O' => {
if **up_chunks[up_chunks.len() - 2].last().unwrap() == b'.' {
let x = self.robot_pos.x();
// swap the whole chunk left
for y_target in
self.robot_pos.y() - up_chunks.last().unwrap().len() as i64..=self.robot_pos.y() as i64
{
self.map.swap((x, y_target), (x, y_target - 1));
}
self.robot_pos.y -= 1;
}
}
b'#' => {}
c => panic!("unexpected char {}", c),
}
}
Move::Down => {
let to_down =
&self.map.col(self.robot_pos.x()).unwrap()[self.robot_pos.y() as usize + 1..self.map.height()];
let down_chunks = to_down.chunk_by(|a, b| a == b).collect_vec();
match down_chunks[0][0] {
b'.' => {
self.map
.swap(&self.robot_pos, (self.robot_pos.x(), self.robot_pos.y() + 1));
self.robot_pos.y += 1;
}
b'O' => {
if *down_chunks[1][0] == b'.' {
let x = self.robot_pos.x();
// swap the whole chunk down
for y_target in
(self.robot_pos.y() + 1..=self.robot_pos.y() + 1 + down_chunks[0].len() as i64).rev()
{
self.map.swap((x, y_target), (x, y_target - 1));
}
self.robot_pos.y += 1;
}
}
b'#' => {}
c => panic!("unexpected char {}", c),
}
}
}
}
fn step_robot_2(&mut self, dir: Move) {
let start = self.robot_pos.clone(); let start = self.robot_pos.clone();
if self.push(&start, &dir) { if self.push(&start, &dir) {
self.robot_pos = match dir { self.robot_pos = match dir {
@ -151,6 +33,10 @@ impl Warehouse {
match self.map.get(&target).unwrap() { match self.map.get(&target).unwrap() {
b'#' => {} b'#' => {}
b'.' => self.map.swap(target, pos), b'.' => self.map.swap(target, pos),
b'O' => {
self.push(&target, dir);
self.map.swap(target, pos);
}
b'[' | b']' if *dir == Move::Left || *dir == Move::Right => { b'[' | b']' if *dir == Move::Left || *dir == Move::Right => {
self.push(&target, dir); self.push(&target, dir);
self.map.swap(target, pos) self.map.swap(target, pos)
@ -204,6 +90,16 @@ impl Warehouse {
self.map = Grid::from(Cursor::new(new_lines.as_str())); self.map = Grid::from(Cursor::new(new_lines.as_str()));
self.robot_pos = self.map.find(&b'@').unwrap().to_coord(); self.robot_pos = self.map.find(&b'@').unwrap().to_coord();
} }
fn score(&self) -> i64 {
self.map
.data
.iter()
.enumerate()
.filter(|(_, v)| **v == b'O' || **v == b'[')
.map(|(i, _)| self.map.coord(i as i64).unwrap().y() * 100 + self.map.coord(i as i64).unwrap().x())
.sum()
}
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -254,9 +150,7 @@ struct MovePlan(Vec<Move>);
impl FromStr for MovePlan { impl FromStr for MovePlan {
type Err = Box<dyn std::error::Error>; type Err = Box<dyn std::error::Error>;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(MovePlan( Ok(MovePlan(s.chars().filter(|c| *c != '\n').map(Move::from).collect()))
s.chars().filter(|c| *c != '\n').map(|c| Move::from(c)).collect(),
))
} }
} }
@ -276,19 +170,10 @@ fn parse(input: &str) -> (Warehouse, MovePlan) {
#[aoc(day15, part1)] #[aoc(day15, part1)]
pub fn part1(input: &str) -> i64 { pub fn part1(input: &str) -> i64 {
let (mut wh, moves) = parse(input); let (mut wh, moves) = parse(input);
// println!("map:\n {}\nmoves: {:?}", wh, moves);
for m in moves.0 { for m in moves.0 {
// println!("{}", m);
wh.step_robot(m); wh.step_robot(m);
// println!("{}", wh);
} }
wh.map wh.score()
.data
.iter()
.enumerate()
.filter(|(i, v)| **v == b'O')
.map(|(i, _)| wh.map.coord(i as i64).unwrap().y() * 100 + wh.map.coord(i as i64).unwrap().x())
.sum()
} }
#[aoc(day15, part2)] #[aoc(day15, part2)]
@ -296,21 +181,10 @@ pub fn part2(input: &str) -> i64 {
let (mut wh, moves) = parse(input); let (mut wh, moves) = parse(input);
wh.embiggen(); wh.embiggen();
println!("{}", wh);
for m in moves.0 { for m in moves.0 {
// println!("{}", m); wh.step_robot(m);
wh.step_robot_2(m);
// println!("{}", wh);
} }
println!("{}", wh); wh.score()
let mut sum = 0;
wh.map
.data
.iter()
.enumerate()
.filter(|(i, v)| **v == b'[')
.map(|(i, _)| wh.map.coord(i as i64).unwrap().y() * 100 + wh.map.coord(i as i64).unwrap().x())
.sum()
} }
#[cfg(test)] #[cfg(test)]