diff options
-rw-r--r-- | bot.json | 2 | ||||
-rw-r--r-- | src/actions.rs | 52 | ||||
-rw-r--r-- | src/files.rs | 5 | ||||
-rw-r--r-- | src/lib.rs | 30 | ||||
-rw-r--r-- | src/math.rs | 58 | ||||
-rw-r--r-- | src/placement.rs | 24 | ||||
-rw-r--r-- | src/ships.rs | 2 | ||||
-rw-r--r-- | src/shooting.rs | 6 |
8 files changed, 138 insertions, 41 deletions
@@ -4,5 +4,5 @@ "NickName" :"Admiral Worthebot", "BotType": 8, "ProjectLocation" : "", - "RunFile" : "target\\release\\100k_worthebot_battleships" + "RunFile" : "target\\release\\worthebot_battleships" } diff --git a/src/actions.rs b/src/actions.rs index a7f61b5..1b6400d 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -3,9 +3,11 @@ use ships::*; use std::fmt; +use std::collections::HashSet; + #[derive(Clone, PartialEq, Eq, Debug)] pub enum Action { - PlaceShips(Vec<(Ship, Point, Orientation)>), + PlaceShips(Vec<ShipPlacement>), Shoot(Point) } @@ -13,10 +15,54 @@ 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_type, p, orientation)| { - writeln!(f, "{} {} {} {}", ship_type, p.x, p.y, orientation) + &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)] +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(), map_size); + start.x < map_size && start.y < map_size && end.is_some() + } + pub fn valid_placements(placements: &Vec<ShipPlacement>, 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() { + 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 + } +} diff --git a/src/files.rs b/src/files.rs index 87d295f..99dca8c 100644 --- a/src/files.rs +++ b/src/files.rs @@ -27,6 +27,9 @@ pub fn write_action(working_dir: &PathBuf, is_place_phase: bool, action: Action) let full_filename = working_dir.join(filename); let mut file = File::create(full_filename.as_path()).map_err(|e| e.to_string())?; - writeln!(file, "{}", action).map_err(|e| e.to_string())?; + write!(file, "{}", action).map_err(|e| e.to_string())?; + + println!("Making move: {}", action); + Ok(()) } @@ -5,11 +5,14 @@ mod actions; mod math; mod files; mod ships; +mod placement; +mod shooting; -use actions::*; use math::*; use files::*; use ships::*; +use placement::*; +use shooting::*; use std::path::PathBuf; @@ -17,15 +20,15 @@ pub fn write_move(working_dir: PathBuf) -> Result<(), String> { let state = read_file(&working_dir)?; let is_place_phase = state["Phase"] == 1; - let map_dimension = state["MapDimension"] + let map_size = state["MapDimension"] .as_u16() .ok_or("Did not find the map dimension in the state json file")?; let action = if is_place_phase { - place_ships() + place_ships_randomly(map_size) } else { - shoot_randomly(map_dimension) + shoot_randomly(map_size) }; write_action(&working_dir, is_place_phase, action) @@ -34,22 +37,3 @@ pub fn write_move(working_dir: PathBuf) -> Result<(), String> { Ok(()) } - -fn place_ships() -> Action { - let ships = vec!( - (Ship::Battleship, Point::new(1, 0), Orientation::North), - (Ship::Carrier, Point::new(3, 1), Orientation::East), - (Ship::Cruiser, Point::new(4, 2), Orientation::North), - (Ship::Destroyer, Point::new(7, 3), Orientation::North), - (Ship::Submarine, Point::new(1, 8), Orientation::East) - ); - - Action::PlaceShips(ships) -} - -fn shoot_randomly(map_dimension: u16) -> Action { - Action::Shoot(random_point(map_dimension)) -} - - - diff --git a/src/math.rs b/src/math.rs index 665d4d0..8e81348 100644 --- a/src/math.rs +++ b/src/math.rs @@ -2,18 +2,18 @@ use std::fmt; use rand; use rand::distributions::{IndependentSample, Range}; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum Orientation { +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum Direction { North, East, South, West, } -impl fmt::Display for Orientation { +use Direction::*; + +impl fmt::Display for Direction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Orientation::*; - f.write_str( match self { &North => "North", @@ -25,7 +25,22 @@ impl fmt::Display for Orientation { } } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +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)] pub struct Point { pub x: u16, pub y: u16 @@ -38,12 +53,29 @@ impl Point { y: y } } -} -pub fn random_point(map_dimension: u16) -> Point { - let mut rng = rand::thread_rng(); - let between = Range::new(0, map_dimension); - let x = between.ind_sample(&mut rng); - let y = between.ind_sample(&mut rng); - Point::new(x, 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: u16, map_size: u16) -> Option<Point> { + let x = self.x; + let y = self.y; + + match direction { + South if y < distance => None, + West if x < distance => None, + North if y + distance >= map_size => None, + East if x + distance >= map_size => None, + South => Some(Point::new(x, y-distance)), + West => Some(Point::new(x-distance, y)), + North => Some(Point::new(x, y+distance)), + East => Some(Point::new(x+distance, y)) + } + } } diff --git a/src/placement.rs b/src/placement.rs new file mode 100644 index 0000000..faa340e --- /dev/null +++ b/src/placement.rs @@ -0,0 +1,24 @@ +use actions::*; +use math::*; +use ships::*; + +pub fn place_ships_randomly(map_size: u16) -> Action { + let mut current_placement: Vec<ShipPlacement>; + + while { + current_placement = create_random_placement(map_size); + !ShipPlacement::valid_placements(¤t_placement, map_size) + } {} + + Action::PlaceShips(current_placement) +} + +fn create_random_placement(map_size: u16) -> Vec<ShipPlacement> { + vec!( + ShipPlacement::new(Ship::Battleship, Point::random(map_size), Direction::random()), + ShipPlacement::new(Ship::Carrier, Point::random(map_size), Direction::random()), + ShipPlacement::new(Ship::Cruiser, Point::random(map_size), Direction::random()), + ShipPlacement::new(Ship::Destroyer, Point::random(map_size), Direction::random()), + ShipPlacement::new(Ship::Submarine, Point::random(map_size), Direction::random()) + ) +} diff --git a/src/ships.rs b/src/ships.rs index 8058d4a..e21b20e 100644 --- a/src/ships.rs +++ b/src/ships.rs @@ -27,6 +27,8 @@ impl fmt::Display for Ship { impl Ship { pub fn length(&self) -> u16 { + use Ship::*; + match self { &Battleship => 4, &Carrier => 5, diff --git a/src/shooting.rs b/src/shooting.rs new file mode 100644 index 0000000..14f2b81 --- /dev/null +++ b/src/shooting.rs @@ -0,0 +1,6 @@ +use actions::*; +use math::*; + +pub fn shoot_randomly(map_size: u16) -> Action { + Action::Shoot(Point::random(map_size)) +} |