day16: use tail recursion unstead of passing mutable state

This commit is contained in:
Keenan Tims 2023-12-16 11:07:39 -08:00
parent 842def62dc
commit da25b73eca
Signed by: ktims
GPG Key ID: 11230674D69038D4

View File

@ -41,12 +41,12 @@ enum FromDirection {
} }
impl FromDirection { impl FromDirection {
fn mask(&self) -> u8 { const fn mask(&self) -> u8 {
1 << *self as u8 1 << *self as u8
} }
// return the new pos for a ray that will be from the direction. // return the new pos for a ray that will be from the direction.
// a ray 'from' left 'goes' right // a ray 'from' left 'goes' right
fn goes_pos(&self, pos: (i64, i64)) -> (i64, i64) { const fn goes_pos(&self, pos: (i64, i64)) -> (i64, i64) {
match self { match self {
Self::Left => (pos.0 + 1, pos.1), Self::Left => (pos.0 + 1, pos.1),
Self::Right => (pos.0 - 1, pos.1), Self::Right => (pos.0 - 1, pos.1),
@ -54,7 +54,7 @@ impl FromDirection {
Self::Below => (pos.0, pos.1 - 1), Self::Below => (pos.0, pos.1 - 1),
} }
} }
fn reflect_ne(&self) -> Self { const fn reflect_ne(&self) -> Self {
match self { match self {
Self::Left => Self::Below, Self::Left => Self::Below,
Self::Right => Self::Above, Self::Right => Self::Above,
@ -62,7 +62,7 @@ impl FromDirection {
Self::Below => Self::Left, Self::Below => Self::Left,
} }
} }
fn opposite(&self) -> FromDirection { const fn opposite(&self) -> FromDirection {
match self { match self {
Self::Left => Self::Right, Self::Left => Self::Right,
Self::Right => Self::Left, Self::Right => Self::Left,
@ -70,7 +70,7 @@ impl FromDirection {
Self::Below => Self::Above, Self::Below => Self::Above,
} }
} }
fn reflect_se(&self) -> FromDirection { const fn reflect_se(&self) -> FromDirection {
self.reflect_ne().opposite() self.reflect_ne().opposite()
} }
fn interact(&self, tile: char) -> Interaction { fn interact(&self, tile: char) -> Interaction {
@ -90,7 +90,7 @@ impl FromDirection {
Interaction::Two((FromDirection::Left, FromDirection::Right)) Interaction::Two((FromDirection::Left, FromDirection::Right))
} }
}, },
c => unimplemented!("invalid tile {}", c), c => panic!("invalid tile {}", c),
} }
} }
} }
@ -150,17 +150,15 @@ impl Contraption {
fn width(&self) -> i64 { fn width(&self) -> i64 {
self.tiles[0].len() as i64 self.tiles[0].len() as i64
} }
fn cast_ray<'a>(&'a mut self, pos: (i64, i64), dir: FromDirection) -> VisitState { fn cast_ray(&self, pos: (i64, i64), dir: FromDirection) -> VisitState {
let mut state = self.empty_state(); self.cast_ray_inner(self.empty_state(), pos, dir)
self.cast_ray_inner(&mut state, pos, dir);
state
} }
fn cast_ray_inner<'a>( fn cast_ray_inner(
&'a mut self, &self,
state: &'a mut VisitState, mut state: VisitState,
pos: (i64, i64), pos: (i64, i64),
dir: FromDirection, dir: FromDirection,
) { ) -> VisitState {
if pos.0 >= 0 if pos.0 >= 0
&& pos.1 >= 0 && pos.1 >= 0
&& pos.0 < self.width() && pos.0 < self.width()
@ -169,11 +167,14 @@ impl Contraption {
{ {
match dir.interact(self.tiles[pos.1 as usize][pos.0 as usize]) { match dir.interact(self.tiles[pos.1 as usize][pos.0 as usize]) {
Interaction::One(dir) => self.cast_ray_inner(state, dir.goes_pos(pos), dir), Interaction::One(dir) => self.cast_ray_inner(state, dir.goes_pos(pos), dir),
Interaction::Two((dir1, dir2)) => { Interaction::Two((dir1, dir2)) => self.cast_ray_inner(
self.cast_ray_inner(state, dir1.goes_pos(pos), dir1); self.cast_ray_inner(state, dir2.goes_pos(pos), dir2),
self.cast_ray_inner(state, dir2.goes_pos(pos), dir2); dir1.goes_pos(pos),
} dir1,
}; ),
}
} else {
state
} }
} }
fn empty_state(&self) -> VisitState { fn empty_state(&self) -> VisitState {
@ -198,14 +199,14 @@ impl<T: BufRead> From<Lines<T>> for Contraption {
// PROBLEM 1 solution // PROBLEM 1 solution
fn problem1<T: BufRead>(input: Lines<T>) -> u64 { fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
let mut contraption = Contraption::from(input); let contraption = Contraption::from(input);
contraption.cast_ray((0, 0), FromDirection::Left).score() contraption.cast_ray((0, 0), FromDirection::Left).score()
} }
// PROBLEM 2 solution // PROBLEM 2 solution
fn problem2<T: BufRead>(input: Lines<T>) -> u64 { fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
let mut contraption = Contraption::from(input); let contraption = Contraption::from(input);
let rows_max = (0..contraption.height()).fold(0, |max_tiles, y| { let rows_max = (0..contraption.height()).fold(0, |max_tiles, y| {
std::cmp::max( std::cmp::max(