Implement SRS kicks code gen
This commit is contained in:
parent
6726326ec8
commit
4b9d10699f
|
@ -18,6 +18,7 @@ pub fn compile_ruleset(in_path: impl AsRef<Path>, out_path: impl AsRef<Path>) ->
|
|||
#[derive(serde::Deserialize)]
|
||||
struct RulesData {
|
||||
shapes: BTreeMap<String, Vec<(i16, i16)>>,
|
||||
kicks: BTreeMap<String, [Vec<(i16, i16)>; 4]>,
|
||||
}
|
||||
|
||||
/// Output data (Rust code)
|
||||
|
@ -27,6 +28,9 @@ struct RulesCode {
|
|||
extents: Extents<Vec<i16>>,
|
||||
cells_bits: Vec<u16>,
|
||||
cells_indices: Vec<usize>,
|
||||
kicks_tests: Vec<(i16, i16)>,
|
||||
kicks_counts: Vec<usize>,
|
||||
kicks_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
struct Extents<E> {
|
||||
|
@ -45,6 +49,7 @@ fn compile(rules: &RulesData) -> RulesCode {
|
|||
.collect();
|
||||
|
||||
let len_per_shape_rot = shape_indices.len() * 4;
|
||||
let len_per_shape_kicks = shape_indices.len() * 4 * 4;
|
||||
|
||||
let mut extents = Extents {
|
||||
x0: vec![i16::MAX; len_per_shape_rot],
|
||||
|
@ -56,6 +61,18 @@ fn compile(rules: &RulesData) -> RulesCode {
|
|||
let mut cells_bits = vec![];
|
||||
let mut cells_indices = vec![usize::MAX; len_per_shape_rot];
|
||||
|
||||
let mut shapes_kicks: HashMap<String, &[Vec<(i16, i16)>; 4]> = HashMap::new();
|
||||
for (shapes_string, kicks) in rules.kicks.iter() {
|
||||
for ch in shapes_string.chars() {
|
||||
let shape = std::iter::once(ch).collect::<String>();
|
||||
shapes_kicks.insert(shape, kicks);
|
||||
}
|
||||
}
|
||||
|
||||
let mut kicks_tests = vec![];
|
||||
let mut kicks_counts = vec![0; len_per_shape_kicks];
|
||||
let mut kicks_indices = vec![usize::MAX; len_per_shape_kicks];
|
||||
|
||||
for (shape, &i0) in shape_indices.iter() {
|
||||
let coords = rules.shapes.get(shape).unwrap();
|
||||
for r in 0u8..4 {
|
||||
|
@ -67,6 +84,16 @@ fn compile(rules: &RulesData) -> RulesCode {
|
|||
extents.y1[i] = exts.y1;
|
||||
cells_indices[i] = find_or_insert(&mut cells_bits, &data);
|
||||
}
|
||||
|
||||
let kicks = *shapes_kicks.get(shape).unwrap();
|
||||
for r0 in 0u8..4 {
|
||||
for r1 in 0u8..4 {
|
||||
let i = i0 * 16 + r0 as usize * 4 + r1 as usize;
|
||||
let tests = process_kicks(kicks, r0, r1);
|
||||
kicks_counts[i] = tests.len();
|
||||
kicks_indices[i] = find_or_insert(&mut kicks_tests, &tests);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RulesCode {
|
||||
|
@ -74,6 +101,9 @@ fn compile(rules: &RulesData) -> RulesCode {
|
|||
extents,
|
||||
cells_bits,
|
||||
cells_indices,
|
||||
kicks_tests,
|
||||
kicks_counts,
|
||||
kicks_indices,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,6 +139,20 @@ fn rotate(x: i16, y: i16, r: u8) -> (i16, i16) {
|
|||
xy
|
||||
}
|
||||
|
||||
fn process_kicks(kicks: &[Vec<(i16, i16)>; 4], r0: u8, r1: u8) -> Vec<(i16, i16)> {
|
||||
if r0 == r1 {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let kicks0 = &kicks[r0 as usize];
|
||||
let kicks1 = &kicks[r1 as usize];
|
||||
kicks0
|
||||
.iter()
|
||||
.zip(kicks1.iter())
|
||||
.map(|(&(x0, y0), &(x1, y1))| (x0 - x1, y0 - y1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Finds the first occurence of `needle` in `haystack`, or appends a suffix of it (up to
|
||||
/// the entire length), returning the index within `haystack` that now contains `needle`.
|
||||
fn find_or_insert<T: Eq + Copy>(haystack: &mut Vec<T>, needle: &[T]) -> usize {
|
||||
|
@ -150,6 +194,18 @@ impl RulesCode {
|
|||
let len = self.cells_indices.len();
|
||||
writeln!(out, "pub const CELLS_INDEX: [usize; {len}] = {arr:?};")?;
|
||||
|
||||
let arr = &self.kicks_tests;
|
||||
let len = self.kicks_tests.len();
|
||||
writeln!(out, "pub const KICKS_TESTS: [(i16, i16); {len}] = {arr:?};")?;
|
||||
|
||||
let arr = &self.kicks_counts;
|
||||
let len = self.kicks_counts.len();
|
||||
writeln!(out, "pub const KICKS_COUNT: [usize; {len}] = {arr:?};")?;
|
||||
|
||||
let arr = &self.kicks_indices;
|
||||
let len = self.kicks_indices.len();
|
||||
writeln!(out, "pub const KICKS_INDEX: [usize; {len}] = {arr:?};")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Implementation of SRS shapes and movement quirks.
|
||||
|
||||
use crate::input::Kicks as KicksTrait;
|
||||
use crate::piece::{Cells, Rot, Shape as ShapeTrait};
|
||||
|
||||
mod code_gen {
|
||||
|
@ -29,12 +30,23 @@ impl ShapeTrait<'static> for Shape {
|
|||
}
|
||||
}
|
||||
|
||||
impl KicksTrait<'static> for Shape {
|
||||
fn kicks(&self, r0: Rot, r1: Rot) -> &'static [(i16, i16)] {
|
||||
let i = (*self as usize) * 16 + (r0 as usize) * 4 + r1 as usize;
|
||||
let idx = code_gen::KICKS_INDEX[i];
|
||||
let len = code_gen::KICKS_COUNT[i];
|
||||
&code_gen::KICKS_TESTS[idx..idx + len]
|
||||
}
|
||||
}
|
||||
|
||||
pub type Piece = crate::piece::Piece<Shape>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::matrix::Mat;
|
||||
use crate::piece::Loc;
|
||||
use crate::{input, mat};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Range;
|
||||
|
@ -90,4 +102,74 @@ mod test {
|
|||
test_cells_all_rotations(Shape::T, &[(0, 1), (-1, 0), (0, 0), (1, 0)]);
|
||||
test_cells_all_rotations(Shape::Z, &[(1, 0), (0, 0), (0, 1), (-1, 1)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_srs_o_kicks_in_place() {
|
||||
use input::Spin::*;
|
||||
let mut piece = Piece {
|
||||
shape: Shape::O,
|
||||
loc: Loc {
|
||||
x: 6,
|
||||
y: 6,
|
||||
r: Rot::N,
|
||||
},
|
||||
};
|
||||
assert_eq!(input::rotate(&mut piece, Mat::EMPTY, Cw), Some(0));
|
||||
assert_eq!(piece.loc.x, 6);
|
||||
assert_eq!(piece.loc.y, 7);
|
||||
assert_eq!(input::rotate(&mut piece, Mat::EMPTY, Cw), Some(0));
|
||||
assert_eq!(piece.loc.x, 7);
|
||||
assert_eq!(piece.loc.y, 7);
|
||||
assert_eq!(input::rotate(&mut piece, Mat::EMPTY, Cw), Some(0));
|
||||
assert_eq!(piece.loc.x, 7);
|
||||
assert_eq!(piece.loc.y, 6);
|
||||
assert_eq!(input::rotate(&mut piece, Mat::EMPTY, Cw), Some(0));
|
||||
assert_eq!(piece.loc.x, 6);
|
||||
assert_eq!(piece.loc.y, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_srs_t_spin_triple() {
|
||||
const SETUP: &Mat = mat! {
|
||||
"......xx..";
|
||||
".......x..";
|
||||
"xxxxxx.xxx";
|
||||
"xxxxx..xxx";
|
||||
"xxxxxx.xxx";
|
||||
};
|
||||
let mut piece = Piece {
|
||||
shape: Shape::T,
|
||||
loc: Loc {
|
||||
x: 5,
|
||||
y: 3,
|
||||
r: Rot::N,
|
||||
},
|
||||
};
|
||||
assert_eq!(input::rotate(&mut piece, SETUP, input::Spin::Ccw), Some(4));
|
||||
assert_eq!(piece.loc.x, 6);
|
||||
assert_eq!(piece.loc.y, 1);
|
||||
assert_eq!(piece.loc.r, Rot::W);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_srs_z_spin_triple() {
|
||||
const SETUP: &Mat = mat! {
|
||||
"....x.....";
|
||||
"xxxxxx.xxx";
|
||||
"xxxxx..xxx";
|
||||
"xxxxx.xxxx";
|
||||
};
|
||||
let mut piece = Piece {
|
||||
shape: Shape::Z,
|
||||
loc: Loc {
|
||||
x: 5,
|
||||
y: 3,
|
||||
r: Rot::N,
|
||||
},
|
||||
};
|
||||
assert_eq!(input::rotate(&mut piece, SETUP, input::Spin::Cw), Some(3));
|
||||
assert_eq!(piece.loc.x, 5);
|
||||
assert_eq!(piece.loc.y, 1);
|
||||
assert_eq!(piece.loc.r, Rot::E);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue