day16: back to elegant recursion now that we track beams

problem 1 solution was busting the stack, so used an iterative approach,
but now that we track lit beams we can bail out early enough not to bust
the stack. performance is the same but it's much nicer.
This commit is contained in:
Keenan Tims 2023-12-15 23:54:22 -08:00
parent 427a0c766b
commit 842def62dc
Signed by: ktims
GPG Key ID: 11230674D69038D4

View File

@ -1,4 +1,3 @@
use std::collections::HashSet;
use std::fmt::Display; use std::fmt::Display;
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader, Lines}; use std::io::{BufRead, BufReader, Lines};
@ -153,37 +152,29 @@ impl Contraption {
} }
fn cast_ray<'a>(&'a mut self, pos: (i64, i64), dir: FromDirection) -> VisitState { fn cast_ray<'a>(&'a mut self, pos: (i64, i64), dir: FromDirection) -> VisitState {
let mut state = self.empty_state(); let mut state = self.empty_state();
let mut new_rays = self.cast_ray_inner(&mut state, pos, dir); self.cast_ray_inner(&mut state, pos, dir);
while new_rays.len() != 0 {
new_rays = new_rays
.iter()
.flat_map(|(pos, dir)| self.cast_ray_inner(&mut state, *pos, *dir))
.collect();
}
state state
} }
fn cast_ray_inner<'a>( fn cast_ray_inner<'a>(
&'a mut self, &'a mut self,
state: &'a mut VisitState, state: &'a mut VisitState,
mut pos: (i64, i64), pos: (i64, i64),
mut dir: FromDirection, dir: FromDirection,
) -> Vec<((i64, i64), FromDirection)> { ) {
let mut new_rays = Vec::new(); if pos.0 >= 0
&& pos.1 >= 0
while pos.0 >= 0 && pos.1 >= 0 && pos.0 < self.width() && pos.1 < self.height() { && pos.0 < self.width()
if !state.visit(pos, dir) { && pos.1 < self.height()
break; && state.visit(pos, dir)
} {
dir = 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) => dir, Interaction::One(dir) => self.cast_ray_inner(state, dir.goes_pos(pos), dir),
Interaction::Two((dir1, dir2)) => { Interaction::Two((dir1, dir2)) => {
new_rays.push((pos, dir1)); self.cast_ray_inner(state, dir1.goes_pos(pos), dir1);
dir2 self.cast_ray_inner(state, dir2.goes_pos(pos), dir2);
} }
}; };
pos = dir.goes_pos(pos);
} }
new_rays
} }
fn empty_state(&self) -> VisitState { fn empty_state(&self) -> VisitState {
let mut visited_from = Vec::new(); let mut visited_from = Vec::new();