use super::angles::upscale_angles;
use super::snake::Snake;
use crate::cyclotomic::{HasZZ4, HasZZ6, HasZZ10, HasZZ12};
pub fn square<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[1, 1, 1, 1]).as_slice()).unwrap()
}
pub fn triangle<T: HasZZ6>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(6, &[2, 2, 2]).as_slice()).unwrap()
}
pub fn hexagon<T: HasZZ6>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(6, &[1, 1, 1, 1, 1, 1]).as_slice()).unwrap()
}
pub fn spectre<T: HasZZ12>() -> Snake<T> {
Snake::try_from(
upscale_angles::<T>(12, &[3, 2, 0, 2, -3, 2, 3, 2, -3, 2, 3, -2, 3, -2]).as_slice(),
)
.unwrap()
}
pub fn penrose_p3_narrow<T: HasZZ10>() -> Snake<T> {
let seq: &[i8] = &[
4, 1, -2, 1, 1, -1, 2, -1, 4, 0, 2, -4, 2, 1, -2, 4, -2, 0, ];
Snake::try_from(upscale_angles::<T>(10, seq).as_slice()).unwrap()
}
pub fn penrose_p3_wide<T: HasZZ10>() -> Snake<T> {
let seq: &[i8] = &[
3, 0, 2, -4, 2, 2, 1, -2, 1, 3, -1, 2, -1, 2, -2, 4, -2, 0, ];
Snake::try_from(upscale_angles::<T>(10, seq).as_slice()).unwrap()
}
#[allow(non_snake_case)]
pub fn tetromino_O<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[0, 1, 0, 1, 0, 1, 0, 1]).as_slice()).unwrap()
}
#[allow(non_snake_case)]
pub fn tetromino_I<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[0, 0, 0, 1, 1, 0, 0, 0, 1, 1]).as_slice()).unwrap()
}
#[allow(non_snake_case)]
pub fn tetromino_T<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[-1, 1, 1, -1, 1, 1, 0, 0, 1, 1]).as_slice()).unwrap()
}
#[allow(non_snake_case)]
pub fn tetromino_S<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[-1, 1, 1, 0, 1, -1, 1, 1, 0, 1]).as_slice()).unwrap()
}
#[allow(non_snake_case)]
pub fn tetromino_Z<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[-1, 1, 0, 1, 1, -1, 1, 0, 1, 1]).as_slice()).unwrap()
}
#[allow(non_snake_case)]
pub fn tetromino_J<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[-1, 1, 1, 0, 1, 0, 0, 1, 1, 0]).as_slice()).unwrap()
}
#[allow(non_snake_case)]
pub fn tetromino_L<T: HasZZ4>() -> Snake<T> {
Snake::try_from(upscale_angles::<T>(4, &[-1, 0, 1, 1, 0, 0, 1, 0, 1, 1]).as_slice()).unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cyclotomic::{ZZ10, ZZ24};
use crate::geom::rat::Rat;
#[test]
fn test_upscaling() {
let seq_zz24: Vec<i8> = vec![6, 4, 0, 4, -6, 4, 6, 4, -6, 4, 6, -4, 6, -4];
let s: Snake<ZZ24> = spectre();
assert_eq!(s.angles(), seq_zz24);
}
#[test]
fn test_penrose() {
let fat: Rat<ZZ10> = Rat::try_from(&penrose_p3_wide()).unwrap();
let thin: Rat<ZZ10> = Rat::try_from(&penrose_p3_narrow()).unwrap();
assert_eq!(fat.len(), 18);
assert_eq!(thin.len(), 18);
fn marking(seq: &[i8], starts: &[usize]) -> Vec<(char, i8)> {
let n = seq.len();
(0..starts.len())
.map(|k| {
let interior = &seq[starts[k] + 1..*starts.get(k + 1).unwrap_or(&n)];
let ty = interior.iter().map(|t| t.abs()).max().unwrap() / 2;
let first = *interior.iter().find(|&&t| t != 0).unwrap();
(if first < 0 { '+' } else { '-' }, ty)
})
.collect()
}
assert_eq!(
marking(penrose_p3_narrow::<ZZ10>().angles(), &[0, 4, 8, 13]),
[('-', 1), ('+', 1), ('-', 2), ('+', 2)]
);
assert_eq!(
marking(penrose_p3_wide::<ZZ10>().angles(), &[0, 5, 9, 13]),
[('-', 2), ('-', 1), ('+', 1), ('+', 2)]
);
for t in [&fat, &thin] {
assert!(t.seq().iter().any(|&a| a.abs() == 4));
assert!(
t.seq()
.windows(3)
.any(|w| matches!(w, [-1, 2, -1] | [1, -2, 1]))
);
}
assert!(fat.try_glue((0, 0), &thin).is_ok());
}
}