diff --git a/2022/src/common.rs b/2022/src/common.rs index 3edc925..c0a0b60 100644 --- a/2022/src/common.rs +++ b/2022/src/common.rs @@ -133,3 +133,42 @@ pub fn get_both(slice: &mut [T], first: usize, second: usize) -> (&mut T, &mu Ordering::Equal => panic!("Tried to get the same index twice {first}"), } } + +#[derive(Default)] +pub struct IndexSet(Vec); + +impl IndexSet { + pub fn with_capacity(capacity: usize) -> Self { + Self(Vec::with_capacity( + capacity / std::mem::size_of::() / 8, + )) + } + + fn ensure_item(&mut self, item: usize) -> &mut u32 { + if self.0.len() <= item { + self.0.resize(item + 1, 0); + } + + &mut self.0[item] + } + + #[inline] + fn index(index: usize) -> (usize, u8) { + const PER_ENTRY: usize = 8 * std::mem::size_of::(); + + (index / PER_ENTRY, (index % PER_ENTRY) as u8) + } + + pub fn insert(&mut self, index: usize) -> bool { + let (entry, pos) = Self::index(index); + + let item = self.ensure_item(entry); + + if *item & (1 << pos) != 0 { + false + } else { + *item |= 1 << pos; + true + } + } +} diff --git a/2022/src/day12.rs b/2022/src/day12.rs index bdd8a32..ef6033b 100644 --- a/2022/src/day12.rs +++ b/2022/src/day12.rs @@ -3,6 +3,8 @@ use std::collections::VecDeque; use anyhow::Context; use anyhow::Result; +use crate::common::IndexSet; + fn can_travel(from: u8, to: u8) -> bool { match (from, to) { (b'S', b'a'..=b'z') => true, @@ -24,7 +26,7 @@ pub fn part1(input: &[u8]) -> Result { .position(|&c| c == b'S') .context("Could not find starting position")?; - let mut visited = vec![false; input.len()]; + let mut visited = IndexSet::with_capacity(input.len()); let mut todo = VecDeque::new(); todo.push_back((0, starting_pos)); @@ -35,8 +37,7 @@ pub fn part1(input: &[u8]) -> Result { } let mut add_todo = |new: usize| { - if can_travel(input[pos], input[new]) && !visited[new] { - visited[new] = true; + if can_travel(input[pos], input[new]) && visited.insert(new) { todo.push_back((dist + 1, new)); } }; @@ -73,7 +74,7 @@ pub fn part2(input: &[u8]) -> Result { .position(|&c| c == b'E') .context("Could not find starting position")?; - let mut visited = vec![false; input.len()]; + let mut visited = IndexSet::with_capacity(input.len()); let mut todo = VecDeque::new(); todo.push_back((0, starting_pos)); @@ -84,8 +85,7 @@ pub fn part2(input: &[u8]) -> Result { } let mut add_todo = |new: usize| { - if can_travel(input[new], input[pos]) && !visited[new] { - visited[new] = true; + if can_travel(input[new], input[pos]) && visited.insert(new) { todo.push_back((dist + 1, new)); } };