1
0
Fork 0

day(17): add solution

Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
Matej Focko 2023-12-17 18:09:44 +01:00
parent fffaaf0637
commit 15fccb9f5e
Signed by: mfocko
GPG key ID: 7C47D46246790496
2 changed files with 148 additions and 0 deletions

13
samples/day17.txt Normal file
View file

@ -0,0 +1,13 @@
2413432311323
3215453535623
3255245654254
3446585845452
4546657867536
1438598798454
4457876987766
3637877979653
4654967986887
4564679986453
1224686865563
2546548887735
4322674655533

135
src/bin/day17.rs Normal file
View file

@ -0,0 +1,135 @@
use std::collections::HashSet;
use aoc_2023::*;
type Output1 = u32;
type Output2 = Output1;
fn left(v: &Vector2D<isize>) -> Vector2D<isize> {
Vector2D::new(v.y(), -v.x())
}
fn right(v: &Vector2D<isize>) -> Vector2D<isize> {
Vector2D::new(-v.y(), v.x())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct State {
heat_loss: u32,
distance: isize,
position: Vector2D<isize>,
direction: Vector2D<isize>,
}
impl State {
fn step(&self, m: &[Vec<u32>], direction: Vector2D<isize>, steps: isize) -> State {
let position = self.position + (direction * steps);
let distance = self.distance + steps;
let heat_loss = self.heat_loss
+ (1..=steps)
.map(|s| m[self.position + direction * s])
.sum::<u32>();
State {
heat_loss,
distance,
position,
direction,
}
}
}
struct Day17 {
map: Vec<Vec<u32>>,
}
impl Day17 {
fn astar(&self, min_steps: isize, max_steps: isize) -> u32 {
let (width, height) = (self.map[0].len(), self.map.len());
let goal = Vector2D::new(width as isize - 1, height as isize - 1);
let mut queue: MinHeap<State> = MinHeap::new();
queue.push(State {
heat_loss: 0,
distance: 0,
position: Vector2D::new(0, 0),
direction: Vector2D::new(1, 0),
});
queue.push(State {
heat_loss: 0,
distance: 0,
position: Vector2D::new(0, 0),
direction: Vector2D::new(0, 1),
});
let mut seen: HashSet<(Vector2D<isize>, Vector2D<isize>)> = HashSet::new();
while let Some(s) = queue.pop() {
if s.position == goal {
return s.heat_loss;
}
if seen.contains(&(s.position, s.direction)) {
continue;
}
seen.insert((s.position, s.direction));
for steps in min_steps..=max_steps {
for d in [left(&s.direction), right(&s.direction)] {
if !in_range(&self.map, &(s.position + d * steps)) {
continue;
}
queue.push(s.step(&self.map, d, steps));
}
}
}
unreachable!()
}
}
impl Solution<Output1, Output2> for Day17 {
fn new<P: AsRef<Path>>(pathname: P) -> Self {
Self {
map: file_to_string(pathname)
.lines()
.map(|l| l.chars().map(|c| c.to_digit(10).unwrap()).collect())
.collect(),
}
}
fn part_1(&mut self) -> Output1 {
self.astar(1, 3)
}
fn part_2(&mut self) -> Output2 {
self.astar(4, 10)
}
}
fn main() -> Result<()> {
Day17::main()
}
test_sample!(day_17, Day17, 102, 94);
#[cfg(test)]
mod day_17_extended {
use super::*;
#[test]
fn test_left_rotate() {
assert_eq!(left(&Vector2D::new(1, 0)), Vector2D::new(0, -1));
assert_eq!(left(&Vector2D::new(0, -1)), Vector2D::new(-1, 0));
assert_eq!(left(&Vector2D::new(-1, 0)), Vector2D::new(0, 1));
assert_eq!(left(&Vector2D::new(0, 1)), Vector2D::new(1, 0));
}
#[test]
fn test_right_rotate() {
assert_eq!(right(&Vector2D::new(1, 0)), Vector2D::new(0, 1));
assert_eq!(right(&Vector2D::new(0, -1)), Vector2D::new(1, 0));
assert_eq!(right(&Vector2D::new(-1, 0)), Vector2D::new(0, -1));
assert_eq!(right(&Vector2D::new(0, 1)), Vector2D::new(-1, 0));
}
}