From 862897ea1d183810c2783eaeeaf40f648ef3dc2d Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Sun, 18 Jun 2017 15:15:11 +0200 Subject: Added knowledge of weapons Next step: knowledge of weapon's effects. --- src/actions.rs | 4 ++-- src/knowledge.rs | 35 ++++++++++++++++++++++++---- src/ships.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/shooting.rs | 6 +++-- src/state.rs | 44 ++++++++++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+), 9 deletions(-) diff --git a/src/actions.rs b/src/actions.rs index 2291de6..ae1f6ce 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -8,13 +8,13 @@ use std::collections::HashSet; #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum Action { PlaceShips(Vec), - Shoot(Point) + Shoot(Weapon, 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::Shoot(w, p) => writeln!(f, "{},{},{}", w, 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)) diff --git a/src/knowledge.rs b/src/knowledge.rs index 5e45f07..e12a8b2 100644 --- a/src/knowledge.rs +++ b/src/knowledge.rs @@ -9,7 +9,9 @@ use std::collections::HashMap; pub struct Knowledge { pub last_action: Action, pub opponent_map: OpponentMapKnowledge, - pub map_size: u16 + pub map_size: u16, + pub available_weapons: Vec, + pub charging_weapons: HashMap } impl Knowledge { @@ -17,24 +19,47 @@ impl Knowledge { Knowledge { last_action: action, opponent_map: OpponentMapKnowledge::new(map_size), - map_size: map_size + map_size: map_size, + available_weapons: Vec::new(), + charging_weapons: HashMap::new() } } pub fn with_action(&self, action: Action) -> Knowledge { Knowledge { last_action: action, - opponent_map: self.opponent_map.clone(), - map_size: self.map_size + ..self.clone() } } pub fn resolve_last_action(&self, state: &State) -> Knowledge { let mut new_knowledge = self.clone(); + + let energy = state.player_map.energy; + let mut available_weapons: Vec<_> = state.player_map.ships.iter() + .filter(|&(_, ship_data)| !ship_data.destroyed) + .flat_map(|(ship, _)| ship.weapons()) + .collect(); + + available_weapons.sort_by_key(|weapon| format!("{}",weapon)); + available_weapons.dedup(); + new_knowledge.available_weapons = available_weapons.iter() + .filter(|weapon| weapon.energy_cost(state.map_size) <= energy) + .cloned() + .collect(); + + new_knowledge.charging_weapons = available_weapons.iter() + .filter(|weapon| weapon.energy_cost(state.map_size) > energy) + .map(|weapon| (weapon.clone(), weapon.energy_cost(state.map_size) - energy)) + .collect(); + match self.last_action { Action::PlaceShips(_) => {}, - Action::Shoot(p) => { + Action::Shoot(Weapon::SingleShot, p) => { new_knowledge.opponent_map.update_from_shot(p, &state); + }, + Action::Shoot(w, p) => { + //TODO } }; diff --git a/src/ships.rs b/src/ships.rs index ef29fe9..e37fe33 100644 --- a/src/ships.rs +++ b/src/ships.rs @@ -1,6 +1,62 @@ use std::fmt; use std::str; +#[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 + } + } +} + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub enum Ship { Battleship, @@ -55,6 +111,19 @@ impl Ship { } } + pub fn weapons(&self) -> Vec { + 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 { use Ship::*; diff --git a/src/shooting.rs b/src/shooting.rs index 4d87d86..bcdf783 100644 --- a/src/shooting.rs +++ b/src/shooting.rs @@ -4,6 +4,7 @@ use rand::distributions::{IndependentSample, Range}; use actions::*; use math::*; use knowledge::*; +use ships::*; pub fn shoot_smartly(knowledge: &Knowledge) -> Action { let shot = if knowledge.has_unknown_hits() { @@ -12,8 +13,9 @@ pub fn shoot_smartly(knowledge: &Knowledge) -> Action { else { seek_shoot(&knowledge) }; - - Action::Shoot(shot) + + //TODO shoot other weapons + Action::Shoot(Weapon::SingleShot, shot) } fn seek_shoot(knowledge: &Knowledge) -> Point { diff --git a/src/state.rs b/src/state.rs index 8c176e1..1756ad0 100644 --- a/src/state.rs +++ b/src/state.rs @@ -4,17 +4,23 @@ use ships::*; pub struct State { pub map_size: u16, + pub player_map: PlayerMap, pub opponent_map: OpponentMap } impl State { pub fn new(json: &json::JsonValue) -> Result { let map_size = State::map_size_from_json(&json)?; + + let ref player_map_json = json["PlayerMap"]; + let player_map = PlayerMap::new(&player_map_json)?; + let ref opponent_map_json = json["OpponentMap"]; let opponent_map = OpponentMap::new(&opponent_map_json, map_size)?; Ok(State { map_size: map_size, + player_map: player_map, opponent_map: opponent_map }) } @@ -100,3 +106,41 @@ impl Cell { } } } + +pub struct PlayerMap { + pub ships: HashMap, + pub energy: u16 +} + +impl PlayerMap { + fn new(json: &json::JsonValue) -> Result { + let mut ships = HashMap::new(); + for json_ship in json["Owner"]["Ships"].members() { + let ship_type_string = json_ship["ShipType"] + .as_str() + .ok_or(String::from("Failed to read ShipType value of player map ship in json file"))?; + let ship_type = ship_type_string.parse::()?; + + let destroyed = json_ship["Destroyed"] + .as_bool() + .ok_or(String::from("Failed to read Destroyed value of player map ship in json file"))?; + ships.insert(ship_type, PlayerShip { + destroyed: destroyed + }); + } + + let energy = json["Owner"]["Energy"] + .as_u16() + .ok_or(String::from("Did not find the energy in the state json file"))?; + + Ok(PlayerMap { + ships: ships, + energy: energy + }) + } +} + + +pub struct PlayerShip { + pub destroyed: bool +} -- cgit v1.2.3