Skip to content

Commit

Permalink
Day 17: Clumsy Crucible
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient committed Dec 17, 2023
1 parent fa4ff04 commit 904330a
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ Development occurs in language-specific directories:
|[Day14.hs](hs/src/Day14.hs)|[Day14.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day14.kt)|[day14.py](py/aoc2023/day14.py)|[day14.rs](rs/src/day14.rs)|
|[Day15.hs](hs/src/Day15.hs)|[Day15.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day15.kt)|[day15.py](py/aoc2023/day15.py)|[day15.rs](rs/src/day15.rs)|
|[Day16.hs](hs/src/Day16.hs)|[Day16.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day16.kt)|[day16.py](py/aoc2023/day16.py)|[day16.rs](rs/src/day16.rs)|
|[Day17.hs](hs/src/Day17.hs)|[Day17.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day17.kt)|[day17.py](py/aoc2023/day17.py)||
|[Day17.hs](hs/src/Day17.hs)|[Day17.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day17.kt)|[day17.py](py/aoc2023/day17.py)|[day17.rs](rs/src/day17.rs)|
10 changes: 8 additions & 2 deletions rs/benches/criterion.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use aoc2023::{
day1, day10, day11, day12, day13, day14, day15, day16, day2, day3, day4, day5, day6, day7,
day8, day9,
day1, day10, day11, day12, day13, day14, day15, day16, day17, day2, day3, day4, day5, day6,
day7, day8, day9,
};
use criterion::{black_box, Criterion};
use std::env;
Expand Down Expand Up @@ -113,6 +113,12 @@ fn aoc2023_bench(c: &mut Criterion) -> io::Result<()> {
g.bench_function("part 2", |b| b.iter(|| day16::part2(black_box(&data))));
g.finish();

let data = get_day_input(17)?;
let mut g = c.benchmark_group("day 17");
g.bench_function("part 1", |b| b.iter(|| day17::part1(black_box(&data))));
g.bench_function("part 2", |b| b.iter(|| day17::part2(black_box(&data))));
g.finish();

Ok(())
}

Expand Down
158 changes: 158 additions & 0 deletions rs/src/day17.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use std::cmp::Reverse;
use std::collections::{BinaryHeap, HashSet};

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum Direction {
U,
L,
D,
R,
}

impl Direction {
fn next(&self) -> Direction {
match self {
Direction::U => Direction::L,
Direction::L => Direction::D,
Direction::D => Direction::R,
Direction::R => Direction::U,
}
}
fn prev(&self) -> Direction {
match self {
Direction::U => Direction::R,
Direction::L => Direction::U,
Direction::D => Direction::L,
Direction::R => Direction::D,
}
}
}

fn step(y: usize, x: usize, dir: Direction) -> Option<(usize, usize)> {
Some(match dir {
Direction::U => (y.checked_sub(1)?, x),
Direction::L => (y, x.checked_sub(1)?),
Direction::D => (y.checked_add(1)?, x),
Direction::R => (y, x.checked_add(1)?),
})
}

fn solve<P, F, T>(data: &str, ok: P, next: F) -> Option<usize>
where
P: Fn(usize) -> bool,
F: Fn(Direction, usize) -> T,
T: IntoIterator,
<T as IntoIterator>::Item: Into<Direction>,
{
let maze = data
.lines()
.filter_map(|line| {
line.chars()
.map(|c| c.to_digit(10).filter(|&d| d > 0))
.collect::<Option<Vec<_>>>()
})
.collect::<Vec<_>>();
let mut queue: BinaryHeap<_> = [(Reverse(0), (0, 0, Direction::R, 0))].into();
let mut visited = HashSet::new();
while let Some((Reverse(cost), state @ (y, x, direction, distance))) = queue.pop() {
if y == maze.len() - 1 && x == maze[y].len() - 1 && ok(distance) {
return Some(cost);
}
if !visited.insert(state) {
continue;
}
for direction in next(direction, distance) {
let direction = direction.into();
let Some((y, x)) =
step(y, x, direction).filter(|&(y, x)| y < maze.len() && x < maze[y].len())
else {
continue;
};
queue.push((
Reverse(cost + maze[y][x] as usize),
(
y,
x,
direction,
if direction == state.2 {
distance + 1
} else {
1
},
),
));
}
}
None
}

pub fn part1(data: &str) -> Option<usize> {
solve(
data,
|_| true,
|direction, distance| {
if distance < 3 {
vec![direction.prev(), direction.next(), direction]
} else {
vec![direction.prev(), direction.next()]
}
},
)
}

pub fn part2(data: &str) -> Option<usize> {
solve(
data,
|distance| distance >= 4,
|direction, distance| {
if distance < 4 {
vec![direction]
} else if distance < 10 {
vec![direction.prev(), direction.next(), direction]
} else {
vec![direction.prev(), direction.next()]
}
},
)
}

#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
use pretty_assertions::assert_eq;

static EXAMPLE_1: &str = indoc! {"
2413432311323
3215453535623
3255245654254
3446585845452
4546657867536
1438598798454
4457876987766
3637877979653
4654967986887
4564679986453
1224686865563
2546548887735
4322674655533
"};
static EXAMPLE_2: &str = indoc! {"
111111111111
999999999991
999999999991
999999999991
999999999991
"};

#[test]
fn part1_examples() {
assert_eq!(Some(102), part1(EXAMPLE_1));
}

#[test]
fn part2_examples() {
assert_eq!(Some(94), part2(EXAMPLE_1));
assert_eq!(Some(71), part2(EXAMPLE_2));
}
}
1 change: 1 addition & 0 deletions rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod day13;
pub mod day14;
pub mod day15;
pub mod day16;
pub mod day17;
pub mod day2;
pub mod day3;
pub mod day4;
Expand Down
12 changes: 10 additions & 2 deletions rs/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use aoc2023::{
day1, day10, day11, day12, day13, day14, day15, day16, day2, day3, day4, day5, day6, day7,
day8, day9,
day1, day10, day11, day12, day13, day14, day15, day16, day17, day2, day3, day4, day5, day6,
day7, day8, day9,
};
use std::collections::HashSet;
use std::env;
Expand Down Expand Up @@ -147,5 +147,13 @@ fn main() -> io::Result<()> {
println!();
}

if args.is_empty() || args.contains("17") {
println!("Day 17");
let data = get_day_input(17)?;
println!("{:?}", day17::part1(&data).expect("error"));
println!("{:?}", day17::part2(&data).expect("error"));
println!();
}

Ok(())
}

0 comments on commit 904330a

Please sign in to comment.