grid symmetry helpers
This commit is contained in:
@@ -0,0 +1,110 @@
|
|||||||
|
use crate::config::SymmetryType;
|
||||||
|
|
||||||
|
pub fn mirror_coords(
|
||||||
|
row: usize,
|
||||||
|
col: usize,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
symmetry: SymmetryType,
|
||||||
|
) -> Vec<(usize, usize)> {
|
||||||
|
let mut coords = vec![(row, col)];
|
||||||
|
|
||||||
|
let mirror_row = |i: usize| height.checked_sub(1).and_then(|h| h.checked_sub(i));
|
||||||
|
let mirror_col = |i: usize| width.checked_sub(1).and_then(|w| w.checked_sub(i));
|
||||||
|
|
||||||
|
match symmetry {
|
||||||
|
SymmetryType::Rotational180 => {
|
||||||
|
if let (Some(mr), Some(mc)) = (mirror_row(row), mirror_col(col)) {
|
||||||
|
coords.push((mr, mc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymmetryType::Rotational90 => {
|
||||||
|
// each 90-degree image is kept only when it lands inside the grid,
|
||||||
|
// so non-square grids no longer underflow or go out of bounds
|
||||||
|
if let Some(mc) = mirror_col(row) {
|
||||||
|
if col < height {
|
||||||
|
coords.push((col, mc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let (Some(mr), Some(mc)) = (mirror_row(row), mirror_col(col)) {
|
||||||
|
coords.push((mr, mc));
|
||||||
|
}
|
||||||
|
if let Some(mr) = mirror_row(col) {
|
||||||
|
if row < width {
|
||||||
|
coords.push((mr, row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymmetryType::Diagonal => {
|
||||||
|
if width == height {
|
||||||
|
coords.push((col, row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymmetryType::Mirror => {
|
||||||
|
if let Some(mc) = mirror_col(col) {
|
||||||
|
coords.push((row, mc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymmetryType::None => {}
|
||||||
|
}
|
||||||
|
coords.sort();
|
||||||
|
coords.dedup();
|
||||||
|
coords
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rotational_180() {
|
||||||
|
let coords = mirror_coords(0, 0, 5, 5, SymmetryType::Rotational180);
|
||||||
|
assert_eq!(coords, vec![(0, 0), (4, 4)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rotational_180_center() {
|
||||||
|
let coords = mirror_coords(2, 2, 5, 5, SymmetryType::Rotational180);
|
||||||
|
assert_eq!(coords, vec![(2, 2)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rotational_90() {
|
||||||
|
let coords = mirror_coords(0, 1, 5, 5, SymmetryType::Rotational90);
|
||||||
|
assert!(coords.contains(&(0, 1)));
|
||||||
|
assert!(coords.contains(&(1, 4)));
|
||||||
|
assert!(coords.contains(&(4, 3)));
|
||||||
|
assert!(coords.contains(&(3, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mirror_lr() {
|
||||||
|
let coords = mirror_coords(1, 0, 5, 5, SymmetryType::Mirror);
|
||||||
|
assert_eq!(coords, vec![(1, 0), (1, 4)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn diagonal() {
|
||||||
|
let coords = mirror_coords(1, 3, 5, 5, SymmetryType::Diagonal);
|
||||||
|
assert_eq!(coords, vec![(1, 3), (3, 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rotational_90_non_square_stays_in_bounds() {
|
||||||
|
let coords = mirror_coords(0, 3, 5, 7, SymmetryType::Rotational90);
|
||||||
|
for (r, c) in &coords {
|
||||||
|
assert!(*r < 7 && *c < 5, "point ({}, {}) out of bounds", r, c);
|
||||||
|
}
|
||||||
|
assert!(coords.contains(&(0, 3)));
|
||||||
|
let coords2 = mirror_coords(6, 4, 5, 7, SymmetryType::Rotational90);
|
||||||
|
for (r, c) in &coords2 {
|
||||||
|
assert!(*r < 7 && *c < 5, "point ({}, {}) out of bounds", r, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_symmetry() {
|
||||||
|
let coords = mirror_coords(1, 2, 5, 5, SymmetryType::None);
|
||||||
|
assert_eq!(coords, vec![(1, 2)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user