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