Create MatBuf abstraction for mutable matrix types
This commit is contained in:
parent
aade234881
commit
21f6b25de0
|
@ -5,7 +5,7 @@ pub mod matrix;
|
||||||
pub mod piece;
|
pub mod piece;
|
||||||
|
|
||||||
pub use input::Movement;
|
pub use input::Movement;
|
||||||
pub use matrix::Mat;
|
pub use matrix::{Mat, MatBuf};
|
||||||
pub use piece::{Loc, Piece, Rot};
|
pub use piece::{Loc, Piece, Rot};
|
||||||
|
|
||||||
#[cfg(feature = "srs")]
|
#[cfg(feature = "srs")]
|
||||||
|
|
|
@ -120,6 +120,129 @@ pub mod __ascii {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrapper struct for using an underlying buffer (such as an array or vec) as a
|
||||||
|
/// "writable" matrix. This allows operations such as changing if a cell is occupied or
|
||||||
|
/// not.
|
||||||
|
///
|
||||||
|
/// [`MatBuf`] implements [`Deref`], so it automatically inherits the methods of [`Mat`].
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct MatBuf<T: AsRef<[u16]> = [u16; 40]> {
|
||||||
|
buffer: T,
|
||||||
|
rows: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> MatBuf<[u16; N]> {
|
||||||
|
/// Returns a new empty [`MatBuf`] backed by a fixed-size array.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
buffer: [0u16; N],
|
||||||
|
rows: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MatBuf<T>
|
||||||
|
where
|
||||||
|
T: AsRef<[u16]>,
|
||||||
|
{
|
||||||
|
/// Returns the underyling buffer.
|
||||||
|
pub fn into_inner(self) -> T {
|
||||||
|
self.buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a read-only view of this matrix.
|
||||||
|
#[inline]
|
||||||
|
pub fn as_mat(&self) -> &Mat {
|
||||||
|
Mat::new(&self.buffer.as_ref()[..self.rows])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets the matrix so it is empty.
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.rows = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MatBuf<T>
|
||||||
|
where
|
||||||
|
T: AsRef<[u16]> + AsMut<[u16]>,
|
||||||
|
{
|
||||||
|
/// Modifies the cells in this matrix to be identical to those in `mat`.
|
||||||
|
///
|
||||||
|
/// Panics if the buffer space cannot fit the rows of `mat`.
|
||||||
|
pub fn copy_from(&mut self, mat: &Mat) {
|
||||||
|
let data = self.buffer.as_mut();
|
||||||
|
if mat.data().len() > data.len() {
|
||||||
|
panic!("matrix cannot fit in available buffer space");
|
||||||
|
}
|
||||||
|
self.rows = mat.rows() as usize;
|
||||||
|
data[..self.rows].copy_from_slice(mat.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fills in the cell at the given (x,y) coordinate. Adds new rows to the top of the
|
||||||
|
/// matrix if necessary.
|
||||||
|
///
|
||||||
|
/// Panics if the buffer space cannot fit the new rows.
|
||||||
|
pub fn set(&mut self, x: i16, y: i16) {
|
||||||
|
if y < 0 || !(0..COLUMNS).contains(&x) {
|
||||||
|
// OOB coordinates are considered already set
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let y = y as usize;
|
||||||
|
let data = self.buffer.as_mut();
|
||||||
|
while y >= self.rows {
|
||||||
|
*data
|
||||||
|
.get_mut(self.rows)
|
||||||
|
.expect("y should be within available buffer space") = EMPTY_ROW;
|
||||||
|
self.rows += 1;
|
||||||
|
}
|
||||||
|
data[y] |= 1 << x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes any rows that are completely filled, shifting rows above down. Returns a
|
||||||
|
/// new view of the buffer that only includes the remaining rows.
|
||||||
|
pub fn clear_lines(&mut self) {
|
||||||
|
let data = self.buffer.as_mut();
|
||||||
|
let mut dst_y = 0;
|
||||||
|
for y in 0..self.rows {
|
||||||
|
if data[y] != FULL_ROW && data[y] != EMPTY_ROW {
|
||||||
|
data[dst_y] = data[y];
|
||||||
|
dst_y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.rows = dst_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All boilerplate below
|
||||||
|
|
||||||
|
impl<T: AsRef<[u16]>> core::ops::Deref for MatBuf<T> {
|
||||||
|
type Target = Mat;
|
||||||
|
fn deref(&self) -> &Mat {
|
||||||
|
self.as_mat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AsRef<[u16]>> core::fmt::Debug for MatBuf<T> {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
self.as_mat().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AsRef<[u16]>> core::cmp::Eq for MatBuf<T> {}
|
||||||
|
impl<T: AsRef<[u16]>> core::cmp::PartialEq<Mat> for MatBuf<T> {
|
||||||
|
fn eq(&self, other: &Mat) -> bool {
|
||||||
|
self.as_mat() == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AsRef<[u16]>> core::cmp::PartialEq<&Mat> for MatBuf<T> {
|
||||||
|
fn eq(&self, other: &&Mat) -> bool {
|
||||||
|
self.as_mat() == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: AsRef<[u16]>, U: AsRef<[u16]>> core::cmp::PartialEq<MatBuf<U>> for MatBuf<T> {
|
||||||
|
fn eq(&self, other: &MatBuf<U>) -> bool {
|
||||||
|
self.as_mat() == other.as_mat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -192,4 +315,73 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mat_buf_copy_from() {
|
||||||
|
let mut buf: MatBuf = MatBuf::new();
|
||||||
|
assert_eq!(buf, Mat::EMPTY);
|
||||||
|
assert_eq!(buf.rows(), 0);
|
||||||
|
let mat = mat! {
|
||||||
|
"xxx.......";
|
||||||
|
"xx........";
|
||||||
|
"x.........";
|
||||||
|
};
|
||||||
|
buf.copy_from(mat);
|
||||||
|
assert_eq!(buf, mat);
|
||||||
|
assert_eq!(buf.rows(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clear_lines() {
|
||||||
|
let mat0 = mat! {
|
||||||
|
".........."; // clear
|
||||||
|
".........."; // clear
|
||||||
|
"x.........";
|
||||||
|
".........."; // clear
|
||||||
|
".x.xxxxxxx";
|
||||||
|
"xxxxxxxxxx"; // clear
|
||||||
|
"x.xxxxxxxx";
|
||||||
|
};
|
||||||
|
let mat1 = mat! {
|
||||||
|
"x.........";
|
||||||
|
".x.xxxxxxx";
|
||||||
|
"x.xxxxxxxx";
|
||||||
|
};
|
||||||
|
let mut buf: MatBuf<[u16; 7]> = MatBuf::new();
|
||||||
|
assert_eq!(buf.rows(), 0);
|
||||||
|
buf.copy_from(mat0);
|
||||||
|
assert_eq!(buf.rows(), 7);
|
||||||
|
buf.clear_lines();
|
||||||
|
assert_eq!(buf, mat1);
|
||||||
|
assert_eq!(buf.rows(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set() {
|
||||||
|
let mut buf: MatBuf<[u16; 4]> = MatBuf::new();
|
||||||
|
buf.set(0, 0); // a
|
||||||
|
buf.set(9, 3); // b
|
||||||
|
buf.set(1, 1); // c
|
||||||
|
buf.set(2, 1); // d
|
||||||
|
buf.set(3, 1); // e
|
||||||
|
assert!(buf.get(0, 0));
|
||||||
|
assert!(buf.get(9, 3));
|
||||||
|
assert!(buf.get(1, 1));
|
||||||
|
assert!(buf.get(2, 1));
|
||||||
|
assert!(buf.get(3, 1));
|
||||||
|
let mat = mat! {
|
||||||
|
".........b";
|
||||||
|
"..........";
|
||||||
|
".cde......";
|
||||||
|
"a.........";
|
||||||
|
};
|
||||||
|
assert_eq!(buf, mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_set_oob() {
|
||||||
|
let mut buf: MatBuf<[u16; 4]> = MatBuf::new();
|
||||||
|
buf.set(0, 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue