use crate::morph::{MorphResult, Sel};
const SEL_4_1: &str = " x\noCx\n x";
const SEL_4_2: &str = " x\noCx\n o ";
const SEL_4_3: &str = " o \noCx\n x";
const SEL_4_4: &str = " o \noCx\n o ";
const SEL_4_5: &str = " ox\noCx\n o ";
const SEL_4_6: &str = " o \noCx\n ox";
const SEL_4_7: &str = " xx\noCx\n o ";
const SEL_4_8: &str = " x\noCx\no x";
const SEL_4_9: &str = "o x\noCx\n x";
const SEL_8_1: &str = " x \noCx\n x ";
const SEL_8_2: &str = " x \noCx\no ";
const SEL_8_3: &str = "o \noCx\n x ";
const SEL_8_4: &str = "o \noCx\no ";
const SEL_8_5: &str = "o x\noCx\no ";
const SEL_8_6: &str = "o \noCx\no x";
const SEL_8_7: &str = " x \noCx\noo ";
const SEL_8_8: &str = " x \noCx\nox ";
const SEL_8_9: &str = "ox \noCx\n x ";
const SEL_48_1: &str = " xx\noCx\noo ";
const SEL_48_2: &str = "o x\noCx\no x";
fn sel_from_thin_pattern(pattern: &str, name: &str) -> MorphResult<Sel> {
let lines: Vec<&str> = pattern.lines().collect();
let height = lines.len() as u32;
let width = lines.iter().map(|l| l.len()).max().unwrap_or(0) as u32;
let mut sel = Sel::new(width, height)?;
let mut cx = width / 2;
let mut cy = height / 2;
for (y, line) in lines.iter().enumerate() {
for (x, ch) in line.chars().enumerate() {
if ch == 'C' || ch == 'c' {
cx = x as u32;
cy = y as u32;
}
}
}
sel.set_origin(cx, cy)?;
for (y, line) in lines.iter().enumerate() {
for (x, ch) in line.chars().enumerate() {
let elem = match ch {
'x' | 'X' | 'C' | 'c' => crate::morph::SelElement::Hit,
'o' | 'O' => crate::morph::SelElement::Miss,
_ => crate::morph::SelElement::DontCare,
};
sel.set_element(x as u32, y as u32, elem);
}
}
sel.set_name(name);
Ok(sel)
}
pub fn sels_4cc_thin() -> Vec<Sel> {
vec![
sel_from_thin_pattern(SEL_4_1, "sel_4_1").unwrap(),
sel_from_thin_pattern(SEL_4_2, "sel_4_2").unwrap(),
sel_from_thin_pattern(SEL_4_3, "sel_4_3").unwrap(),
sel_from_thin_pattern(SEL_4_4, "sel_4_4").unwrap(),
sel_from_thin_pattern(SEL_4_5, "sel_4_5").unwrap(),
sel_from_thin_pattern(SEL_4_6, "sel_4_6").unwrap(),
sel_from_thin_pattern(SEL_4_7, "sel_4_7").unwrap(),
sel_from_thin_pattern(SEL_4_8, "sel_4_8").unwrap(),
sel_from_thin_pattern(SEL_4_9, "sel_4_9").unwrap(),
]
}
pub fn sels_8cc_thin() -> Vec<Sel> {
vec![
sel_from_thin_pattern(SEL_8_1, "sel_8_1").unwrap(),
sel_from_thin_pattern(SEL_8_2, "sel_8_2").unwrap(),
sel_from_thin_pattern(SEL_8_3, "sel_8_3").unwrap(),
sel_from_thin_pattern(SEL_8_4, "sel_8_4").unwrap(),
sel_from_thin_pattern(SEL_8_5, "sel_8_5").unwrap(),
sel_from_thin_pattern(SEL_8_6, "sel_8_6").unwrap(),
sel_from_thin_pattern(SEL_8_7, "sel_8_7").unwrap(),
sel_from_thin_pattern(SEL_8_8, "sel_8_8").unwrap(),
sel_from_thin_pattern(SEL_8_9, "sel_8_9").unwrap(),
]
}
pub fn sels_4and8cc_thin() -> Vec<Sel> {
vec![
sel_from_thin_pattern(SEL_48_1, "sel_48_1").unwrap(),
sel_from_thin_pattern(SEL_48_2, "sel_48_2").unwrap(),
]
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ThinSelSet {
Set4cc1 = 1,
Set4cc2 = 2,
Set4cc3 = 3,
Set48 = 4,
Set8cc1 = 5,
Set8cc2 = 6,
Set8cc3 = 7,
Set8cc4 = 8,
Set8cc5 = 9,
Thicken4cc = 10,
Thicken8cc = 11,
}
pub fn make_thin_sels(set: ThinSelSet) -> Vec<Sel> {
let sels_4cc = sels_4cc_thin();
let sels_8cc = sels_8cc_thin();
let sels_48cc = sels_4and8cc_thin();
match set {
ThinSelSet::Set4cc1 => {
vec![
sels_4cc[0].clone(),
sels_4cc[1].clone(),
sels_4cc[2].clone(),
]
}
ThinSelSet::Set4cc2 => {
vec![
sels_4cc[0].clone(),
sels_4cc[4].clone(),
sels_4cc[5].clone(),
]
}
ThinSelSet::Set4cc3 => {
let sel_4_7_rot = sels_4cc[6].rotate_orth(1);
vec![sels_4cc[0].clone(), sels_4cc[6].clone(), sel_4_7_rot]
}
ThinSelSet::Set48 => {
let sel_48_1_rot = sels_48cc[0].rotate_orth(1);
vec![sels_48cc[0].clone(), sel_48_1_rot, sels_48cc[1].clone()]
}
ThinSelSet::Set8cc1 => {
vec![
sels_8cc[1].clone(),
sels_8cc[2].clone(),
sels_8cc[4].clone(),
sels_8cc[5].clone(),
]
}
ThinSelSet::Set8cc2 => {
vec![
sels_8cc[1].clone(),
sels_8cc[2].clone(),
sels_48cc[1].clone(),
]
}
ThinSelSet::Set8cc3 => {
vec![
sels_8cc[0].clone(),
sels_8cc[4].clone(),
sels_8cc[5].clone(),
]
}
ThinSelSet::Set8cc4 => {
vec![
sels_8cc[1].clone(),
sels_8cc[2].clone(),
sels_8cc[7].clone(),
sels_8cc[8].clone(),
]
}
ThinSelSet::Set8cc5 => {
let sel_8_7_rot = sels_8cc[6].rotate_orth(1);
vec![
sels_8cc[4].clone(),
sels_8cc[5].clone(),
sels_8cc[6].clone(),
sel_8_7_rot,
]
}
ThinSelSet::Thicken4cc => {
vec![sels_4cc[1].clone(), sels_4cc[2].clone()]
}
ThinSelSet::Thicken8cc => {
vec![sels_8cc[3].clone()]
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sels_4cc_thin() {
let sels = sels_4cc_thin();
assert_eq!(sels.len(), 9);
let sel = &sels[0];
assert_eq!(sel.width(), 3);
assert_eq!(sel.height(), 3);
assert_eq!(sel.origin_x(), 1);
assert_eq!(sel.origin_y(), 1);
assert_eq!(sel.name(), Some("sel_4_1"));
}
#[test]
fn test_sels_8cc_thin() {
let sels = sels_8cc_thin();
assert_eq!(sels.len(), 9);
let sel = &sels[0];
assert_eq!(sel.width(), 3);
assert_eq!(sel.height(), 3);
assert_eq!(sel.name(), Some("sel_8_1"));
}
#[test]
fn test_sels_4and8cc_thin() {
let sels = sels_4and8cc_thin();
assert_eq!(sels.len(), 2);
}
#[test]
fn test_make_thin_sels_set1() {
let sels = make_thin_sels(ThinSelSet::Set4cc1);
assert_eq!(sels.len(), 3);
assert_eq!(sels[0].name(), Some("sel_4_1"));
assert_eq!(sels[1].name(), Some("sel_4_2"));
assert_eq!(sels[2].name(), Some("sel_4_3"));
}
#[test]
fn test_make_thin_sels_set5() {
let sels = make_thin_sels(ThinSelSet::Set8cc1);
assert_eq!(sels.len(), 4);
assert_eq!(sels[0].name(), Some("sel_8_2"));
assert_eq!(sels[1].name(), Some("sel_8_3"));
assert_eq!(sels[2].name(), Some("sel_8_5"));
assert_eq!(sels[3].name(), Some("sel_8_6"));
}
#[test]
fn test_make_thin_sels_with_rotation() {
let sels = make_thin_sels(ThinSelSet::Set4cc3);
assert_eq!(sels.len(), 3);
assert_eq!(sels[0].name(), Some("sel_4_1"));
assert_eq!(sels[1].name(), Some("sel_4_7"));
assert!(sels[2].name().unwrap().contains("rot"));
}
#[test]
fn test_sel_pattern_correctness() {
let sels = sels_4cc_thin();
let sel = &sels[0];
assert_eq!(sel.get_element(1, 1), Some(crate::morph::SelElement::Hit));
assert_eq!(sel.get_element(0, 1), Some(crate::morph::SelElement::Miss));
assert_eq!(sel.get_element(2, 1), Some(crate::morph::SelElement::Hit));
assert_eq!(sel.get_element(2, 0), Some(crate::morph::SelElement::Hit));
assert_eq!(sel.get_element(2, 2), Some(crate::morph::SelElement::Hit));
}
}