use bit_vec::BitVec;
use glam::{IVec2, UVec2};
use crate::{GridPoint, GridRect, GridSize, SizedGrid};
#[derive(Default, Clone)]
pub struct BitGrid {
bits: BitVec,
size: UVec2,
}
impl SizedGrid for BitGrid {
fn size(&self) -> UVec2 {
self.size
}
}
impl BitGrid {
pub fn new(size: impl GridSize) -> Self {
Self {
bits: BitVec::from_elem(size.tile_count(), false),
size: size.to_uvec2(),
}
}
pub fn with_value(mut self, value: bool) -> Self {
self.set_all(value);
self
}
#[inline]
pub fn get(&self, xy: impl GridPoint) -> bool {
let i = self.transform_lti(xy);
self.get_index(i)
}
#[inline]
pub fn get_index(&self, i: usize) -> bool {
self.bits.get(i).unwrap()
}
#[inline]
pub fn set_true(&mut self, xy: impl GridPoint) {
self.set(xy, true);
}
#[inline]
pub fn set_false(&mut self, xy: impl GridPoint) {
self.set(xy, false);
}
#[inline]
pub fn set(&mut self, xy: impl GridPoint, value: bool) {
let i = self.transform_lti(xy);
self.bits.set(i, value);
}
#[inline]
pub fn set_index(&mut self, i: usize, value: bool) {
self.bits.set(i, value);
}
#[inline]
pub fn set_index_true(&mut self, i: usize) {
self.set_index(i, true);
}
#[inline]
pub fn set_index_false(&mut self, i: usize) {
self.set_index(i, false);
}
#[inline]
pub fn toggle(&mut self, xy: impl GridPoint) {
let i = self.transform_lti(xy);
self.toggle_index(i)
}
#[inline]
pub fn toggle_index(&mut self, i: usize) {
let v = self.bits.get(i).unwrap();
self.bits.set(i, !v);
}
pub fn set_all(&mut self, value: bool) {
match value {
true => self.bits.set_all(),
false => self.bits.clear(),
}
}
pub fn bits(&self) -> &BitVec {
&self.bits
}
pub fn bits_mut(&mut self) -> &mut BitVec {
&mut self.bits
}
pub fn any(&self) -> bool {
self.bits.any()
}
pub fn none(&self) -> bool {
self.bits.none()
}
pub fn all_negate(&mut self) {
self.bits.negate();
}
pub fn clear(&mut self) {
self.bits.clear();
}
pub fn iter(&self) -> impl Iterator<Item = bool> + '_ {
self.bits.iter()
}
pub fn iter_xy(&self) -> impl Iterator<Item = (IVec2, bool)> + '_ {
self.iter_grid_points().map(move |p| (p, self.get(p)))
}
pub fn iter_rect(&self, rect: GridRect) -> impl Iterator<Item = (IVec2, bool)> + '_ {
rect.iter_points().map(move |p| (p, self.get(p)))
}
pub fn clone_rect(&self, area: GridRect) -> BitGrid {
let mut grid = BitGrid::new(area.size());
for p in area.iter_points() {
grid.set(p, self.get(p));
}
grid
}
}
impl IntoIterator for BitGrid {
type Item = bool;
type IntoIter = bit_vec::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.bits.into_iter()
}
}
impl std::fmt::Debug for BitGrid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let a = format!("{:?}", self.bits);
for y in (0..self.height()).rev() {
let start = self.transform_lti([0, y]);
let end = start + self.width();
writeln!(f, "{}", &a[start..end])?;
}
Ok(())
}
}
impl<T: GridPoint> std::ops::Index<T> for BitGrid {
type Output = bool;
fn index(&self, index: T) -> &Self::Output {
&self.bits[self.transform_lti(index)]
}
}
impl std::ops::Index<usize> for BitGrid {
type Output = bool;
fn index(&self, index: usize) -> &Self::Output {
&self.bits[index]
}
}
#[cfg(test)]
mod tests {
use super::BitGrid;
use crate::SizedGrid;
#[test]
fn iter() {
let mut grid = BitGrid::new([10, 5]);
grid.set_true([0, 0]);
grid.set_true([0, 1]);
grid.set_true([9, 2]);
grid.set_true([9, 4]);
let points: Vec<_> = grid.iter_xy().collect();
assert!(points[grid.transform_lti([0, 0])].1);
assert!(points[grid.transform_lti([0, 1])].1);
assert!(points[grid.transform_lti([9, 2])].1);
assert!(points[grid.transform_lti([9, 4])].1);
}
}