Clean up code in mino-code-gen and make sure it is deterministic
This commit is contained in:
parent
0d52d6b1b5
commit
b5e20e14a2
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub fn compile_ruleset(in_path: impl AsRef<Path>, out_path: impl AsRef<Path>) -> Result<()> {
|
pub fn compile_ruleset(in_path: impl AsRef<Path>, out_path: impl AsRef<Path>) -> Result<()> {
|
||||||
|
@ -17,14 +17,13 @@ pub fn compile_ruleset(in_path: impl AsRef<Path>, out_path: impl AsRef<Path>) ->
|
||||||
/// Input data (JSON file)
|
/// Input data (JSON file)
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct RulesData {
|
struct RulesData {
|
||||||
shapes: BTreeMap<String, Vec<(i16, i16)>>,
|
shapes: HashMap<String, Vec<(i16, i16)>>,
|
||||||
kicks: BTreeMap<String, [Vec<(i16, i16)>; 4]>,
|
kicks: HashMap<String, [Vec<(i16, i16)>; 4]>,
|
||||||
spawn: (i16, i16),
|
spawn: (i16, i16),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Output data (Rust code)
|
/// Output data (Rust code)
|
||||||
struct RulesCode {
|
struct RulesCode {
|
||||||
// establish consistent mapping from shape name to integer
|
|
||||||
shape_indices: HashMap<String, usize>,
|
shape_indices: HashMap<String, usize>,
|
||||||
extents: Extents<Vec<i16>>,
|
extents: Extents<Vec<i16>>,
|
||||||
cells_bits: Vec<u16>,
|
cells_bits: Vec<u16>,
|
||||||
|
@ -43,15 +42,24 @@ struct Extents<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(rules: &RulesData) -> RulesCode {
|
fn compile(rules: &RulesData) -> RulesCode {
|
||||||
let shape_indices: HashMap<String, usize> = rules
|
let mut shape_names: Vec<&str> = rules.shapes.keys().map(String::as_str).collect();
|
||||||
.shapes
|
// ensure deterministic order
|
||||||
.keys()
|
shape_names.sort();
|
||||||
.enumerate()
|
|
||||||
.map(|(i, sh)| (sh.clone(), i))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let len_per_shape_rot = shape_indices.len() * 4;
|
// `kicks` is keyed by strings indicating multiple shape names, e.g. "LJSTZ" means
|
||||||
let len_per_shape_kicks = shape_indices.len() * 4 * 4;
|
// that this entry applies to each of those types. split the shape names into entries
|
||||||
|
// per shape for easier lookup.
|
||||||
|
let mut shapes_kicks: HashMap<String, [&[(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>();
|
||||||
|
let kicks = std::array::from_fn(|i| &kicks[i][..]);
|
||||||
|
shapes_kicks.insert(shape, kicks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let len_per_shape_rot = shape_names.len() * 4;
|
||||||
|
let len_per_shape_kicks = shape_names.len() * 16;
|
||||||
|
|
||||||
let mut extents = Extents {
|
let mut extents = Extents {
|
||||||
x0: vec![i16::MAX; len_per_shape_rot],
|
x0: vec![i16::MAX; len_per_shape_rot],
|
||||||
|
@ -60,22 +68,21 @@ fn compile(rules: &RulesData) -> RulesCode {
|
||||||
y1: vec![i16::MIN; len_per_shape_rot],
|
y1: vec![i16::MIN; len_per_shape_rot],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let shape_indices: HashMap<String, usize> = shape_names
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, &name)| (name.to_owned(), i))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut cells_bits = vec![];
|
let mut cells_bits = vec![];
|
||||||
let mut cells_indices = vec![usize::MAX; len_per_shape_rot];
|
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_tests = vec![];
|
||||||
let mut kicks_counts = vec![0; len_per_shape_kicks];
|
let mut kicks_counts = vec![0; len_per_shape_kicks];
|
||||||
let mut kicks_indices = vec![usize::MAX; len_per_shape_kicks];
|
let mut kicks_indices = vec![usize::MAX; len_per_shape_kicks];
|
||||||
|
|
||||||
for (shape, &i0) in shape_indices.iter() {
|
for &shape in shape_names.iter() {
|
||||||
|
let i0 = shape_indices.get(shape).unwrap();
|
||||||
let coords = rules.shapes.get(shape).unwrap();
|
let coords = rules.shapes.get(shape).unwrap();
|
||||||
for r in 0u8..4 {
|
for r in 0u8..4 {
|
||||||
let i = i0 * 4 + r as usize;
|
let i = i0 * 4 + r as usize;
|
||||||
|
@ -87,7 +94,7 @@ fn compile(rules: &RulesData) -> RulesCode {
|
||||||
cells_indices[i] = find_or_insert(&mut cells_bits, &data);
|
cells_indices[i] = find_or_insert(&mut cells_bits, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
let kicks = *shapes_kicks.get(shape).unwrap();
|
let kicks = shapes_kicks.get(shape).unwrap();
|
||||||
for r0 in 0u8..4 {
|
for r0 in 0u8..4 {
|
||||||
for r1 in 0u8..4 {
|
for r1 in 0u8..4 {
|
||||||
let i = i0 * 16 + r0 as usize * 4 + r1 as usize;
|
let i = i0 * 16 + r0 as usize * 4 + r1 as usize;
|
||||||
|
@ -142,16 +149,14 @@ fn rotate(x: i16, y: i16, r: u8) -> (i16, i16) {
|
||||||
xy
|
xy
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_kicks(kicks: &[Vec<(i16, i16)>; 4], r0: u8, r1: u8) -> Vec<(i16, i16)> {
|
fn process_kicks(kicks: &[&[(i16, i16)]], r0: u8, r1: u8) -> Vec<(i16, i16)> {
|
||||||
if r0 == r1 {
|
if r0 == r1 {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
|
let kicks0 = kicks[r0 as usize].iter();
|
||||||
let kicks0 = &kicks[r0 as usize];
|
let kicks1 = kicks[r1 as usize].iter();
|
||||||
let kicks1 = &kicks[r1 as usize];
|
|
||||||
kicks0
|
kicks0
|
||||||
.iter()
|
.zip(kicks1)
|
||||||
.zip(kicks1.iter())
|
|
||||||
.map(|(&(x0, y0), &(x1, y1))| (x0 - x1, y0 - y1))
|
.map(|(&(x0, y0), &(x1, y1))| (x0 - x1, y0 - y1))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue