Add day15 part2

This commit is contained in:
Adrian Groh 2024-12-15 14:03:00 +01:00
parent b813526dfe
commit 35c3e99fbc
Signed by: Gobidev
GPG Key ID: 3AA3153E98B0D771

View File

@ -2,11 +2,13 @@ use std::{collections::VecDeque, fmt::Display};
use glam::IVec2; use glam::IVec2;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Copy)]
enum Tile { enum Tile {
Wall, Wall,
Robot, Robot,
Box, Box,
BoxL,
BoxR,
Empty, Empty,
} }
use Tile::*; use Tile::*;
@ -17,6 +19,8 @@ impl Display for Tile {
Wall => write!(f, "#"), Wall => write!(f, "#"),
Robot => write!(f, "@"), Robot => write!(f, "@"),
Box => write!(f, "O"), Box => write!(f, "O"),
BoxL => write!(f, "["),
BoxR => write!(f, "]"),
Empty => write!(f, "."), Empty => write!(f, "."),
} }
} }
@ -62,6 +66,27 @@ impl Display for State {
} }
} }
impl State {
fn widen(&mut self) {
self.map = self
.map
.iter()
.map(|l| {
l.iter()
.flat_map(|t| match t {
Empty => [Empty, Empty],
Wall => [Wall, Wall],
Box => [BoxL, BoxR],
Robot => [Robot, Empty],
e => [*e, *e],
})
.collect()
})
.collect();
self.robot_pos *= IVec2::new(1, 2);
}
}
fn parse(input: &str) -> State { fn parse(input: &str) -> State {
let (map, directions) = input.split_once("\n\n").unwrap(); let (map, directions) = input.split_once("\n\n").unwrap();
let mut robot_pos = IVec2::new(0, 0); let mut robot_pos = IVec2::new(0, 0);
@ -105,6 +130,31 @@ fn get_tile<'a>(map: &'a mut [Vec<Tile>], idx: &IVec2) -> &'a mut Tile {
&mut map[idx.x as usize][idx.y as usize] &mut map[idx.x as usize][idx.y as usize]
} }
fn can_be_moved(state: &State, pos: &IVec2, direction: &IVec2, to_move: &mut Vec<IVec2>) -> bool {
let tile_in_front = state.map[(pos + direction).x as usize][(pos + direction).y as usize];
if tile_in_front == Wall {
return false;
}
if tile_in_front == Empty {
return true;
}
let to_check_dir = match tile_in_front {
BoxL => Right.as_vec(),
BoxR => Left.as_vec(),
_ => IVec2::new(0, 0),
};
if direction == &Up.as_vec() || direction == &Down.as_vec() {
to_move.push(pos + direction);
to_move.push(pos + direction + to_check_dir);
return can_be_moved(state, &(pos + direction), direction, to_move)
&& can_be_moved(state, &(pos + direction + to_check_dir), direction, to_move);
}
to_move.push(pos + direction);
can_be_moved(state, &(pos + direction), direction, to_move)
}
fn do_move(state: &mut State) { fn do_move(state: &mut State) {
let dir = state.directions.pop_front().unwrap().as_vec(); let dir = state.directions.pop_front().unwrap().as_vec();
let pos_in_front = state.robot_pos + dir; let pos_in_front = state.robot_pos + dir;
@ -120,42 +170,50 @@ fn do_move(state: &mut State) {
return; return;
} }
let mut curr = pos_in_front; let mut to_move = Vec::new();
while get_tile(&mut state.map, &curr) != &Wall && get_tile(&mut state.map, &curr) != &Empty { if can_be_moved(state, &state.robot_pos, &dir, &mut to_move) {
curr += dir; let mut new_map = state.map.clone();
for pos in &to_move {
*get_tile(&mut new_map, pos) = Empty;
} }
if get_tile(&mut state.map, &curr) == &Wall {
return; for pos in &to_move {
*get_tile(&mut new_map, &(pos + dir)) = *get_tile(&mut state.map, pos);
} }
*get_tile(&mut state.map, &curr) = Box; state.map = new_map;
*get_tile(&mut state.map, &pos_in_front) = Robot; *get_tile(&mut state.map, &pos_in_front) = Robot;
*get_tile(&mut state.map, &state.robot_pos) = Empty; *get_tile(&mut state.map, &state.robot_pos) = Empty;
state.robot_pos = pos_in_front; state.robot_pos = pos_in_front;
} }
fn part1(state: &mut State) -> usize {
while !state.directions.is_empty() {
do_move(state);
} }
fn get_gps_sum(state: &State) -> usize {
state state
.map .map
.iter() .iter()
.enumerate() .enumerate()
.flat_map(|(l_idx, l)| { .flat_map(|(l_idx, l)| {
l.iter().enumerate().map( l.iter().enumerate().map(move |(t_idx, t)| {
move |(t_idx, t)| { if t == &Box || t == &BoxL {
if t == &Box {
100 * l_idx + t_idx 100 * l_idx + t_idx
} else { } else {
0 0
} }
}, })
)
}) })
.sum() .sum()
} }
fn part12(state: &mut State) -> usize {
while !state.directions.is_empty() {
do_move(state);
}
get_gps_sum(state)
}
fn main() { fn main() {
let mut input = parse(include_str!("../input.txt")); let mut input = parse(include_str!("../input.txt"));
println!("{}", part1(&mut input)); println!("{}", part12(&mut input.clone()));
input.widen();
println!("{}", part12(&mut input));
} }