use std::fmt; use rand; use rand::distributions::{IndependentSample, Range}; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub enum Direction { North, East, South, West, } use Direction::*; impl fmt::Display for Direction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str( match self { &North => "North", &East => "East", &South => "South", &West => "West" } ) } } impl Direction { pub fn random() -> Direction { let mut rng = rand::thread_rng(); let between = Range::new(0, 4); let dir = between.ind_sample(&mut rng); match dir { 0 => North, 1 => East, 2 => South, 3 => West, _ => panic!("Invalid number generated by random number generator") } } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub struct Point { pub x: u16, pub y: u16 } impl Point { pub fn new(x: u16, y: u16) -> Point { Point { x: x, y: y } } pub fn random(map_size: u16) -> Point { let mut rng = rand::thread_rng(); let between = Range::new(0, map_size); let x = between.ind_sample(&mut rng); let y = between.ind_sample(&mut rng); Point::new(x, y) } pub fn move_point(&self, direction: Direction, distance: i32, map_size: u16) -> Option { let x = self.x as i32 + match direction { West => -distance, East => distance, _ => 0 }; let y = self.y as i32 + match direction { South => -distance, North => distance, _ => 0 }; let max = map_size as i32; if x >= max || y >= max || x < 0 || y < 0 { None } else { Some(Point::new(x as u16, y as u16)) } } pub fn move_point_no_bounds_check(&self, direction: Direction, distance: i32) -> Point { let x = self.x as i32 + match direction { West => -distance, East => distance, _ => 0 }; let y = self.y as i32 + match direction { South => -distance, North => distance, _ => 0 }; Point::new(x as u16, y as u16) } pub fn check_for_ship_collision(&self, ship_start: Point, direction: Direction, length: u16) -> bool { let reverse = match direction { West | South => true, East | North => false }; let same_cross = match direction { East | West => self.y == ship_start.y, North | South => self.x == ship_start.x }; let (parr_self, parr_ship) = match direction { East | West => (self.x, ship_start.x), North | South => (self.y, ship_start.y) }; let corrected_parr_ship = match reverse { true => 1 + parr_ship - length, false => parr_ship }; same_cross && parr_self >= corrected_parr_ship && parr_self < corrected_parr_ship + length } pub fn is_adjacent(&self, other: Point) -> bool { let dx = if self.x > other.x {self.x - other.x} else {other.x - self.x}; let dy = if self.y > other.y {self.y - other.y} else {other.y - self.y}; (dx == 0 && dy == 1) || (dx == 1 && dy == 0) } }