use std::fmt::{Formatter, Display, Error};
use super::super::vector::VectorAdd;
use super::{Position, MinimumPosition, Translatable, Translation, Transformable, CubeSymmetry};
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Piece<T> {
positions: Vec<Position<T>>,
name: Option<String>
}
impl<T> Piece<T> where T: PartialOrd + Ord + Clone {
pub fn new(mut positions: Vec<Position<T>>) -> Piece<T> {
positions.sort();
Piece { positions, name: None }
}
pub fn named<S>(mut positions: Vec<Position<T>>, name: S) -> Piece<T> where S: Into<String> {
positions.sort();
Piece { positions, name: Some(name.into()) }
}
pub fn contains(&self, position: &Position<T>) -> bool {
self.positions.contains(position)
}
pub fn iter(&self) -> PositionIterator<T> {
let positions: Vec<Position<T>> = self.positions.to_vec();
PositionIterator::new(positions)
}
}
impl Display for Piece<(i8,i8,i8)> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "[")?;
let name = self.name.clone().unwrap_or_else(|| String::from(""));
write!(f, "{}", name)?;
for position in &self.positions {
write!(f, "{}", position)?
}
write!(f, "]")
}
}
impl Display for Piece<(i8, i8)> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "[")?;
let name = self.name.clone().unwrap_or_else(|| String::from(""));
write!(f, "{}", name)?;
for position in &self.positions {
write!(f, "{}", position)?
}
write!(f, "]")
}
}
impl<T> Transformable for Piece<T> where T: Transformable + PartialOrd + Ord {
fn transform(&mut self, symmetry: &CubeSymmetry) {
for position in &mut self.positions {
position.transform(symmetry);
}
self.positions.sort()
}
}
impl<T> Translatable<T> for Piece<T> where T: VectorAdd<T> {
fn translate(&mut self, translation: &Translation<T>) {
for position in &mut self.positions {
position.translate(translation);
}
}
}
impl<T> MinimumPosition<T> for Piece<T> where T: PartialOrd + Ord + Clone {
fn minimum_position(&self) -> Option<Position<T>> {
self.positions.iter().min().cloned()
}
}
pub struct PositionIterator<T> {
index: usize,
positions: Vec<Position<T>>,
}
impl<T> PositionIterator<T> {
pub fn new(positions: Vec<Position<T>>) -> PositionIterator<T> {
PositionIterator { index: 0, positions }
}
}
impl<T> Iterator for PositionIterator<T> where T: Clone {
type Item = Position<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.positions.len() {
let position = self.positions[self.index].clone();
self.index += 1;
Some(position)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn piece_should_translate() {
let mut piece = Piece::new(vec!(
Position::new(0, 0, 0),
Position::new(1, 0, 0),
Position::new(1, 1, 0),
Position::new(1, 1, 1),
));
let translation = Translation::new(5, -3, 0);
piece.translate(&translation);
assert_eq!(piece, Piece::new(vec!(
Position::new(5, -3, 0),
Position::new(6, -3, 0),
Position::new(6, -2, 0),
Position::new(6, -2, 1),
)));
}
#[test]
fn piece_should_tranform() {
let mut piece = Piece::new(vec!(
Position::new(0, 0, 0),
Position::new(1, 0, 0),
Position::new(1, 1, 0),
Position::new(1, 1, 1),
));
piece.transform(&CubeSymmetry::E2103);
assert_eq!(piece, Piece::new(vec!(
Position::new(0, 0, 0),
Position::new(0, 1, 0),
Position::new(1, 1, 0),
Position::new(1, 1, -1),
)));
}
}