Rotation works!

main
Elijah Voigt 2 months ago
parent 92ee8c7598
commit 62d24bec0e

@ -65,7 +65,7 @@ const Y_MAX: usize = 20;
/// Stores shape data in an asset file, likely toml /// Stores shape data in an asset file, likely toml
#[derive(Asset, TypePath, Debug, Deserialize)] #[derive(Asset, TypePath, Debug, Deserialize)]
struct ShapeAsset { struct ShapeAsset {
layout: ShapeLayout, layout: Vec<Vec<u8>>,
#[serde(default = "default_tint")] #[serde(default = "default_tint")]
tint: String, tint: String,
#[serde(skip)] #[serde(skip)]
@ -81,11 +81,12 @@ fn default_tint() -> String {
impl ShapeAsset { impl ShapeAsset {
fn as_bundle(&self) -> impl Bundle { fn as_bundle(&self) -> impl Bundle {
// Get shape block's relative positions // Get shape block's relative positions
let [a, b, c, d] = self.layout.positions(); let layout = ShapeLayout::new(self.layout.clone());
let [a, b, c, d] = layout.positions(Orientation::Up);
( (
GridPosition { x: 5, y: 5 }, // TEMP GridPosition { x: 5, y: 5 }, // TEMP
self.layout.clone(), layout.clone(),
Orientation::Up, Orientation::Up,
related!(ShapeBlocks[ related!(ShapeBlocks[
(self.mesh.clone(), self.material.clone(), a), (self.mesh.clone(), self.material.clone(), a),
@ -168,30 +169,58 @@ impl From<(isize, isize)> for RelativePosition {
/// Layout for a given shape /// Layout for a given shape
#[derive(Debug, Component, Deserialize, PartialEq, Clone)] #[derive(Debug, Component, Deserialize, PartialEq, Clone)]
pub(crate) struct ShapeLayout(pub Vec<Vec<u8>>); pub(crate) struct ShapeLayout {
pub matrix: Vec<Vec<u8>>,
#[serde(skip)]
symmetrical: bool,
}
impl ShapeLayout { impl ShapeLayout {
pub(crate) fn positions(&self) -> [RelativePosition; 4] { pub(crate) fn new(matrix: Vec<Vec<u8>>) -> Self {
let mut s = Self {
matrix,
symmetrical: true,
};
// Check if symmetrical
s.symmetrical = s.matrix == s.rotated_matrix(Orientation::Down);
s
}
pub(crate) fn positions(&self, o: Orientation) -> [RelativePosition; 4] {
let mut c: Vec<RelativePosition> = Vec::with_capacity(4); let mut c: Vec<RelativePosition> = Vec::with_capacity(4);
let layout = self.rotated_matrix(o);
let center: (isize, isize) = { let center: (isize, isize) = {
// This could be less lines of code but it would be confusing af // This could be less lines of code but it would be confusing af
let y = if self.0.len() % 2 == 1 { let y = if layout.len() % 2 == 1 {
self.0.len() / 2 layout.len() / 2
} else { } else {
self.0.len() / 2 - 1 layout.len() / 2 - 1
}; };
let x = if self.0[0].len() % 2 == 1 { let x = if layout[0].len() % 2 == 1 {
self.0[0].len() / 2 layout[0].len() / 2
} else { } else {
self.0[0].len() / 2 - 1 layout[0].len() / 2 - 1
}; };
(x as isize, y as isize) let (x_off, y_off) = match self.symmetrical {
true => (0, 0),
false => match o {
Orientation::Up => (0, 0),
Orientation::Right => (0, 0),
Orientation::Down => (0, 1),
Orientation::Left => (1, 0),
},
}; };
for (y, nested) in self.0.iter().rev().enumerate() { (x_off + x as isize, y_off + y as isize)
};
for (y, nested) in layout.iter().rev().enumerate() {
for (x, val) in nested.iter().enumerate() { for (x, val) in nested.iter().enumerate() {
if *val == 1 { if *val == 1 {
c.push(RelativePosition { c.push(RelativePosition {
@ -205,40 +234,52 @@ impl ShapeLayout {
[c[0], c[1], c[2], c[3]] [c[0], c[1], c[2], c[3]]
} }
pub(crate) fn rotated(&self, o: Orientation) -> Self { pub(crate) fn rotated_matrix(&self, o: Orientation) -> Vec<Vec<u8>> {
info!("Rotation: {:?} {:?}", o, self);
// Now we have the base layout, rotate it based on orientation // Now we have the base layout, rotate it based on orientation
match o { match o {
Orientation::Up => { Orientation::Up => {
// The identity // The identity
self.clone() self.matrix.clone()
} }
Orientation::Right => { Orientation::Right => {
// The main algorithm // The main algorithm
let cols = self.0[0].len(); let cols = self.matrix[0].len();
let rows = self.0.len(); let rows = self.matrix.len();
let mut rotated = vec![vec![0;rows];cols]; let mut rotated = vec![vec![0; rows]; cols];
// (i, j) -> (j,rows-1-i) // (i, j) -> (j,rows-1-i)
for i in 0..rows { for i in 0..rows {
for j in 0..cols { for j in 0..cols {
rotated[j][rows - 1 - i] = self.0[i][j]; rotated[j][rows - 1 - i] = self.matrix[i][j];
} }
} }
ShapeLayout(rotated) rotated
} }
Orientation::Down => { Orientation::Down => {
// Implemented as repeated turns right // HACK: Implemented as repeated turns right
self.rotated(Orientation::Right) // TODO: Just hard-code this
.rotated(Orientation::Right) ShapeLayout {
matrix: self.rotated_matrix(Orientation::Right),
symmetrical: false
}.rotated_matrix(Orientation::Right)
} }
Orientation::Left => { Orientation::Left => {
// Implemented as repeated turns right // The main algorithm
self.rotated(Orientation::Right) let cols = self.matrix[0].len();
.rotated(Orientation::Right) let rows = self.matrix.len();
.rotated(Orientation::Right)
let mut rotated = vec![vec![0; rows]; cols];
// (i, j) -> (cols-1-j,i)
for i in 0..rows {
for j in 0..cols {
rotated[cols - 1 - j][i] = self.matrix[i][j];
}
}
rotated
} }
} }
} }
@ -391,7 +432,6 @@ fn update_grid_position_transform(
>, >,
) { ) {
query.iter_mut().for_each(|(gp, mut t)| { query.iter_mut().for_each(|(gp, mut t)| {
info!("Updating grid position to {:?}", gp);
t.translation = gp.into(); t.translation = gp.into();
}); });
} }
@ -415,7 +455,7 @@ fn propogate_orientation(
mut children: Query<&mut GridPosition, Without<ShapeBlocks>>, mut children: Query<&mut GridPosition, Without<ShapeBlocks>>,
) { ) {
parent.iter().for_each(|(parent_gp, parent_o, sl, sbs)| { parent.iter().for_each(|(parent_gp, parent_o, sl, sbs)| {
let new_layout = sl.rotated(*parent_o).positions(); let new_layout = sl.positions(*parent_o);
sbs.iter().zip(new_layout).for_each(|(e, rp)| { sbs.iter().zip(new_layout).for_each(|(e, rp)| {
let mut gp = children.get_mut(e).unwrap(); let mut gp = children.get_mut(e).unwrap();
@ -491,25 +531,25 @@ fn handle_movement(
moves.read().for_each(|m| match m { moves.read().for_each(|m| match m {
Movement::Left => { Movement::Left => {
grid_positions.iter_mut().for_each(|mut gp| { grid_positions.iter_mut().for_each(|mut gp| {
info!("moving shape left"); debug!("moving shape left");
*gp -= RelativePosition::new(1, 0); *gp -= RelativePosition::new(1, 0);
}); });
} }
Movement::Right => { Movement::Right => {
grid_positions.iter_mut().for_each(|mut gp| { grid_positions.iter_mut().for_each(|mut gp| {
info!("moving shape right"); debug!("moving shape right");
*gp += RelativePosition::new(1, 0); *gp += RelativePosition::new(1, 0);
}); });
} }
Movement::Down => { Movement::Down => {
grid_positions.iter_mut().for_each(|mut gp| { grid_positions.iter_mut().for_each(|mut gp| {
info!("moving shape down"); debug!("moving shape down");
*gp -= RelativePosition::new(0, 1); *gp -= RelativePosition::new(0, 1);
}); });
} }
Movement::Rotate => { Movement::Rotate => {
orientations.iter_mut().for_each(|mut o| { orientations.iter_mut().for_each(|mut o| {
info!("rotating shape"); debug!("rotating shape");
*o = o.rotated(); *o = o.rotated();
}); });
} }

@ -2,7 +2,7 @@ use super::*;
#[test] #[test]
fn test_shape_layout_01a() { fn test_shape_layout_01a() {
let actual = ShapeLayout(vec![vec![0, 1, 0], vec![1, 1, 1]]).positions(); let actual = ShapeLayout::new(vec![vec![0, 1, 0], vec![1, 1, 1]]).positions(Orientation::Up);
let expected: [RelativePosition; 4] = let expected: [RelativePosition; 4] =
[(-1, 0).into(), (0, 0).into(), (1, 0).into(), (0, 1).into()]; [(-1, 0).into(), (0, 0).into(), (1, 0).into(), (0, 1).into()];
@ -12,7 +12,8 @@ fn test_shape_layout_01a() {
#[test] #[test]
fn test_shape_layout_01b() { fn test_shape_layout_01b() {
let actual = ShapeLayout(vec![vec![1, 0], vec![1, 1], vec![1, 0]]).positions(); let actual =
ShapeLayout::new(vec![vec![1, 0], vec![1, 1], vec![1, 0]]).positions(Orientation::Up);
let expected: [RelativePosition; 4] = let expected: [RelativePosition; 4] =
[(0, -1).into(), (0, 0).into(), (1, 0).into(), (0, 1).into()]; [(0, -1).into(), (0, 0).into(), (1, 0).into(), (0, 1).into()];
@ -20,9 +21,20 @@ fn test_shape_layout_01b() {
debug_assert_eq!(expected, actual); debug_assert_eq!(expected, actual);
} }
#[test]
fn test_shape_layout_01c() {
let actual = ShapeLayout::new(vec![vec![0, 1, 0], vec![1, 1, 1]]).positions(Orientation::Down);
let expected: [RelativePosition; 4] =
[(0, -1).into(), (-1, 0).into(), (0, 0).into(), (1, 0).into(),];
debug_assert_eq!(expected, actual);
}
#[test] #[test]
fn test_shape_layout_02a() { fn test_shape_layout_02a() {
let actual = ShapeLayout(vec![vec![1], vec![1], vec![1], vec![1]]).positions(); let actual =
ShapeLayout::new(vec![vec![1], vec![1], vec![1], vec![1]]).positions(Orientation::Up);
let expected: [RelativePosition; 4] = let expected: [RelativePosition; 4] =
[(0, -1).into(), (0, 0).into(), (0, 1).into(), (0, 2).into()]; [(0, -1).into(), (0, 0).into(), (0, 1).into(), (0, 2).into()];
@ -32,7 +44,7 @@ fn test_shape_layout_02a() {
#[test] #[test]
fn test_shape_layout_02b() { fn test_shape_layout_02b() {
let actual = ShapeLayout(vec![vec![1, 1, 1, 1]]).positions(); let actual = ShapeLayout::new(vec![vec![1, 1, 1, 1]]).positions(Orientation::Up);
let expected: [RelativePosition; 4] = let expected: [RelativePosition; 4] =
[(-1, 0).into(), (0, 0).into(), (1, 0).into(), (2, 0).into()]; [(-1, 0).into(), (0, 0).into(), (1, 0).into(), (2, 0).into()];
@ -42,7 +54,7 @@ fn test_shape_layout_02b() {
#[test] #[test]
fn test_shape_layout_03() { fn test_shape_layout_03() {
let actual = ShapeLayout(vec![vec![1, 1, 0], vec![0, 1, 1]]).positions(); let actual = ShapeLayout::new(vec![vec![1, 1, 0], vec![0, 1, 1]]).positions(Orientation::Up);
let expected: [RelativePosition; 4] = let expected: [RelativePosition; 4] =
[(0, 0).into(), (1, 0).into(), (-1, 1).into(), (0, 1).into()]; [(0, 0).into(), (1, 0).into(), (-1, 1).into(), (0, 1).into()];
@ -52,28 +64,29 @@ fn test_shape_layout_03() {
#[test] #[test]
fn test_rotation_01() { fn test_rotation_01() {
let actual = ShapeLayout(vec![vec![1], vec![1], vec![1], vec![1]]).rotated(Orientation::Left); let actual =
ShapeLayout::new(vec![vec![1], vec![1], vec![1], vec![1]]).positions(Orientation::Left);
let expected = ShapeLayout(vec![vec![1, 1, 1, 1]]); let expected = ShapeLayout::new(vec![vec![1, 1, 1, 1]]).positions(Orientation::Up);
debug_assert_eq!(expected, actual); debug_assert_eq!(expected, actual);
} }
#[test] #[test]
fn test_rotation_02() { fn test_rotation_02() {
let base = ShapeLayout(vec![vec![0, 1, 0], vec![1, 1, 1]]); let base = ShapeLayout::new(vec![vec![0, 1, 0], vec![1, 1, 1]]);
let expected_up = base.clone(); let expected_up = base.matrix.clone();
let actual_up = base.rotated(Orientation::Up); let actual_up = base.rotated_matrix(Orientation::Up);
let expected_down = ShapeLayout(vec![vec![1, 1, 1], vec![0, 1, 0]]); let expected_down = ShapeLayout::new(vec![vec![1, 1, 1], vec![0, 1, 0]]).matrix;
let actual_down = base.rotated(Orientation::Down); let actual_down = base.rotated_matrix(Orientation::Down);
let expected_right = ShapeLayout(vec![vec![1, 0], vec![1, 1], vec![1, 0]]); let expected_right = ShapeLayout::new(vec![vec![1, 0], vec![1, 1], vec![1, 0]]).matrix;
let actual_right = base.rotated(Orientation::Right); let actual_right = base.rotated_matrix(Orientation::Right);
let expected_left = ShapeLayout(vec![vec![0, 1], vec![1, 1], vec![0, 1]]); let expected_left = ShapeLayout::new(vec![vec![0, 1], vec![1, 1], vec![0, 1]]).matrix;
let actual_left = base.rotated(Orientation::Left); let actual_left = base.rotated_matrix(Orientation::Left);
debug_assert_eq!(expected_up, actual_up); debug_assert_eq!(expected_up, actual_up);
debug_assert_eq!(expected_down, actual_down); debug_assert_eq!(expected_down, actual_down);
@ -83,11 +96,10 @@ fn test_rotation_02() {
#[test] #[test]
fn test_rotation_03() { fn test_rotation_03() {
let base = ShapeLayout(vec![vec![0, 1, 0], vec![1, 1, 1]]); let base = ShapeLayout::new(vec![vec![0, 1, 0], vec![1, 1, 1]]);
let actual_right = base.rotated(Orientation::Right); let actual_right = base.rotated_matrix(Orientation::Right);
let expected_right = ShapeLayout(vec![vec![1, 0], vec![1, 1], vec![1, 0]]); let expected_right = ShapeLayout::new(vec![vec![1, 0], vec![1, 1], vec![1, 0]]).matrix;
debug_assert_eq!(expected_right, actual_right); debug_assert_eq!(expected_right, actual_right);
} }

Loading…
Cancel
Save