From 34c87bf04a9b70809eda125ca180de1d993d410e Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Sun, 3 Jun 2018 17:22:22 +0200 Subject: Moved json parsing to be part of a module, with textmap equivalence --- src/bin/perf-test.rs | 4 +- src/input/json.rs | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/input/mod.rs | 2 + src/input/textmap.rs | 67 +++++++++++++++ src/json.rs | 238 --------------------------------------------------- src/lib.rs | 2 +- src/main.rs | 2 +- 7 files changed, 311 insertions(+), 242 deletions(-) create mode 100644 src/input/json.rs create mode 100644 src/input/mod.rs create mode 100644 src/input/textmap.rs delete mode 100644 src/json.rs (limited to 'src') diff --git a/src/bin/perf-test.rs b/src/bin/perf-test.rs index 03da160..71044ad 100644 --- a/src/bin/perf-test.rs +++ b/src/bin/perf-test.rs @@ -17,7 +17,7 @@ fn main() { fn normal_state() { println!("Normal size state file"); let start_time = PreciseTime::now(); - let (settings, state) = match json::read_state_from_file(STATE_PATH) { + let (settings, state) = match input::json::read_state_from_file(STATE_PATH) { Ok(ok) => ok, Err(error) => { println!("Error while parsing JSON file: {}", error); @@ -31,7 +31,7 @@ fn normal_state() { fn big_state() { println!("Big state file"); let start_time = PreciseTime::now(); - let (settings, state) = match json::read_state_from_file(STATE_BIG_PATH) { + let (settings, state) = match input::json::read_state_from_file(STATE_BIG_PATH) { Ok(ok) => ok, Err(error) => { println!("Error while parsing JSON file: {}", error); diff --git a/src/input/json.rs b/src/input/json.rs new file mode 100644 index 0000000..3a3fbf2 --- /dev/null +++ b/src/input/json.rs @@ -0,0 +1,238 @@ +use std::fs::File; +use std::io::prelude::*; +use serde_json; +use std::error::Error; + +use ::engine; + + +pub fn read_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, engine::GameState), Box> { + let mut file = File::open(filename)?; + let mut content = String::new(); + file.read_to_string(&mut content)?; + let state: State = serde_json::from_str(content.as_ref())?; + + let engine_settings = state.to_engine_settings(); + let engine_state = state.to_engine(&engine_settings); + Ok((engine_settings, engine_state)) +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct State { + game_details: GameDetails, + players: Vec, + game_map: Vec>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GameDetails { + //round: u16, + //max_rounds: u16, + map_width: u8, + map_height: u8, + round_income_energy: u16, + buildings_stats: BuildingStats +} + +#[derive(Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +struct BuildingStats { + energy: BuildingBlueprint, + defense: BuildingBlueprint, + attack: BuildingBlueprint +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct BuildingBlueprint { + price: u16, + health: u8, + construction_time: u8, + weapon_damage: u8, + weapon_speed: u8, + weapon_cooldown_period: u8, + energy_generated_per_turn: u16, +// destroy_multiplier: u16, +// construction_score: u16 +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct Player { + player_type: char, + energy: u16, + health: u8, + //hits_taken: u32, + //score: u32 +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct GameCell { + //x: u8, + //y: u8, + buildings: Vec, + missiles: Vec, + //cell_owner: char +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct BuildingState { + health: u8, + construction_time_left: i8, + //price: u16, + weapon_damage: u8, + weapon_speed: u8, + weapon_cooldown_time_left: u8, + weapon_cooldown_period: u8, + //destroy_multiplier: u32, + //construction_score: u32, + energy_generated_per_turn: u16, + //building_type: String, + x: u8, + y: u8, + player_type: char +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct MissileState { + damage: u8, + speed: u8, + x: u8, + y: u8, + player_type: char +} + + +impl State { + fn to_engine_settings(&self) -> engine::settings::GameSettings { + engine::settings::GameSettings { + size: engine::geometry::Point::new(self.game_details.map_width, self.game_details.map_height), + energy_income: self.game_details.round_income_energy, + energy: self.game_details.buildings_stats.energy.to_engine(), + defence: self.game_details.buildings_stats.defense.to_engine(), + attack: self.game_details.buildings_stats.attack.to_engine(), + } + } + + fn to_engine(&self, settings: &engine::settings::GameSettings) -> engine::GameState { + let player_buildings = self.buildings_to_engine('A'); + let opponent_buildings = self.buildings_to_engine('B'); + engine::GameState::new( + self.player().to_engine(settings, &player_buildings), + self.opponent().to_engine(settings, &opponent_buildings), + self.unconstructed_buildings_to_engine('A'), + player_buildings, + self.unconstructed_buildings_to_engine('B'), + opponent_buildings, + self.missiles_to_engine('A'), + self.missiles_to_engine('B'), + settings + ) + } + + fn player(&self) -> &Player { + self.players.iter() + .find(|p| p.player_type == 'A') + .expect("Player character did not appear in state.json") + } + + fn opponent(&self) -> &Player { + self.players.iter() + .find(|p| p.player_type == 'B') + .expect("Opponent character did not appear in state.json") + } + + fn unconstructed_buildings_to_engine(&self, player_type: char) -> Vec { + self.game_map.iter() + .flat_map(|row| row.iter() + .flat_map(|cell| cell.buildings.iter() + .filter(|b| b.player_type == player_type && b.construction_time_left >= 0) + .map(|b| b.to_engine_unconstructed()) + ) + ) + .collect() + } + + fn buildings_to_engine(&self, player_type: char) -> Vec { + self.game_map.iter() + .flat_map(|row| row.iter() + .flat_map(|cell| cell.buildings.iter() + .filter(|b| b.player_type == player_type && b.construction_time_left < 0) + .map(|b| b.to_engine()) + ) + ) + .collect() + } + + fn missiles_to_engine(&self, player_type: char) -> Vec { + self.game_map.iter() + .flat_map(|row| row.iter() + .flat_map(|cell| cell.missiles.iter() + .filter(|b| b.player_type == player_type) + .map(|b| b.to_engine()) + ) + ) + .collect() + } +} + +impl BuildingBlueprint { + fn to_engine(&self) -> engine::settings::BuildingSettings { + engine::settings::BuildingSettings { + price: self.price, + health: self.health, + construction_time: self.construction_time-2, + weapon_damage: self.weapon_damage, + weapon_speed: self.weapon_speed, + weapon_cooldown_period: self.weapon_cooldown_period, + energy_generated_per_turn: self.energy_generated_per_turn, + } + } +} + +impl Player { + fn to_engine(&self, settings: &engine::settings::GameSettings, buildings: &[engine::Building]) -> engine::Player { + engine::Player::new(self.energy, self.health, settings, buildings) + } +} + +impl BuildingState { + fn to_engine(&self) -> engine::Building { + engine::Building { + pos: engine::geometry::Point::new(self.x, self.y), + health: self.health, + weapon_damage: self.weapon_damage, + weapon_speed: self.weapon_speed, + weapon_cooldown_time_left: self.weapon_cooldown_time_left, + weapon_cooldown_period: self.weapon_cooldown_period, + energy_generated_per_turn: self.energy_generated_per_turn, + } + } + + fn to_engine_unconstructed(&self) -> engine::UnconstructedBuilding { + engine::UnconstructedBuilding { + pos: engine::geometry::Point::new(self.x, self.y), + health: self.health, + construction_time_left: self.construction_time_left as u8, // > 0 check already happened + weapon_damage: self.weapon_damage, + weapon_speed: self.weapon_speed, + weapon_cooldown_period: self.weapon_cooldown_period, + energy_generated_per_turn: self.energy_generated_per_turn, + } + } +} + +impl MissileState { + fn to_engine(&self) -> engine::Missile { + engine::Missile { + pos: engine::geometry::Point::new(self.x, self.y), + damage: self.damage, + speed: self.speed, + } + } +} diff --git a/src/input/mod.rs b/src/input/mod.rs new file mode 100644 index 0000000..47f359a --- /dev/null +++ b/src/input/mod.rs @@ -0,0 +1,2 @@ +pub mod json; +pub mod textmap; diff --git a/src/input/textmap.rs b/src/input/textmap.rs new file mode 100644 index 0000000..dbee60a --- /dev/null +++ b/src/input/textmap.rs @@ -0,0 +1,67 @@ +use std::fs::File; +use std::io::prelude::*; +use std::error::Error; + +use ::engine::*; +use ::engine::settings::*; +use ::engine::geometry::*; + + +pub fn read_state_from_file(filename: &str) -> Result<(GameSettings, GameState), Box> { + let mut file = File::open(filename)?; + let mut content = String::new(); + file.read_to_string(&mut content)?; + + let engine_settings = GameSettings { + size: Point::new(8,4), + energy_income: 5, + energy: BuildingSettings { + price: 20, + health: 5, + construction_time: 2-2, + weapon_damage: 0, + weapon_speed: 0, + weapon_cooldown_period: 0, + energy_generated_per_turn: 3 + }, + defence: BuildingSettings { + price: 30, + health: 20, + construction_time: 4-2, + weapon_damage: 0, + weapon_speed: 0, + weapon_cooldown_period: 0, + energy_generated_per_turn: 0 + }, + attack: BuildingSettings { + price: 30, + health: 5, + construction_time: 2-2, + weapon_damage: 5, + weapon_speed: 2, + weapon_cooldown_period: 3, + energy_generated_per_turn: 0 + } + }; + let engine_state = GameState::new( + Player { + energy: 20, + health: 5, + energy_generated: 5 + }, + Player { + energy: 20, + health: 5, + energy_generated: 5 + }, + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + &engine_settings + ); + + Ok((engine_settings, engine_state)) +} diff --git a/src/json.rs b/src/json.rs deleted file mode 100644 index 3a3fbf2..0000000 --- a/src/json.rs +++ /dev/null @@ -1,238 +0,0 @@ -use std::fs::File; -use std::io::prelude::*; -use serde_json; -use std::error::Error; - -use ::engine; - - -pub fn read_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, engine::GameState), Box> { - let mut file = File::open(filename)?; - let mut content = String::new(); - file.read_to_string(&mut content)?; - let state: State = serde_json::from_str(content.as_ref())?; - - let engine_settings = state.to_engine_settings(); - let engine_state = state.to_engine(&engine_settings); - Ok((engine_settings, engine_state)) -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct State { - game_details: GameDetails, - players: Vec, - game_map: Vec>, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GameDetails { - //round: u16, - //max_rounds: u16, - map_width: u8, - map_height: u8, - round_income_energy: u16, - buildings_stats: BuildingStats -} - -#[derive(Deserialize)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] -struct BuildingStats { - energy: BuildingBlueprint, - defense: BuildingBlueprint, - attack: BuildingBlueprint -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct BuildingBlueprint { - price: u16, - health: u8, - construction_time: u8, - weapon_damage: u8, - weapon_speed: u8, - weapon_cooldown_period: u8, - energy_generated_per_turn: u16, -// destroy_multiplier: u16, -// construction_score: u16 -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct Player { - player_type: char, - energy: u16, - health: u8, - //hits_taken: u32, - //score: u32 -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct GameCell { - //x: u8, - //y: u8, - buildings: Vec, - missiles: Vec, - //cell_owner: char -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct BuildingState { - health: u8, - construction_time_left: i8, - //price: u16, - weapon_damage: u8, - weapon_speed: u8, - weapon_cooldown_time_left: u8, - weapon_cooldown_period: u8, - //destroy_multiplier: u32, - //construction_score: u32, - energy_generated_per_turn: u16, - //building_type: String, - x: u8, - y: u8, - player_type: char -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct MissileState { - damage: u8, - speed: u8, - x: u8, - y: u8, - player_type: char -} - - -impl State { - fn to_engine_settings(&self) -> engine::settings::GameSettings { - engine::settings::GameSettings { - size: engine::geometry::Point::new(self.game_details.map_width, self.game_details.map_height), - energy_income: self.game_details.round_income_energy, - energy: self.game_details.buildings_stats.energy.to_engine(), - defence: self.game_details.buildings_stats.defense.to_engine(), - attack: self.game_details.buildings_stats.attack.to_engine(), - } - } - - fn to_engine(&self, settings: &engine::settings::GameSettings) -> engine::GameState { - let player_buildings = self.buildings_to_engine('A'); - let opponent_buildings = self.buildings_to_engine('B'); - engine::GameState::new( - self.player().to_engine(settings, &player_buildings), - self.opponent().to_engine(settings, &opponent_buildings), - self.unconstructed_buildings_to_engine('A'), - player_buildings, - self.unconstructed_buildings_to_engine('B'), - opponent_buildings, - self.missiles_to_engine('A'), - self.missiles_to_engine('B'), - settings - ) - } - - fn player(&self) -> &Player { - self.players.iter() - .find(|p| p.player_type == 'A') - .expect("Player character did not appear in state.json") - } - - fn opponent(&self) -> &Player { - self.players.iter() - .find(|p| p.player_type == 'B') - .expect("Opponent character did not appear in state.json") - } - - fn unconstructed_buildings_to_engine(&self, player_type: char) -> Vec { - self.game_map.iter() - .flat_map(|row| row.iter() - .flat_map(|cell| cell.buildings.iter() - .filter(|b| b.player_type == player_type && b.construction_time_left >= 0) - .map(|b| b.to_engine_unconstructed()) - ) - ) - .collect() - } - - fn buildings_to_engine(&self, player_type: char) -> Vec { - self.game_map.iter() - .flat_map(|row| row.iter() - .flat_map(|cell| cell.buildings.iter() - .filter(|b| b.player_type == player_type && b.construction_time_left < 0) - .map(|b| b.to_engine()) - ) - ) - .collect() - } - - fn missiles_to_engine(&self, player_type: char) -> Vec { - self.game_map.iter() - .flat_map(|row| row.iter() - .flat_map(|cell| cell.missiles.iter() - .filter(|b| b.player_type == player_type) - .map(|b| b.to_engine()) - ) - ) - .collect() - } -} - -impl BuildingBlueprint { - fn to_engine(&self) -> engine::settings::BuildingSettings { - engine::settings::BuildingSettings { - price: self.price, - health: self.health, - construction_time: self.construction_time-2, - weapon_damage: self.weapon_damage, - weapon_speed: self.weapon_speed, - weapon_cooldown_period: self.weapon_cooldown_period, - energy_generated_per_turn: self.energy_generated_per_turn, - } - } -} - -impl Player { - fn to_engine(&self, settings: &engine::settings::GameSettings, buildings: &[engine::Building]) -> engine::Player { - engine::Player::new(self.energy, self.health, settings, buildings) - } -} - -impl BuildingState { - fn to_engine(&self) -> engine::Building { - engine::Building { - pos: engine::geometry::Point::new(self.x, self.y), - health: self.health, - weapon_damage: self.weapon_damage, - weapon_speed: self.weapon_speed, - weapon_cooldown_time_left: self.weapon_cooldown_time_left, - weapon_cooldown_period: self.weapon_cooldown_period, - energy_generated_per_turn: self.energy_generated_per_turn, - } - } - - fn to_engine_unconstructed(&self) -> engine::UnconstructedBuilding { - engine::UnconstructedBuilding { - pos: engine::geometry::Point::new(self.x, self.y), - health: self.health, - construction_time_left: self.construction_time_left as u8, // > 0 check already happened - weapon_damage: self.weapon_damage, - weapon_speed: self.weapon_speed, - weapon_cooldown_period: self.weapon_cooldown_period, - energy_generated_per_turn: self.energy_generated_per_turn, - } - } -} - -impl MissileState { - fn to_engine(&self) -> engine::Missile { - engine::Missile { - pos: engine::geometry::Point::new(self.x, self.y), - damage: self.damage, - speed: self.speed, - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 6bcfc00..7b15502 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,6 @@ extern crate time; extern crate rayon; -pub mod json; +pub mod input; pub mod engine; pub mod strategy; diff --git a/src/main.rs b/src/main.rs index 651df35..e84e207 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ fn main() { let start_time = PreciseTime::now(); println!("Reading in state.json file"); - let (settings, state) = match json::read_state_from_file(STATE_PATH) { + let (settings, state) = match input::json::read_state_from_file(STATE_PATH) { Ok(ok) => ok, Err(error) => { println!("Error while parsing JSON file: {}", error); -- cgit v1.2.3