day15: cleanup & use the same implementation for both parts
Some checks failed
test / AoC 2024 (push) Failing after 2m17s
Some checks failed
test / AoC 2024 (push) Failing after 2m17s
This commit is contained in:
parent
c2c0145219
commit
411d6aa26d
168
src/day15.rs
168
src/day15.rs
@ -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)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user