use std::fmt; use std::str; use math::*; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub enum Weapon { SingleShot, DoubleShotVertical, DoubleShotHorizontal, CornerShot, CrossShotDiagonal, CrossShotHorizontal, SeekerMissle } impl fmt::Display for Weapon { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use Weapon::*; f.write_str( match self { &SingleShot => "1", &DoubleShotVertical => "2", &DoubleShotHorizontal => "3", &CornerShot => "4", &CrossShotDiagonal => "5", &CrossShotHorizontal => "6", &SeekerMissle => "7" } ) } } impl Weapon { pub fn energy_per_round(map_size: u16) -> u16 { if map_size < 10 { 2 } else if map_size < 14 { 3 } else { 4 } } pub fn energy_cost(&self, map_size: u16) -> u16 { use Weapon::*; let epr = Weapon::energy_per_round(map_size); match self { &SingleShot => 1, &DoubleShotVertical | &DoubleShotHorizontal => 8*epr, &CornerShot => 10*epr, &CrossShotDiagonal => 12*epr, &CrossShotHorizontal => 14*epr, &SeekerMissle => 10*epr } } pub fn single_shot_rounds_to_ready(&self, current_energy: u16, map_size: u16) -> u16 { let single_shot_cost = Weapon::SingleShot.energy_cost(map_size); let energy_per_round = Weapon::energy_per_round(map_size) - single_shot_cost; let required_energy = self.energy_cost(map_size) - current_energy; //weird plus is to make the integer rounding up instead of down (required_energy + energy_per_round - 1) / energy_per_round } pub fn affected_cells(&self, target: Point, map_size: u16) -> Vec { use Weapon::*; let p = target; match self { &SingleShot => { vec!(Some(p)) }, &DoubleShotVertical => { vec!( p.move_point(Direction::North, 1, map_size), p.move_point(Direction::South, 1, map_size) ) }, &DoubleShotHorizontal => { vec!( p.move_point(Direction::East, 1, map_size), p.move_point(Direction::West, 1, map_size) ) }, &CornerShot => { vec!( p.move_point(Direction::NorthEast, 1, map_size), p.move_point(Direction::SouthEast, 1, map_size), p.move_point(Direction::NorthWest, 1, map_size), p.move_point(Direction::SouthWest, 1, map_size), ) }, &CrossShotDiagonal => { vec!( p.move_point(Direction::NorthEast, 1, map_size), p.move_point(Direction::SouthEast, 1, map_size), p.move_point(Direction::NorthWest, 1, map_size), p.move_point(Direction::SouthWest, 1, map_size), Some(p) ) }, &CrossShotHorizontal => { vec!( p.move_point(Direction::North, 1, map_size), p.move_point(Direction::East, 1, map_size), p.move_point(Direction::South, 1, map_size), p.move_point(Direction::West, 1, map_size), Some(p) ) }, &SeekerMissle => { vec!( Some(p), p.move_point(Direction::North, 1, map_size), p.move_point(Direction::East, 1, map_size), p.move_point(Direction::South, 1, map_size), p.move_point(Direction::West, 1, map_size), p.move_point(Direction::NorthEast, 1, map_size), p.move_point(Direction::SouthEast, 1, map_size), p.move_point(Direction::NorthWest, 1, map_size), p.move_point(Direction::SouthWest, 1, map_size), p.move_point(Direction::North, 2, map_size), p.move_point(Direction::East, 2, map_size), p.move_point(Direction::South, 2, map_size), p.move_point(Direction::West, 2, map_size) ) } }.iter().filter_map(|&p| p).collect::>() } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub enum Ship { Battleship, Carrier, Cruiser, Destroyer, Submarine } impl fmt::Display for Ship { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use Ship::*; f.write_str( match self { &Battleship => "Battleship", &Carrier => "Carrier", &Cruiser => "Cruiser", &Destroyer => "Destroyer", &Submarine => "Submarine" } ) } } impl str::FromStr for Ship { type Err = String; fn from_str(s: &str) -> Result { use Ship::*; match s { "Battleship" => Ok(Battleship), "Carrier" => Ok(Carrier), "Cruiser" => Ok(Cruiser), "Destroyer" => Ok(Destroyer), "Submarine" => Ok(Submarine), _ => Err(String::from("ship type is not known")) } } } impl Ship { pub fn length(&self) -> u16 { use Ship::*; match self { &Battleship => 4, &Carrier => 5, &Cruiser => 3, &Destroyer => 2, &Submarine => 3 } } pub fn weapons(&self) -> Vec { use Ship::*; use Weapon::*; match self { &Battleship => vec!(SingleShot, CrossShotDiagonal), &Carrier => vec!(SingleShot, CornerShot), &Cruiser => vec!(SingleShot, CrossShotHorizontal), &Destroyer => vec!(SingleShot, DoubleShotVertical, DoubleShotHorizontal), &Submarine => vec!(SingleShot, SeekerMissle) } } pub fn all_types() -> Vec { use Ship::*; vec!( Battleship, Carrier, Cruiser, Destroyer, Submarine ) } }