use std::f32::consts::PI; #[derive(PartialEq, Debug, Clone)] pub enum PenState { Up, Down, } #[derive(PartialEq, Debug, Clone)] pub enum PenColor { Black, Red, } #[derive(PartialEq, Debug, Clone)] pub struct Position(f32, f32); impl Position { pub fn new(x: f32, y: f32) -> Self { Position(x, y) } } #[derive(PartialEq, Debug, Clone)] pub struct Angle(f32); impl Angle { pub fn new(x: f32) -> Self { Angle(x) } } #[derive(PartialEq, Debug, Clone)] pub struct Distance(f32); impl Distance { pub fn new(x: f32) -> Self { Distance(x) } } #[derive(PartialEq, Debug, Clone)] pub struct Turtle { pub position: Position, pub angle: Angle, pub state: PenState, pub color: PenColor, } impl Default for Turtle { fn default() -> Self { Self { position: Position(0.0, 0.0), angle: Angle(0.0), state: PenState::Up, color: PenColor::Black, } } } impl Turtle { pub fn r#move(self, d: Distance) -> Self { Self { position: Self::calc_new_position(&d, &self.angle, &self.position), ..self } } /// The same as `r#move` but returns a tuple ((), Turtle) pub fn r#move2(self, d: Distance) -> ((), Self) { ( (), Self { position: Self::calc_new_position(&d, &self.angle, &self.position), ..self }, ) } pub fn turn(self, angle: Angle) -> Self { Self { angle: Angle(angle.0), ..self } } /// The same as `turn` but returns a tuple ((), Turtle) pub fn turn2(self, angle: Angle) -> ((), Self) { ( (), Self { angle: Angle(angle.0), ..self }, ) } pub fn set_pen_state(self, pen_state: PenState) -> Self { Self { state: pen_state, ..self } } pub fn set_pen_color(self, pen_color: PenColor) -> Self { Self { color: pen_color, ..self } } fn calc_new_position(distance: &Distance, angle: &Angle, cur_position: &Position) -> Position { let angle_in_rads = angle.0 * PI / 180.0; let new_x = cur_position.0 + distance.0 * angle_in_rads.cos(); let new_y = cur_position.1 + distance.0 * angle_in_rads.sin(); Position(new_x.ceil(), new_y.ceil()) } } #[cfg(test)] mod test { use super::{Angle, Distance, PenColor, PenState, Position, Turtle}; #[test] fn test_move() { let t = Turtle::default(); assert_eq!(t.r#move(Distance(1.0)).position, Position(1.0, 0.0)); } #[test] fn test_turn() { let t = Turtle::default(); assert_eq!(t.turn(Angle(90.0)).angle, Angle(90.0)); } #[test] fn test_state() { let t = Turtle::default(); assert_eq!(t.set_pen_state(PenState::Down).state, PenState::Down); } #[test] fn test_color() { let t = Turtle::default(); assert_eq!(t.set_pen_color(PenColor::Red).color, PenColor::Red); } }