mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Replace sparse map with bitset
This commit is contained in:
@@ -102,25 +102,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct BitSet {
|
pub struct BitSet {
|
||||||
buffer: Vec<u32>,
|
buffer: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitSet {
|
impl BitSet {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::with_capacity(0)
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
let buffer = Vec::with_capacity(capacity);
|
let buffer = Vec::with_capacity(capacity / 32);
|
||||||
|
|
||||||
Self { buffer }
|
Self { buffer }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, value: usize) -> bool {
|
fn convert_value(value: usize) -> (usize, u32) {
|
||||||
let chunk = value / 32;
|
let chunk = value / 32;
|
||||||
let bit = 1 << (31 - (value % 32));
|
let bit = 1 << (31 - (value % 32));
|
||||||
|
|
||||||
|
(chunk, bit)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, value: usize) -> bool {
|
||||||
|
let (chunk, bit) = Self::convert_value(value);
|
||||||
|
|
||||||
if self.buffer.len() <= chunk + 1 {
|
if self.buffer.len() <= chunk + 1 {
|
||||||
self.buffer.resize(chunk + 1, 0);
|
self.buffer.resize(chunk + 1, 0);
|
||||||
}
|
}
|
||||||
@@ -135,4 +142,13 @@ impl BitSet {
|
|||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.buffer.iter().map(|c| c.count_ones() as usize).sum()
|
self.buffer.iter().map(|c| c.count_ones() as usize).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, value: usize) -> bool {
|
||||||
|
let (chunk, bit) = Self::convert_value(value);
|
||||||
|
|
||||||
|
self.buffer
|
||||||
|
.get(chunk)
|
||||||
|
.map(|&c| c & bit != 0)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,125 @@
|
|||||||
use std::collections::HashSet;
|
use std::fmt::Display;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::mem::swap;
|
use std::ops::Index;
|
||||||
|
|
||||||
|
use crate::common::BitSet;
|
||||||
|
|
||||||
type Translation = [bool; 512];
|
type Translation = [bool; 512];
|
||||||
type Point = (i32, i32);
|
|
||||||
type Field = HashSet<Point>;
|
struct Field {
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
infinity: bool,
|
||||||
|
finite: BitSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field {
|
||||||
|
pub fn from_input<'a>(input: impl Iterator<Item = &'a [u8]>) -> Self {
|
||||||
|
let mut input = input.peekable();
|
||||||
|
|
||||||
|
let width = input.peek().unwrap().len();
|
||||||
|
|
||||||
|
let mut finite = BitSet::new();
|
||||||
|
|
||||||
|
let len = input
|
||||||
|
.flatten()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, &c)| {
|
||||||
|
if c == b'#' {
|
||||||
|
finite.insert(index);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
debug_assert_eq!(len % width, 0);
|
||||||
|
let height = len / width;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
finite,
|
||||||
|
infinity: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn advance(&mut self, translation: &[bool; 512]) {
|
||||||
|
const INDEX_MASK: usize = (1 << 9) - 1;
|
||||||
|
|
||||||
|
let new_width = self.width + 2;
|
||||||
|
let new_height = self.height + 2;
|
||||||
|
|
||||||
|
let mut new_finite = BitSet::with_capacity(new_width * new_height);
|
||||||
|
|
||||||
|
// Now we can just do a normal loop
|
||||||
|
for y in 0..new_height {
|
||||||
|
for x in 0..new_width {
|
||||||
|
let mut mask = if self.infinity { INDEX_MASK } else { 0 };
|
||||||
|
|
||||||
|
for y in y.saturating_sub(2)..=y {
|
||||||
|
if x < 2 {
|
||||||
|
for _ in 0..(2 - x) {
|
||||||
|
mask = self.infinity as usize | (mask << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for x in x.saturating_sub(2)..=x {
|
||||||
|
mask = (mask << 1) | (self[(x, y)] as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if translation[mask & INDEX_MASK] {
|
||||||
|
let index = x + y * new_width;
|
||||||
|
new_finite.insert(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.width += 2;
|
||||||
|
self.height += 2;
|
||||||
|
self.finite = new_finite;
|
||||||
|
self.infinity = translation[if self.infinity { INDEX_MASK } else { 0 }];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
assert!(!self.infinity);
|
||||||
|
self.finite.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<(usize, usize)> for Field {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
|
||||||
|
if x >= self.width || y >= self.height {
|
||||||
|
return &self.infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = x + y * self.width;
|
||||||
|
|
||||||
|
if self.finite.contains(index) {
|
||||||
|
&true
|
||||||
|
} else {
|
||||||
|
&false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Field {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
if self[(x, y)] {
|
||||||
|
write!(f, "#")?
|
||||||
|
} else {
|
||||||
|
write!(f, ".")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_input(input: &mut dyn Read) -> (Translation, Field) {
|
fn read_input(input: &mut dyn Read) -> (Translation, Field) {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
@@ -19,67 +134,16 @@ fn read_input(input: &mut dyn Read) -> (Translation, Field) {
|
|||||||
.zip(it.next().unwrap())
|
.zip(it.next().unwrap())
|
||||||
.for_each(|(t, &c)| *t = c == b'#');
|
.for_each(|(t, &c)| *t = c == b'#');
|
||||||
|
|
||||||
let mut field = Field::default();
|
let field = Field::from_input(it.skip(1));
|
||||||
|
|
||||||
for (y, line) in it.skip(1).enumerate() {
|
|
||||||
for (x, _) in line.iter().enumerate().filter(|(_, &c)| c == b'#') {
|
|
||||||
field.insert((x as i32, y as i32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(translation, field)
|
(translation, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_dimensions(field: &Field) -> ((i32, i32), (i32, i32)) {
|
|
||||||
field
|
|
||||||
.iter()
|
|
||||||
.fold(((0, 0), (0, 0)), |((xmin, xmax), (ymin, ymax)), &(x, y)| {
|
|
||||||
((xmin.min(x), xmax.max(x)), (ymin.min(y), ymax.max(y)))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(translation: &Translation, field: &Field, new_field: &mut Field, infinity: &mut bool) {
|
|
||||||
const INDEX_MASK: usize = (1 << 9) - 1;
|
|
||||||
new_field.clear();
|
|
||||||
|
|
||||||
let ((xmin, xmax), (ymin, ymax)) = find_dimensions(field);
|
|
||||||
|
|
||||||
for x in (xmin - 1)..=(xmax + 1) {
|
|
||||||
let mut index = if *infinity { INDEX_MASK } else { 0 };
|
|
||||||
|
|
||||||
for y in (ymin - 1)..=(ymax + 1) {
|
|
||||||
for dx in -1..=1 {
|
|
||||||
index <<= 1;
|
|
||||||
|
|
||||||
let nx = x + dx;
|
|
||||||
let ny = y + 1;
|
|
||||||
|
|
||||||
if nx < xmin || nx > xmax || ny < ymin || ny > ymax {
|
|
||||||
index |= *infinity as usize;
|
|
||||||
} else if field.contains(&(nx, ny)) {
|
|
||||||
index |= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
index &= INDEX_MASK;
|
|
||||||
|
|
||||||
if translation[index] {
|
|
||||||
new_field.insert((x, y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*infinity = translation[if *infinity { 511 } else { 0 }]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parts_common(input: &mut dyn Read, count: usize) -> String {
|
fn parts_common(input: &mut dyn Read, count: usize) -> String {
|
||||||
let (translation, mut field) = read_input(input);
|
let (translation, mut field) = read_input(input);
|
||||||
let mut new_field = Field::new();
|
|
||||||
let mut infinity = false;
|
|
||||||
|
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
advance(&translation, &field, &mut new_field, &mut infinity);
|
field.advance(&translation);
|
||||||
swap(&mut field, &mut new_field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
field.len().to_string()
|
field.len().to_string()
|
||||||
|
|||||||
Reference in New Issue
Block a user