use math::*; use ships::*; use std::fmt; use std::collections::HashSet; #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum Action { PlaceShips(Vec), Shoot(Point) } impl fmt::Display for Action { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &Action::Shoot(p) => writeln!(f, "1,{},{}", p.x, p.y), &Action::PlaceShips(ref ships) => ships.iter().map(|ref ship| { writeln!(f, "{} {} {} {}", ship.ship_type, ship.point.x, ship.point.y, ship.direction) }).fold(Ok(()), |acc, next| acc.and(next)) } } } #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub struct ShipPlacement { ship_type: Ship, point: Point, direction: Direction } impl ShipPlacement { pub fn new(ship_type: Ship, point: Point, direction: Direction) -> ShipPlacement { ShipPlacement { ship_type: ship_type, point: point, direction: direction } } pub fn valid(&self, map_size: u16) -> bool { let start = self.point; let end = start.move_point(self.direction, self.ship_type.length() as i32, map_size); start.x < map_size && start.y < map_size && end.is_some() } pub fn valid_placements(placements: &Vec, map_size: u16) -> bool { let mut occupied = HashSet::new(); let mut individuals_valid = true; let mut no_overlaps = true; for placement in placements { individuals_valid = individuals_valid && placement.valid(map_size); for i in 0..placement.ship_type.length() as i32 { match placement.point.move_point(placement.direction, i, map_size) { Some(block) => { no_overlaps = no_overlaps && !occupied.contains(&block); occupied.insert(block); }, None => { //invalid case here is handled above } } } } individuals_valid && no_overlaps } }