|
|
|
|
@ -264,7 +264,7 @@ struct ShapeStore(Option<Shape>);
|
|
|
|
|
|
|
|
|
|
impl Display for ShapeStore {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
match self.0 {
|
|
|
|
|
match &self.0 {
|
|
|
|
|
Some(inner) => write!(f, "{}", inner.as_ascii()),
|
|
|
|
|
None => write!(f, "---"),
|
|
|
|
|
}
|
|
|
|
|
@ -572,10 +572,9 @@ fn init_debug_ui(mut commands: Commands) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Component, Debug, Clone, Copy)]
|
|
|
|
|
enum Shape {
|
|
|
|
|
M4(Mat4),
|
|
|
|
|
M3(Mat3),
|
|
|
|
|
#[derive(Component, Debug, Clone)]
|
|
|
|
|
struct Shape {
|
|
|
|
|
layout: ShapeBlockLayout,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Shape {
|
|
|
|
|
@ -586,176 +585,160 @@ impl Default for Shape {
|
|
|
|
|
|
|
|
|
|
impl Display for Shape {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
write!(f, "{}", self.as_ascii())
|
|
|
|
|
write!(f, "{}", self.layout.as_ascii())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Shape {
|
|
|
|
|
fn from_mat4(input: Mat4) -> Self {
|
|
|
|
|
Self::M4(input)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn from_mat3(input: Mat3) -> Self {
|
|
|
|
|
Self::M3(input)
|
|
|
|
|
impl From<Vec<Vec<u8>>> for Shape {
|
|
|
|
|
fn from(inner: Vec<Vec<u8>>) -> Shape {
|
|
|
|
|
Shape {
|
|
|
|
|
layout: ShapeBlockLayout { inner },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Shape {
|
|
|
|
|
fn new_o() -> Self {
|
|
|
|
|
Self::from_mat4(Mat4::from_cols_array_2d(&[
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
[0., 1., 1., 0.],
|
|
|
|
|
[0., 1., 1., 0.],
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
]))
|
|
|
|
|
vec![vec![1, 1], vec![1, 1]].into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_t() -> Self {
|
|
|
|
|
Self::from_mat3(Mat3::from_cols_array_2d(&[
|
|
|
|
|
[0., 1., 0.],
|
|
|
|
|
[1., 1., 1.],
|
|
|
|
|
[0., 0., 0.],
|
|
|
|
|
]))
|
|
|
|
|
vec![
|
|
|
|
|
vec![0, 1, 0],
|
|
|
|
|
vec![1, 1, 1],
|
|
|
|
|
vec![0, 0, 0]
|
|
|
|
|
].into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_l() -> Self {
|
|
|
|
|
Self::from_mat4(Mat4::from_cols_array_2d(&[
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
[0., 1., 0., 0.],
|
|
|
|
|
[0., 1., 0., 0.],
|
|
|
|
|
[0., 1., 1., 0.],
|
|
|
|
|
]))
|
|
|
|
|
vec![vec![1, 0], vec![1, 0], vec![1, 1]].into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_j() -> Self {
|
|
|
|
|
Self::from_mat4(Mat4::from_cols_array_2d(&[
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
[0., 0., 1., 0.],
|
|
|
|
|
[0., 0., 1., 0.],
|
|
|
|
|
[0., 1., 1., 0.],
|
|
|
|
|
]))
|
|
|
|
|
vec![vec![0, 1], vec![0, 1], vec![1, 1]].into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_s() -> Self {
|
|
|
|
|
Self::from_mat4(Mat4::from_cols_array_2d(&[
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
[0., 1., 1., 0.],
|
|
|
|
|
[1., 1., 0., 0.],
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
]))
|
|
|
|
|
vec![vec![0, 1, 1], vec![1, 1, 0]].into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_z() -> Self {
|
|
|
|
|
Self::from_mat4(Mat4::from_cols_array_2d(&[
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
[1., 1., 0., 0.],
|
|
|
|
|
[0., 1., 1., 0.],
|
|
|
|
|
[0., 0., 0., 0.],
|
|
|
|
|
]))
|
|
|
|
|
vec![vec![1, 1, 0], vec![0, 1, 1]].into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_i() -> Self {
|
|
|
|
|
Self::from_mat4(Mat4::from_cols_array_2d(&[
|
|
|
|
|
[0., 0., 1., 0.],
|
|
|
|
|
[0., 0., 1., 0.],
|
|
|
|
|
[0., 0., 1., 0.],
|
|
|
|
|
[0., 0., 1., 0.],
|
|
|
|
|
]))
|
|
|
|
|
vec![vec![1], vec![1], vec![1], vec![1]].into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rotates 90 degrees to the right
|
|
|
|
|
// https://stackoverflow.com/a/8664879
|
|
|
|
|
fn rotated(&self) -> Self {
|
|
|
|
|
match self {
|
|
|
|
|
Self::M4(inner) => {
|
|
|
|
|
let mut new_self = inner.transpose();
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let col = new_self.col_mut(i);
|
|
|
|
|
*col = Vec4::new(col[3], col[2], col[1], col[0]);
|
|
|
|
|
}
|
|
|
|
|
Self::M4(new_self)
|
|
|
|
|
}
|
|
|
|
|
Self::M3(inner) => {
|
|
|
|
|
let mut new_self = inner.transpose();
|
|
|
|
|
for i in 0..3 {
|
|
|
|
|
let col = new_self.col_mut(i);
|
|
|
|
|
*col = Vec3::new(col[2], col[1], col[0]);
|
|
|
|
|
}
|
|
|
|
|
Self::M3(new_self)
|
|
|
|
|
}
|
|
|
|
|
Self {
|
|
|
|
|
layout: self.layout.rotated(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn reposition(
|
|
|
|
|
(x_offset, y_offset): (isize, isize),
|
|
|
|
|
center: &GridPosition,
|
|
|
|
|
) -> Result<GridPosition, OutOfBoundsError> {
|
|
|
|
|
center.with_offset(x_offset, y_offset)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn coordinates(
|
|
|
|
|
&self,
|
|
|
|
|
center: &GridPosition,
|
|
|
|
|
) -> impl Iterator<Item = Result<GridPosition, OutOfBoundsError>> {
|
|
|
|
|
let mut v: Vec<Result<GridPosition, OutOfBoundsError>> = Vec::new();
|
|
|
|
|
match self {
|
|
|
|
|
Self::M4(inner) => {
|
|
|
|
|
for (i, y) in (-1..3).rev().enumerate() {
|
|
|
|
|
let c = inner.col(i);
|
|
|
|
|
for (j, x) in (-1..3).enumerate() {
|
|
|
|
|
if c[j] == 1.0 {
|
|
|
|
|
v.push(center.with_offset(x, y));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Self::M3(inner) => {
|
|
|
|
|
for (i, y) in (-1..2).rev().enumerate() {
|
|
|
|
|
let c = inner.col(i);
|
|
|
|
|
for (j, x) in (-1..2).enumerate() {
|
|
|
|
|
if c[j] == 1.0 {
|
|
|
|
|
v.push(center.with_offset(x, y));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
v.into_iter()
|
|
|
|
|
self.layout
|
|
|
|
|
.coordinates()
|
|
|
|
|
.map(|(x, y)| Shape::reposition((x, y), center))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn as_ascii(&self) -> String {
|
|
|
|
|
let mut output = String::default();
|
|
|
|
|
self.layout.as_ascii()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
Self::M4(this) => {
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let col = this.col(i).to_array();
|
|
|
|
|
output += format!("{}{}{}{}\n", col[0], col[1], col[2], col[3]).as_str();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Self::M3(this) => {
|
|
|
|
|
for i in 0..3 {
|
|
|
|
|
let col = this.col(i).to_array();
|
|
|
|
|
output += format!("{}{}{}\n", col[0], col[1], col[2]).as_str();
|
|
|
|
|
}
|
|
|
|
|
fn height(&self) -> usize {
|
|
|
|
|
self.layout.height()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
|
struct ShapeBlockLayout {
|
|
|
|
|
inner: Vec<Vec<u8>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ShapeBlockLayout {
|
|
|
|
|
fn rotated(&self) -> Self {
|
|
|
|
|
let mut inner = vec![];
|
|
|
|
|
for _ in 0..self.inner[0].len() {
|
|
|
|
|
inner.push(vec![]);
|
|
|
|
|
}
|
|
|
|
|
for y in self.inner.iter() {
|
|
|
|
|
for (j, x) in y.iter().enumerate() {
|
|
|
|
|
inner[j].insert(0, *x);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ShapeBlockLayout { inner }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn center(&self) -> (usize, usize) {
|
|
|
|
|
let mid_x = match self.inner[0].len() % 2 {
|
|
|
|
|
0 => (self.inner[0].len() - 1) / 2,
|
|
|
|
|
1 => self.inner[0].len() / 2,
|
|
|
|
|
|
|
|
|
|
_ => panic!("That's not how mod works!"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mid_y = match self.inner.len() % 2 {
|
|
|
|
|
// If we have an even number of elements
|
|
|
|
|
0 => self.inner.len().div_ceil(2),
|
|
|
|
|
// If we have an odd number of elements
|
|
|
|
|
1 => self.inner.len() / 2,
|
|
|
|
|
|
|
|
|
|
_ => panic!("That's not how mod works!"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
output
|
|
|
|
|
(mid_x, mid_y)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn height(&self) -> usize {
|
|
|
|
|
let mut x = 0;
|
|
|
|
|
fn coordinates(&self) -> impl Iterator<Item = (isize, isize)> {
|
|
|
|
|
let (mid_x, mid_y) = self.center();
|
|
|
|
|
// Loop over outer vec (i)
|
|
|
|
|
self.inner
|
|
|
|
|
.iter()
|
|
|
|
|
.rev()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.flat_map(move |(i, ys)| {
|
|
|
|
|
ys.iter().enumerate().filter_map(move |(j, val)| {
|
|
|
|
|
// this_x = j - mid_x
|
|
|
|
|
let x = j as isize - mid_x as isize;
|
|
|
|
|
// this_y = i - mid_y
|
|
|
|
|
let y = i as isize - mid_y as isize;
|
|
|
|
|
|
|
|
|
|
(*val > 0).then_some((x, y))
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
Self::M4(this) => {
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
if this.col(i).to_array().contains(&1.0) {
|
|
|
|
|
x += 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Self::M3(this) => {
|
|
|
|
|
for i in 0..3 {
|
|
|
|
|
if this.col(i).to_array().contains(&1.0) {
|
|
|
|
|
x += 1
|
|
|
|
|
}
|
|
|
|
|
// TODO: Make fnctional with chaining
|
|
|
|
|
fn as_ascii(&self) -> String {
|
|
|
|
|
let mut s = String::new();
|
|
|
|
|
for y in self.inner.iter() {
|
|
|
|
|
for x in y {
|
|
|
|
|
match x {
|
|
|
|
|
0 => s.push('0'),
|
|
|
|
|
1 => s.push('1'),
|
|
|
|
|
_ => panic!("aur nau"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
s.push('\n');
|
|
|
|
|
}
|
|
|
|
|
s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x
|
|
|
|
|
fn height(&self) -> usize {
|
|
|
|
|
self.inner.len()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1056,7 +1039,7 @@ fn movement(
|
|
|
|
|
MovementDirection::Down
|
|
|
|
|
| MovementDirection::Left
|
|
|
|
|
| MovementDirection::Right
|
|
|
|
|
| MovementDirection::Skip => *this_shape,
|
|
|
|
|
| MovementDirection::Skip => this_shape.clone(),
|
|
|
|
|
MovementDirection::Rotate => this_shape.rotated(),
|
|
|
|
|
};
|
|
|
|
|
debug!(
|
|
|
|
|
@ -1105,7 +1088,7 @@ fn movement(
|
|
|
|
|
|
|
|
|
|
// Update shape/rotation
|
|
|
|
|
let mut s = shape.get_mut(event.entity).unwrap();
|
|
|
|
|
*s = new_shape;
|
|
|
|
|
*s = new_shape.clone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1125,7 +1108,7 @@ fn swap(
|
|
|
|
|
None => {
|
|
|
|
|
// Copy current shape into store
|
|
|
|
|
// De-activate entity
|
|
|
|
|
store.0 = Some(*shapes.get(event.entity).unwrap());
|
|
|
|
|
store.0 = Some(shapes.get(event.entity).unwrap().clone());
|
|
|
|
|
commands
|
|
|
|
|
.entity(event.entity)
|
|
|
|
|
.despawn_related::<ShapeBlocks>()
|
|
|
|
|
|