summaryrefslogtreecommitdiff
path: root/2017-battleships/src/ships.rs
diff options
context:
space:
mode:
Diffstat (limited to '2017-battleships/src/ships.rs')
-rw-r--r--2017-battleships/src/ships.rs216
1 files changed, 216 insertions, 0 deletions
diff --git a/2017-battleships/src/ships.rs b/2017-battleships/src/ships.rs
new file mode 100644
index 0000000..422f24e
--- /dev/null
+++ b/2017-battleships/src/ships.rs
@@ -0,0 +1,216 @@
+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<Point> {
+ 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::<Vec<_>>()
+ }
+}
+
+
+#[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<Self, Self::Err> {
+ 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<Weapon> {
+ 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<Ship> {
+ use Ship::*;
+
+ vec!(
+ Battleship,
+ Carrier,
+ Cruiser,
+ Destroyer,
+ Submarine
+ )
+ }
+}