diff --git a/.gitignore b/.gitignore index 144b48a..09ae99b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ input flamegraph.svg perf.data +guesses diff --git a/6/Cargo.lock b/6/Cargo.lock index f1f33b1..4027548 100644 --- a/6/Cargo.lock +++ b/6/Cargo.lock @@ -2,10 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "day6" version = "0.1.0" dependencies = [ + "bitflags", "grid", ] diff --git a/6/Cargo.toml b/6/Cargo.toml index f4e63ad..98281f9 100644 --- a/6/Cargo.toml +++ b/6/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +bitflags = "2.6.0" grid = { version = "0.1.0", path = "../libs/grid" } diff --git a/6/src/main.rs b/6/src/main.rs index fcbc3c0..71c46c4 100644 --- a/6/src/main.rs +++ b/6/src/main.rs @@ -1,7 +1,9 @@ +use bitflags::bitflags; use std::collections::{HashMap, HashSet}; -use std::fmt::Display; +use std::fmt; use std::fs::File; use std::io::{BufRead, BufReader, Lines}; +use std::ops::BitAnd; use std::time::{Duration, Instant}; // BOILERPLATE @@ -76,10 +78,44 @@ enum RunOutcome { Stuck, } +bitflags! { + #[derive(Copy, Clone, Eq, PartialEq, Debug)] + pub struct DirectionSet: u8 { + const Up = 1; + const Down = 2; + const Left = 4; + const Right = 8; + } +} + +impl From for DirectionSet { + fn from(value: FacingDirection) -> Self { + match value { + FacingDirection::Up => DirectionSet::Up, + FacingDirection::Down => DirectionSet::Down, + FacingDirection::Left => DirectionSet::Left, + FacingDirection::Right => DirectionSet::Right, + } + } +} + +impl fmt::Display for DirectionSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl BitAnd for DirectionSet { + type Output = DirectionSet; + fn bitand(self, rhs: FacingDirection) -> Self::Output { + self & DirectionSet::from(rhs) + } +} + #[derive(Clone)] struct Map { grid: grid::Grid, - visited_from: HashMap<(i64, i64), HashSet>, + visited_from: grid::Grid, guard_facing: FacingDirection, guard_pos: (i64, i64), } @@ -87,7 +123,8 @@ struct Map { impl From> for Map { fn from(input: Lines) -> Self { let grid = grid::Grid::from(input); - let visited_from = HashMap::new(); + let mut visited_from: grid::Grid = grid::Grid::new(grid.width() as i64); + visited_from.data.resize(grid.data.len(), DirectionSet::empty()); let guard_pos = grid.find(b'^').expect("Guard not found"); let guard_facing = FacingDirection::Up; Self { @@ -111,14 +148,19 @@ impl Map { /// Move one step in the facing direction, return if we are still inside the bounds fn step_guard(&mut self) -> StepOutcome { let new_pos = self.guard_facing.pos_ofs(self.guard_pos); - if self.visited_from.contains_key(&new_pos) && self.visited_from[&new_pos].contains(&self.guard_facing) { + if self + .visited_from + .get(new_pos.0, new_pos.1) + .is_some_and(|dirs| dirs.contains(self.guard_facing.into())) + { return StepOutcome::LoopFound; } if self.grid.set(new_pos.0, new_pos.1, b'X') { - self.visited_from - .entry(new_pos) - .or_insert(HashSet::new()) - .insert(self.guard_facing); + self.visited_from.set( + new_pos.0, + new_pos.1, + self.visited_from.get(new_pos.0, new_pos.1).unwrap() | self.guard_facing.into(), + ); self.guard_pos = new_pos; StepOutcome::Continue } else { @@ -157,7 +199,6 @@ impl Map { StepOutcome::LoopFound => return RunOutcome::LoopFound, StepOutcome::Continue => {} }, - } } return RunOutcome::LeftMap;