day(17): add solution
Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
parent
fffaaf0637
commit
15fccb9f5e
2 changed files with 148 additions and 0 deletions
13
samples/day17.txt
Normal file
13
samples/day17.txt
Normal 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
135
src/bin/day17.rs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue