Compare commits

..

No commits in common. "fee37aebd07ca64c974129fcc98640e73e4b209b" and "1cd535c2aa38fda2e1308a5b4b88d48a811a202b" have entirely different histories.

View File

@ -117,7 +117,6 @@ struct Map {
visited_from: grid::Grid<DirectionSet>,
guard_facing: FacingDirection,
guard_pos: (i64, i64),
path: Vec<((i64, i64), FacingDirection)>,
}
impl<T: BufRead> From<Lines<T>> for Map {
@ -132,7 +131,6 @@ impl<T: BufRead> From<Lines<T>> for Map {
guard_pos,
guard_facing,
visited_from,
path: Vec::new(),
}
}
}
@ -147,7 +145,7 @@ impl Map {
}
}
/// Move one step in the facing direction, return if we are still inside the bounds
fn step_guard<const RECORD_PATH: bool>(&mut self) -> StepOutcome {
fn step_guard(&mut self) -> StepOutcome {
let new_pos = self.guard_facing.pos_ofs(self.guard_pos);
if self
.visited_from
@ -157,9 +155,6 @@ impl Map {
return StepOutcome::LoopFound;
}
if self.grid.set(new_pos.0, new_pos.1, b'X') {
if RECORD_PATH {
self.path.push((new_pos, self.guard_facing));
}
self.visited_from.set(
new_pos.0,
new_pos.1,
@ -171,14 +166,34 @@ impl Map {
StepOutcome::LeftMap
}
}
fn run_guard<const RECORD_PATH: bool>(&mut self) -> RunOutcome {
fn run_guard(&mut self) -> RunOutcome {
// if the guard is surrounded by obstacles, bail out
if self
.grid
.get(self.guard_pos.0 - 1, self.guard_pos.1)
.is_some_and(|v| v == b'#')
&& self
.grid
.get(self.guard_pos.0 + 1, self.guard_pos.1)
.is_some_and(|v| v == b'#')
&& self
.grid
.get(self.guard_pos.0, self.guard_pos.1 - 1)
.is_some_and(|v| v == b'#')
&& self
.grid
.get(self.guard_pos.0, self.guard_pos.1 + 1)
.is_some_and(|v| v == b'#')
{
return RunOutcome::Stuck;
}
while let Some(val) = self.look(&self.guard_facing) {
match val {
b'#' => {
// obstacle, turn right
self.guard_facing = self.guard_facing.next();
}
_ => match self.step_guard::<RECORD_PATH>() {
_ => match self.step_guard() {
StepOutcome::LeftMap => return RunOutcome::LeftMap,
StepOutcome::LoopFound => return RunOutcome::LoopFound,
StepOutcome::Continue => {}
@ -193,7 +208,7 @@ impl Map {
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
let mut map = Map::from(input);
map.run_guard::<false>();
map.run_guard();
(map.grid.count(b'X') + map.grid.count(b'-') + map.grid.count(b'|') + map.grid.count(b'^')) as u64
}
@ -201,31 +216,21 @@ fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
// PROBLEM 2 solution
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
let input_map = Map::from(input);
// Use the solution from problem 1 to reduce the number of positions where obstacle placement will change the path
let mut path_map = input_map.clone();
path_map.run_guard::<true>();
let mut tested_position: grid::Grid<bool> = grid::Grid::new(path_map.grid.width() as i64);
tested_position.data.resize(path_map.grid.data.len(), false);
let mut loop_count = 0u64;
let mut last_posdir = (input_map.guard_pos, input_map.guard_facing);
for ((x, y), dir) in path_map.path.iter() {
if !tested_position.get(*x, *y).unwrap() {
tested_position.set(*x, *y, true);
let mut test_map = input_map.clone();
test_map.grid.set(*x, *y, b'#');
test_map.guard_pos = last_posdir.0;
test_map.guard_facing = last_posdir.1;
if let RunOutcome::LoopFound = test_map.run_guard::<false>() {
loop_count += 1
for y in 0..input_map.grid.height() {
for x in 0..input_map.grid.width() {
match input_map.grid.get(x as i64, y as i64) {
Some(b'.') => {
let mut test_map = input_map.clone();
test_map.grid.set(x as i64, y as i64, b'#');
if let RunOutcome::LoopFound = test_map.run_guard() {
loop_count += 1
}
}
_ => continue,
}
last_posdir = ((*x, *y), *dir);
}
}
loop_count
}