use ratatui::prelude::Color; use crate::position::Position; pub trait Monster { fn is_dead(&self) -> bool; fn get_representation(&self) -> (&str, Color); fn decrease_life(&mut self, by: usize); fn get_immutable_position(&self) -> &Position; fn get_experience_gain(&self) -> usize; #[cfg(test)] fn get_position(&mut self) -> &mut Position; #[cfg(test)] fn get_life(&self) -> usize; } macro_rules! default_monster { ($($t:ty),+ $(,)?) => ($( impl Monster for $t { fn is_dead(&self) -> bool { self.life <= 0 } fn get_experience_gain(&self) -> usize { self.experience_gain } fn get_representation(&self) -> (&str, Color) { (&self.symbol, self.color) } fn decrease_life(&mut self, by: usize) { self.life = self.life.saturating_sub(by); } fn get_immutable_position(&self) -> &Position { &self.position } #[cfg(test)] fn get_position(&mut self) -> &mut Position { &mut self.position } #[cfg(test)] fn get_life(&self) -> usize { self.life } } )+) } pub struct Rat { life: usize, position: Position, symbol: String, color: Color, experience_gain: usize, } impl Rat { #[cfg(test)] pub fn new(life: usize) -> Self { Self { life, position: Position::new(0, 0, 0), symbol: String::from("R"), color: Color::Black, experience_gain: 5, } } pub fn new_with_position(position: Position) -> Self { Self { life: 2, position, symbol: String::from("R"), color: Color::Black, experience_gain: 5, } } #[cfg(test)] pub fn get_life(&self) -> usize { self.life } } default_monster!(Rat); pub struct Orc { life: usize, position: Position, symbol: String, color: Color, experience_gain: usize, } impl Orc { #[cfg(test)] pub fn new(life: usize) -> Self { Self { life, position: Position::new(0, 0, 0), symbol: String::from("O"), color: Color::DarkGray, experience_gain: 10, } } pub fn new_with_position(position: Position) -> Self { Self { life: 4, position, symbol: String::from("O"), color: Color::DarkGray, experience_gain: 10, } } #[cfg(test)] pub fn get_life(&self) -> usize { self.life } } default_monster!(Orc); #[test] fn monsters_can_move() { let mut m = Rat::new(2); assert_eq!(m.get_position(), &Position::new(0, 0, 0)); m.get_position().change(1, 2); assert_eq!(m.get_position(), &Position::new(0, 1, 2)); m.get_position().change(2, 1); assert_eq!(m.get_position(), &Position::new(0, 3, 3)); m.get_position().set(1, 2, 3); m.get_position().change(2, 1); assert_eq!(m.get_position(), &Position::new(1, 4, 4)); } #[test] fn monsters_can_die() { let mut m = Rat::new(2); assert_eq!(m.get_life(), 2); assert_eq!(m.is_dead(), false); m.decrease_life(1); assert_eq!(m.get_life(), 1); m.decrease_life(2); assert_eq!(m.get_life(), 0); assert_eq!(m.is_dead(), true); }