diff options
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/actions.rs | 22 | ||||
-rw-r--r-- | src/files.rs | 32 | ||||
-rw-r--r-- | src/lib.rs | 55 | ||||
-rw-r--r-- | src/main.rs | 118 | ||||
-rw-r--r-- | src/math.rs | 49 | ||||
-rw-r--r-- | src/ships.rs | 38 |
8 files changed, 207 insertions, 111 deletions
@@ -1,5 +1,5 @@ [root] -name = "100k_worthebot_battleships" +name = "worthebot_battleships" version = "0.1.0" dependencies = [ "json 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1,5 +1,5 @@ [package] -name = "100k_worthebot_battleships" +name = "worthebot_battleships" version = "0.1.0" authors = ["Justin Worthe <justin.worthe@gmail.com>"] diff --git a/src/actions.rs b/src/actions.rs new file mode 100644 index 0000000..a7f61b5 --- /dev/null +++ b/src/actions.rs @@ -0,0 +1,22 @@ +use math::*; +use ships::*; + +use std::fmt; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Action { + PlaceShips(Vec<(Ship, Point, Orientation)>), + 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_type, p, orientation)| { + writeln!(f, "{} {} {} {}", ship_type, p.x, p.y, orientation) + }).fold(Ok(()), |acc, next| acc.and(next)) + } + } +} + diff --git a/src/files.rs b/src/files.rs new file mode 100644 index 0000000..87d295f --- /dev/null +++ b/src/files.rs @@ -0,0 +1,32 @@ +use json; +use std::io::prelude::*; +use std::fs::File; +use std::path::PathBuf; + +use actions::*; + +const COMMAND_FILE: &'static str = "command.txt"; +const PLACE_FILE: &'static str = "place.txt"; +const STATE_FILE: &'static str = "state.json"; + +pub fn read_file(working_dir: &PathBuf) -> Result<json::JsonValue, String> { + let state_path = working_dir.join(STATE_FILE); + let mut file = File::open(state_path.as_path()).map_err(|e| e.to_string())?; + let mut content = String::new(); + file.read_to_string(&mut content).map_err(|e| e.to_string())?; + json::parse(content.as_ref()).map_err(|e| e.to_string()) +} + +pub fn write_action(working_dir: &PathBuf, is_place_phase: bool, action: Action) -> Result<(), String> { + let filename = if is_place_phase { + PLACE_FILE + } + else { + COMMAND_FILE + }; + + 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())?; + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5ea9ecc --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,55 @@ +extern crate json; +extern crate rand; + +mod actions; +mod math; +mod files; +mod ships; + +use actions::*; +use math::*; +use files::*; +use ships::*; + +use std::path::PathBuf; + +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"] + .as_u16() + .ok_or("Did not find the map dimension in the state json file")?; + + let action = if is_place_phase { + place_ships() + } + else { + shoot_randomly(map_dimension) + }; + + write_action(&working_dir, is_place_phase, action) + .map_err(|e| format!("Failed to write action to file. Error: {}", e))?; + + 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/main.rs b/src/main.rs index 7c904d6..ee0ba59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,119 +1,19 @@ -extern crate json; -extern crate rand; +extern crate worthebot_battleships; +use worthebot_battleships as bot; use std::env; -use std::path::Path; use std::path::PathBuf; -use std::io::prelude::*; -use std::fs::File; -use std::fmt; -use rand::distributions::{IndependentSample, Range}; - -const COMMAND_FILE: &'static str = "command.txt"; -const PLACE_FILE: &'static str = "place.txt"; -const STATE_FILE: &'static str = "state.json"; - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum Orientation { - North, - East, - South, - West, -} - -impl fmt::Display for Orientation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str( - match self { - &Orientation::North => "North", - &Orientation::East => "East", - &Orientation::South => "South", - &Orientation::West => "West" - } - ) - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -enum Action { - PlaceShips(Vec<(String, u32, u32, Orientation)>), - Shoot(u32, u32) -} - -impl fmt::Display for Action { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Action::Shoot(x, y) => writeln!(f, "1,{},{}", x, y), - &Action::PlaceShips(ref ships) => ships.iter().map(|&(ref ship_type, x, y, orientation)| { - writeln!(f, "{} {} {} {}", ship_type, x, y, orientation) - }).fold(Ok(()), |acc, next| acc.and(next)) - } - } -} - -fn main() { +fn main() { let working_dir = env::args() .nth(2) - .map(|pwd| PathBuf::from(pwd)) - .expect("Requires game state folder to be passed as the second parameter"); + .map(|x| PathBuf::from(x)) + .ok_or(String::from("Requires game state folder to be passed as the second parameter")); - // The state file is read here. Chances are, you'll want to read - // more values out of it than the sample bot currently does. - let state = read_file(&working_dir).expect("Failed to read state.json"); - - let is_place_phase = state["Phase"] == 1; - let map_dimension = state["MapDimension"].as_u32().expect("Could not read map dimension from the state"); - - let action = if is_place_phase { - place_ships() - } - else { - shoot_randomly(map_dimension) - }; - - - write_action(&working_dir, is_place_phase, action).expect("Failed to write action to file"); -} - -fn read_file(working_dir: &Path) -> Result<json::JsonValue, String> { - let state_path = working_dir.join(STATE_FILE); - let mut file = File::open(state_path.as_path()).map_err(|e| e.to_string())?; - let mut content = String::new(); - file.read_to_string(&mut content).map_err(|e| e.to_string())?; - json::parse(content.as_ref()).map_err(|e| e.to_string()) -} - -fn place_ships() -> Action { - let ships = vec!( - (String::from("Battleship"), 1, 0, Orientation::North), - (String::from("Carrier"), 3, 1, Orientation::East), - (String::from("Cruiser"), 4, 2, Orientation::North), - (String::from("Destroyer"), 7, 3, Orientation::North), - (String::from("Submarine"), 1, 8, Orientation::East) - ); - - Action::PlaceShips(ships) -} - -fn shoot_randomly(map_dimension: u32) -> Action { - 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); - Action::Shoot(x, y) -} + let result = working_dir.and_then(|working_dir| bot::write_move(working_dir)); -fn write_action(working_dir: &Path, is_place_phase: bool, action: Action) -> Result<(), String> { - let filename = if is_place_phase { - PLACE_FILE + match result { + Ok(()) => println!("Bot terminated successfully"), + Err(e) => println!("Error in bot execution: {}", e) } - else { - COMMAND_FILE - }; - - 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())?; - Ok(()) } diff --git a/src/math.rs b/src/math.rs new file mode 100644 index 0000000..665d4d0 --- /dev/null +++ b/src/math.rs @@ -0,0 +1,49 @@ +use std::fmt; +use rand; +use rand::distributions::{IndependentSample, Range}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Orientation { + North, + East, + South, + West, +} + +impl fmt::Display for Orientation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use Orientation::*; + + f.write_str( + match self { + &North => "North", + &East => "East", + &South => "South", + &West => "West" + } + ) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +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_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) +} diff --git a/src/ships.rs b/src/ships.rs new file mode 100644 index 0000000..8058d4a --- /dev/null +++ b/src/ships.rs @@ -0,0 +1,38 @@ +use std::fmt; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +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 Ship { + pub fn length(&self) -> u16 { + match self { + &Battleship => 4, + &Carrier => 5, + &Cruiser => 3, + &Destroyer => 2, + &Submarine => 3 + } + } +} |