use std::ops::{Index, IndexMut};
use grid::Grid;
use itertools::Itertools;
use crate::pos::{Pos, PosGet};
#[inline]
#[must_use]
pub fn bytes_grid(input: &str) -> Grid<u8> {
Grid::from(
input
.lines()
.map(|line| line.bytes().collect())
.collect_vec(),
)
}
impl<V> PosGet<V> for Grid<V> {
#[inline]
fn pos_get(&self, pos: Pos) -> Option<&V> {
self.get(pos.x, pos.y)
}
#[inline]
fn pos_get_mut(&mut self, pos: Pos) -> Option<&mut V> {
self.get_mut(pos.x, pos.y)
}
}
impl<V> Index<Pos> for Grid<V> {
type Output = V;
fn index(&self, index: Pos) -> &Self::Output {
#[allow(clippy::cast_sign_loss)]
&self[(index.x as usize, index.y as usize)]
}
}
impl<V> IndexMut<Pos> for Grid<V> {
fn index_mut(&mut self, index: Pos) -> &mut Self::Output {
#[allow(clippy::cast_sign_loss)]
&mut self[(index.x as usize, index.y as usize)]
}
}
#[derive(Debug)]
pub struct GridMask {
mask: Vec<bool>,
cols: usize,
}
impl GridMask {
#[must_use]
pub fn new((rows, cols): (usize, usize)) -> Self {
Self {
mask: vec![false; rows * cols],
cols,
}
}
#[inline]
pub fn set_false(&mut self, pos: Pos) -> bool {
if self[pos] {
self[pos] = false;
true
} else {
false
}
}
#[inline]
pub fn set_true(&mut self, pos: Pos) -> bool {
if self[pos] {
false
} else {
self[pos] = true;
true
}
}
#[inline]
pub fn toggle(&mut self, pos: Pos) {
self[pos] = !self[pos];
}
}
impl Index<Pos> for GridMask {
type Output = bool;
#[inline]
fn index(&self, pos: Pos) -> &Self::Output {
#[allow(clippy::cast_sign_loss)]
&self.mask[pos.x as usize * self.cols + pos.y as usize]
}
}
impl IndexMut<Pos> for GridMask {
#[inline]
fn index_mut(&mut self, pos: Pos) -> &mut Self::Output {
#[allow(clippy::cast_sign_loss)]
&mut self.mask[pos.x as usize * self.cols + pos.y as usize]
}
}
#[cfg(test)]
mod tests {
use super::{GridMask, PosGet, bytes_grid};
use crate::pos::Pos;
#[test]
fn bytes_grid_basic() {
let input = ("abc\ndef", [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]);
let expected = (2, 3, b"abcdef");
let grid = bytes_grid(input.0);
let output = (grid.rows(), grid.cols(), &input.1.map(|c| grid[c]));
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn grid_pos_get() {
let input = ("abc\ndef", [Pos::new(1, 1), Pos::new(0, 3)]);
let expected = [Some(&b'e'), None];
let grid = bytes_grid(input.0);
let output = input.1.map(|p| grid.pos_get(p));
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn grid_pos_get_mut() {
let input = ("abc\ndef", (1, 1), b'x');
let expected = b'x';
let mut grid = bytes_grid(input.0);
*grid
.pos_get_mut(Pos::from(input.1))
.expect("Expected in-bound position") = input.2;
let output = grid[input.1];
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn grid_index_pos() {
let input = ("abc\ndef", Pos::new(1, 1));
let expected = b'e';
let grid = bytes_grid(input.0);
let output = grid[input.1];
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn grid_indexmut_pos() {
let input = ("abc\ndef", (1, 1), b'x');
let expected = b'x';
let mut grid = bytes_grid(input.0);
grid[Pos::from(input.1)] = input.2;
let output = grid[input.1];
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn gridmask_new() {
let input = (2, 3);
let expected = (vec![false; 6], 3);
let gridmask = GridMask::new(input);
let output = (gridmask.mask, gridmask.cols);
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn gridmask_set_false() {
let input = ((2, 3), Pos::new(1, 1));
let expected = (false, false, true, false);
let mut gridmask = GridMask::new(input.0);
let output = (
gridmask[input.1],
gridmask.set_false(input.1),
{
gridmask[input.1] = true;
gridmask.set_false(input.1)
},
gridmask[input.1],
);
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn gridmask_set_true() {
let input = ((2, 3), Pos::new(1, 1));
let expected = (false, true, true, false);
let mut gridmask = GridMask::new(input.0);
let output = (
gridmask[input.1],
gridmask.set_true(input.1),
gridmask[input.1],
gridmask.set_true(input.1),
);
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn gridmask_toggle() {
let input = ((2, 3), Pos::new(1, 1));
let expected = (false, true, false);
let mut gridmask = GridMask::new(input.0);
let output = (
gridmask[input.1],
{
gridmask.toggle(input.1);
gridmask[input.1]
},
{
gridmask.toggle(input.1);
gridmask[input.1]
},
);
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn gridmask_index_pos() {
let input = ((2, 3), [Pos::new(0, 2), Pos::new(1, 1)]);
let expected = [true, false];
let mut gridmask = GridMask::new(input.0);
gridmask.set_true(input.1[0]);
let output = input.1.map(|p| gridmask[p]);
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn gridmask_indexmut_pos() {
let input = ((2, 3), [Pos::new(0, 2), Pos::new(1, 1)]);
let expected = [true, false, false, true];
let mut gridmask = GridMask::new(input.0);
gridmask.set_true(input.1[0]);
let mut output = [false; 4];
output[0] = gridmask[input.1[0]];
output[1] = gridmask[input.1[1]];
gridmask[input.1[0]] = !gridmask[input.1[0]];
gridmask[input.1[1]] = !gridmask[input.1[1]];
output[2] = gridmask[input.1[0]];
output[3] = gridmask[input.1[1]];
assert_eq!(expected, output, "\n input: {input:?}");
}
}