grid symmetry helpers

This commit is contained in:
2025-03-24 19:50:43 +02:00
parent 2adeac6b99
commit 950c2772cd
+110
View File
@@ -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)]);
}
}