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;
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
enum Tile {
Wall,
Robot,
Box,
BoxL,
BoxR,
Empty,
}
use Tile::*;
@ -17,6 +19,8 @@ impl Display for Tile {
Wall => write!(f, "#"),
Robot => write!(f, "@"),
Box => write!(f, "O"),
BoxL => write!(f, "["),
BoxR => 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 {
let (map, directions) = input.split_once("\n\n").unwrap();
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]
}
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) {
let dir = state.directions.pop_front().unwrap().as_vec();
let pos_in_front = state.robot_pos + dir;
@ -120,42 +170,50 @@ fn do_move(state: &mut State) {
return;
}
let mut curr = pos_in_front;
while get_tile(&mut state.map, &curr) != &Wall && get_tile(&mut state.map, &curr) != &Empty {
curr += dir;
let mut to_move = Vec::new();
if can_be_moved(state, &state.robot_pos, &dir, &mut to_move) {
let mut new_map = state.map.clone();
for pos in &to_move {
*get_tile(&mut new_map, pos) = Empty;
}
for pos in &to_move {
*get_tile(&mut new_map, &(pos + dir)) = *get_tile(&mut state.map, pos);
}
state.map = new_map;
*get_tile(&mut state.map, &pos_in_front) = Robot;
*get_tile(&mut state.map, &state.robot_pos) = Empty;
state.robot_pos = pos_in_front;
}
if get_tile(&mut state.map, &curr) == &Wall {
return;
}
*get_tile(&mut state.map, &curr) = Box;
*get_tile(&mut state.map, &pos_in_front) = Robot;
*get_tile(&mut state.map, &state.robot_pos) = Empty;
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
.map
.iter()
.enumerate()
.flat_map(|(l_idx, l)| {
l.iter().enumerate().map(
move |(t_idx, t)| {
if t == &Box {
100 * l_idx + t_idx
} else {
0
}
},
)
l.iter().enumerate().map(move |(t_idx, t)| {
if t == &Box || t == &BoxL {
100 * l_idx + t_idx
} else {
0
}
})
})
.sum()
}
fn part12(state: &mut State) -> usize {
while !state.directions.is_empty() {
do_move(state);
}
get_gps_sum(state)
}
fn main() {
let mut input = parse(include_str!("../input.txt"));
println!("{}", part1(&mut input));
println!("{}", part12(&mut input.clone()));
input.widen();
println!("{}", part12(&mut input));
}