Skip to content

Commit

Permalink
2024 day 20
Browse files Browse the repository at this point in the history
  • Loading branch information
ictrobot committed Dec 20, 2024
1 parent 8d992a9 commit 8c783a7
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 0 deletions.
132 changes: 132 additions & 0 deletions crates/year2024/src/day20.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use std::collections::VecDeque;
use utils::grid;
use utils::prelude::*;

/// Finding shortcuts phasing through walls in a maze.
#[derive(Clone, Debug)]
pub struct Day20 {
grid: Vec<u8>,
distances: Vec<u32>,
cols: usize,
}

impl Day20 {
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
let (_, cols, mut grid) = grid::from_str_padded(input, 20, b'#', |b| match b {
b'.' | b'#' | b'S' | b'E' => Some(b),
_ => None,
})?;

let mut starts = grid.iter().enumerate().filter(|(_, &b)| b == b'S');
let Some((start, _)) = starts.next() else {
return Err(InputError::new(input, 0, "expected one start"));
};
if starts.count() > 0 {
return Err(InputError::new(input, 0, "expected one start"));
}
grid[start] = b'.';

let mut ends = grid.iter().enumerate().filter(|(_, &b)| b == b'E');
let Some((end, _)) = ends.next() else {
return Err(InputError::new(input, 0, "expected one end"));
};
if ends.count() > 0 {
return Err(InputError::new(input, 0, "expected one end"));
}
grid[end] = b'.';

let mut distances = vec![u32::MAX; grid.len()];
distances[start] = 0;
let mut queue = VecDeque::new();
queue.push_back((start, 0));
while let Some((index, distance)) = queue.pop_front() {
if index == end {
break;
}

for offset in [1, cols as isize, -1, -(cols as isize)] {
let next = index.wrapping_add_signed(offset);
if grid[next] == b'.' && distances[next] == u32::MAX {
distances[next] = distance + 1;
queue.push_back((next, distance + 1));
}
}
}

Ok(Self {
grid,
distances,
cols,
})
}

#[must_use]
pub fn part1(&self) -> u32 {
let mut cheats = 0;
for index in (self.cols * 20)..self.grid.len() - (self.cols * 20) {
let this_distance = self.distances[index];
if this_distance == u32::MAX {
continue;
}

for offset in [1, self.cols as isize, -1, -(self.cols as isize)] {
if self.grid[index.wrapping_add_signed(offset)] != b'#' {
continue;
}

let Some(next) = index.checked_add_signed(offset * 2) else {
continue;
};
let Some(&target_distance) = self.distances.get(next) else {
continue;
};
if target_distance == u32::MAX || target_distance < this_distance + 2 {
continue;
}
let diff = target_distance - this_distance - 2;
if diff >= 100 {
cheats += 1;
}
}
}
cheats
}

#[must_use]
pub fn part2(&self) -> u32 {
let mut cheats = 0;
for index in (self.cols * 20)..self.grid.len() - (self.cols * 20) {
let this_distance = self.distances[index];
if this_distance == u32::MAX {
continue;
}

for x_offset in -20isize..=20 {
let y_limit = 20 - x_offset.abs();
for y_offset in -y_limit..=y_limit {
let cheat_length = (x_offset.unsigned_abs() + y_offset.unsigned_abs()) as u32;
if cheat_length == 0 {
continue;
}

let offset = y_offset * (self.cols as isize) + x_offset;
let next = index.wrapping_add_signed(offset);
let target_distance = self.distances[next];
if target_distance == u32::MAX || target_distance < this_distance + cheat_length
{
continue;
}

let diff = target_distance - this_distance - cheat_length;
if diff >= 100 {
cheats += 1;
}
}
}
}

cheats
}
}

examples!(Day20 -> (u32, u32) []);
1 change: 1 addition & 0 deletions crates/year2024/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ utils::year!(2024 => year2024, ${
17 => day17::Day17,
18 => day18::Day18,
19 => day19::Day19,
20 => day20::Day20,
});

0 comments on commit 8c783a7

Please sign in to comment.