summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2018-05-09 22:51:38 +0200
committerJustin Worthe <justin@worthe-it.co.za>2018-05-09 22:51:38 +0200
commit11c791a59ac60241f253cdfb4e8765039d15edff (patch)
tree71d4df1b7dad0dfe03e25d3ef128a61927e65522
parent057a4fe886848322adf4e48ad9709a289434dc1b (diff)
Added converting from JSON code to game engine representation
-rw-r--r--src/engine/geometry.rs3
-rw-r--r--src/engine/mod.rs64
-rw-r--r--src/json.rs185
-rw-r--r--src/main.rs19
-rw-r--r--src/state_json.rs86
5 files changed, 228 insertions, 129 deletions
diff --git a/src/engine/geometry.rs b/src/engine/geometry.rs
index f2a2522..a946bf9 100644
--- a/src/engine/geometry.rs
+++ b/src/engine/geometry.rs
@@ -5,6 +5,9 @@ pub struct Point {
}
impl Point {
+ pub fn new(x: u8, y: u8) -> Point {
+ Point { x, y }
+ }
pub fn move_left(&self) -> Option<Point> {
self.x.checked_sub(1).map(|x| Point {
x: x,
diff --git a/src/engine/mod.rs b/src/engine/mod.rs
index d321572..4ea63a3 100644
--- a/src/engine/mod.rs
+++ b/src/engine/mod.rs
@@ -10,14 +10,14 @@ use std::ops::Fn;
use std::cmp;
#[derive(Debug, Clone)]
-struct GameState {
- status: GameStatus,
- player: Player,
- opponent: Player,
- player_buildings: Vec<Building>,
- opponent_buildings: Vec<Building>,
- player_missiles: Vec<Missile>,
- opponent_missiles: Vec<Missile>
+pub struct GameState {
+ pub status: GameStatus,
+ pub player: Player,
+ pub opponent: Player,
+ pub player_buildings: Vec<Building>,
+ pub opponent_buildings: Vec<Building>,
+ pub player_missiles: Vec<Missile>,
+ pub opponent_missiles: Vec<Missile>
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -37,20 +37,20 @@ impl GameStatus {
#[derive(Debug, Clone)]
pub struct Player {
- energy: u16,
- health: u16
+ pub energy: u16,
+ pub health: u16
}
#[derive(Debug, Clone)]
-struct Building {
- pos: Point,
- health: u16,
- construction_time_left: u8,
- weapon_damage: u16,
- weapon_speed: u8,
- weapon_cooldown_time_left: u8,
- weapon_cooldown_period: u8,
- energy_generated_per_turn: u16
+pub struct Building {
+ pub pos: Point,
+ pub health: u16,
+ pub construction_time_left: u8,
+ pub weapon_damage: u16,
+ pub weapon_speed: u8,
+ pub weapon_cooldown_time_left: u8,
+ pub weapon_cooldown_period: u8,
+ pub energy_generated_per_turn: u16
}
impl Building {
@@ -87,7 +87,6 @@ impl Building {
energy_generated_per_turn: 3
}
}
-
}
fn is_constructed(&self) -> bool {
@@ -95,21 +94,15 @@ impl Building {
}
fn is_shooty(&self) -> bool {
- self.is_constructed() && self.weapon_damage >= 0
+ self.is_constructed() && self.weapon_damage > 0
}
}
#[derive(Debug, Clone)]
-struct Missile {
- pos: Point,
- damage: u16,
- speed: u8,
-}
-
-impl Missile {
- fn is_stopped(&self) -> bool {
- self.speed == 0
- }
+pub struct Missile {
+ pub pos: Point,
+ pub damage: u16,
+ pub speed: u8,
}
impl GameState {
@@ -119,8 +112,13 @@ impl GameState {
}
let mut state = self.clone();
- GameState::perform_command(&mut state.player_buildings, player_command, &settings.size);
- GameState::perform_command(&mut state.opponent_buildings, opponent_command, &settings.size);
+ let player_valid = GameState::perform_command(&mut state.player_buildings, player_command, &settings.size);
+ let opponent_valid = GameState::perform_command(&mut state.opponent_buildings, opponent_command, &settings.size);
+
+ if !player_valid || !opponent_valid {
+ state.status = GameStatus::InvalidMove;
+ return state;
+ }
GameState::update_construction(&mut state.player_buildings);
GameState::update_construction(&mut state.opponent_buildings);
diff --git a/src/json.rs b/src/json.rs
new file mode 100644
index 0000000..18e13fb
--- /dev/null
+++ b/src/json.rs
@@ -0,0 +1,185 @@
+use std::fs::File;
+use std::io::prelude::*;
+use serde_json;
+use std::error::Error;
+use std::cmp;
+
+use ::engine;
+
+
+pub fn read_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, engine::GameState), Box<Error>> {
+ 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())?;
+ Ok((state.to_engine_settings(), state.to_engine()))
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct State {
+ game_details: GameDetails,
+ players: Vec<Player>,
+ game_map: Vec<Vec<GameCell>>,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct GameDetails {
+ //round: u32,
+ map_width: u8,
+ map_height: u8,
+ building_prices: BuildingPrices
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+struct BuildingPrices {
+ energy: u16,
+ defense: u16,
+ attack: u16
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct Player {
+ player_type: char,
+ energy: u16,
+ health: u16,
+ //hits_taken: u32,
+ //score: u32
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct GameCell {
+ //x: u8,
+ //y: u8,
+ buildings: Vec<BuildingState>,
+ missiles: Vec<MissileState>,
+ //cell_owner: char
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct BuildingState {
+ health: u16,
+ construction_time_left: i8,
+ //price: u16,
+ weapon_damage: u16,
+ 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: u16,
+ 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: 5,
+ energy_price: self.game_details.building_prices.energy,
+ defence_price: self.game_details.building_prices.defense,
+ attack_price: self.game_details.building_prices.attack,
+ }
+ }
+
+ fn to_engine(&self) -> engine::GameState {
+ engine::GameState {
+ status: engine::GameStatus::Continue,
+ player: self.player().to_engine(),
+ opponent: self.opponent().to_engine(),
+ player_buildings: self.buildings_to_engine('A'),
+ opponent_buildings: self.buildings_to_engine('B'),
+ player_missiles: self.missiles_to_engine('A'),
+ opponent_missiles: self.missiles_to_engine('B'),
+ }
+ }
+
+ fn player(&self) -> &Player {
+ self.players.iter()
+ .filter(|p| p.player_type == 'A')
+ .next()
+ .expect("Player character did not appear in state.json")
+ }
+
+ fn opponent(&self) -> &Player {
+ self.players.iter()
+ .filter(|p| p.player_type != 'B')
+ .next()
+ .expect("Opponent character did not appear in state.json")
+ }
+
+ fn buildings_to_engine(&self, player_type: char) -> Vec<engine::Building> {
+ self.game_map.iter()
+ .flat_map(|row| row.iter()
+ .flat_map(|cell| cell.buildings.iter()
+ .filter(|b| b.player_type == player_type)
+ .map(|b| b.to_engine())
+ )
+ )
+ .collect()
+ }
+
+ fn missiles_to_engine(&self, player_type: char) -> Vec<engine::Missile> {
+ 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 Player {
+ fn to_engine(&self) -> engine::Player {
+ engine::Player {
+ energy: self.energy,
+ health: self.health,
+ }
+ }
+}
+
+impl BuildingState {
+ fn to_engine(&self) -> engine::Building {
+ engine::Building {
+ pos: engine::geometry::Point::new(self.x, self.y),
+ health: self.health,
+ construction_time_left: cmp::max(0, self.construction_time_left) as u8,
+ 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,
+ }
+ }
+}
+
+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/main.rs b/src/main.rs
index d964fee..4e18c48 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,34 +14,33 @@ use std::fs::File;
use std::io::prelude::*;
use std::process;
-mod state_json;
+mod json;
mod engine;
use engine::command::Command;
-fn choose_move(_state: &state_json::State) -> Option<Command> {
- None
+fn choose_move(settings: &engine::settings::GameSettings, state: &engine::GameState) -> Command {
+ state.simulate(&settings, Command::Nothing, Command::Nothing);
+ Command::Nothing
}
-fn write_command(filename: &str, command: Option<Command>) -> Result<(), Box<Error> > {
+fn write_command(filename: &str, command: Command) -> Result<(), Box<Error> > {
let mut file = File::create(filename)?;
- if let Some(command) = command {
- write!(file, "{}", command)?;
- }
+ write!(file, "{}", command)?;
Ok(())
}
fn main() {
- let state = match state_json::read_state_from_file(STATE_PATH) {
- Ok(state) => state,
+ let (settings, state) = match json::read_state_from_file(STATE_PATH) {
+ Ok(ok) => ok,
Err(error) => {
eprintln!("Failed to read the {} file. {}", STATE_PATH, error);
process::exit(1);
}
};
- let command = choose_move(&state);
+ let command = choose_move(&settings, &state);
match write_command(COMMAND_PATH, command) {
Ok(()) => {}
diff --git a/src/state_json.rs b/src/state_json.rs
deleted file mode 100644
index 429db6d..0000000
--- a/src/state_json.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use std::fs::File;
-use std::io::prelude::*;
-use serde_json;
-use std::error::Error;
-
-pub fn read_state_from_file(filename: &str) -> Result<State, Box<Error>> {
- let mut file = File::open(filename)?;
- let mut content = String::new();
- file.read_to_string(&mut content)?;
- let state = serde_json::from_str(content.as_ref())?;
- Ok(state)
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct State {
- pub game_details: GameDetails,
- pub players: Vec<Player>,
- pub game_map: Vec<Vec<GameCell>>,
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct GameDetails {
- pub round: u32,
- pub map_width: u32,
- pub map_height: u32,
- pub building_prices: BuildingPrices
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
-pub struct BuildingPrices {
- pub energy: u32,
- pub defense: u32,
- pub attack: u32
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Player {
- pub player_type: char,
- pub energy: u32,
- pub health: u32,
- pub hits_taken: u32,
- pub score: u32
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct GameCell {
- pub x: u32,
- pub y: u32,
- pub buildings: Vec<BuildingState>,
- pub missiles: Vec<MissileState>,
- pub cell_owner: char
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct BuildingState {
- pub health: u32,
- pub construction_time_left: i32,
- pub price: u32,
- pub weapon_damage: u32,
- pub weapon_speed: u32,
- pub weapon_cooldown_time_left: u32,
- pub weapon_cooldown_period: u32,
- pub destroy_multiplier: u32,
- pub construction_score: u32,
- pub energy_generated_per_turn: u32,
- pub building_type: String,
- pub x: u32,
- pub y: u32,
- pub player_type: char
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct MissileState {
- pub damage: u32,
- pub speed: u32,
- pub x: u32,
- pub y: u32,
- pub player_type: char
-}