From 4755702ef08d70961b5248cb706a592a406d0556 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Thu, 10 May 2018 23:01:22 +0200 Subject: Split to library. Reimplemented sample strategy in new state. --- src/engine/command.rs | 6 +- src/engine/mod.rs | 147 ++++++++++++++++++++++++++++++++----------------- src/lib.rs | 9 +++ src/main.rs | 18 ++---- src/strategy/mod.rs | 1 + src/strategy/sample.rs | 38 +++++++++++++ 6 files changed, 150 insertions(+), 69 deletions(-) create mode 100644 src/lib.rs create mode 100644 src/strategy/mod.rs create mode 100644 src/strategy/sample.rs (limited to 'src') diff --git a/src/engine/command.rs b/src/engine/command.rs index 603ee42..eab98c1 100644 --- a/src/engine/command.rs +++ b/src/engine/command.rs @@ -9,11 +9,9 @@ pub enum Command { impl fmt::Display for Command { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Command::*; - match self { - &Nothing => write!(f, ""), - &Build(p, b) => write!(f, "{},{},{}", p.x, p.y, b as u8), + &Command::Nothing => write!(f, ""), + &Command::Build(p, b) => write!(f, "{},{},{}", p.x, p.y, b as u8), } } } diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 4ea63a3..be95c03 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -29,12 +29,6 @@ pub enum GameStatus { InvalidMove } -impl GameStatus { - fn is_complete(&self) -> bool { - *self != GameStatus::Continue - } -} - #[derive(Debug, Clone)] pub struct Player { pub energy: u16, @@ -53,51 +47,6 @@ pub struct Building { pub energy_generated_per_turn: u16 } -impl Building { - fn new(pos: Point, building: BuildingType) -> Building { - match building { - BuildingType::Defense => Building { - pos: pos, - health: 20, - construction_time_left: 3, - weapon_damage: 0, - weapon_speed: 0, - weapon_cooldown_time_left: 0, - weapon_cooldown_period: 0, - energy_generated_per_turn: 0 - }, - BuildingType::Attack => Building { - pos: pos, - health: 5, - construction_time_left: 1, - weapon_damage: 5, - weapon_speed: 1, - weapon_cooldown_time_left: 0, - weapon_cooldown_period: 3, - energy_generated_per_turn: 0 - }, - BuildingType::Energy => Building { - pos: pos, - health: 5, - construction_time_left: 1, - weapon_damage: 0, - weapon_speed: 0, - weapon_cooldown_time_left: 0, - weapon_cooldown_period: 0, - energy_generated_per_turn: 3 - } - } - } - - fn is_constructed(&self) -> bool { - self.construction_time_left == 0 - } - - fn is_shooty(&self) -> bool { - self.is_constructed() && self.weapon_damage > 0 - } -} - #[derive(Debug, Clone)] pub struct Missile { pub pos: Point, @@ -215,4 +164,100 @@ impl GameState { (false, false) => GameStatus::Continue, }; } + + pub fn unoccupied_player_cells_in_row(&self, settings: &GameSettings, y: u8) -> Vec { + (0..settings.size.x/2) + .map(|x| Point::new(x, y)) + .filter(|&p| !self.player_buildings.iter().any(|b| b.pos == p)) + .collect() + } + + pub fn unoccupied_player_cells(&self, settings: &GameSettings) -> Vec { + (0..settings.size.y) + .flat_map(|y| (0..settings.size.x/2).map(|x| Point::new(x, y)).collect::>()) + .filter(|&p| !self.player_buildings.iter().any(|b| b.pos == p)) + .collect() + } +} + +impl GameStatus { + fn is_complete(&self) -> bool { + *self != GameStatus::Continue + } +} + +impl Player { + pub fn can_afford_all_buildings(&self, settings: &GameSettings) -> bool { + self.can_afford_attack_buildings(settings) && + self.can_afford_defence_buildings(settings) && + self.can_afford_energy_buildings(settings) + } + + pub fn can_afford_attack_buildings(&self, settings: &GameSettings) -> bool { + self.energy >= settings.attack_price + } + pub fn can_afford_defence_buildings(&self, settings: &GameSettings) -> bool { + self.energy >= settings.defence_price + } + pub fn can_afford_energy_buildings(&self, settings: &GameSettings) -> bool { + self.energy >= settings.energy_price + } + +} + +impl Building { + fn new(pos: Point, building: BuildingType) -> Building { + match building { + BuildingType::Defense => Building { + pos: pos, + health: 20, + construction_time_left: 3, + weapon_damage: 0, + weapon_speed: 0, + weapon_cooldown_time_left: 0, + weapon_cooldown_period: 0, + energy_generated_per_turn: 0 + }, + BuildingType::Attack => Building { + pos: pos, + health: 5, + construction_time_left: 1, + weapon_damage: 5, + weapon_speed: 1, + weapon_cooldown_time_left: 0, + weapon_cooldown_period: 3, + energy_generated_per_turn: 0 + }, + BuildingType::Energy => Building { + pos: pos, + health: 5, + construction_time_left: 1, + weapon_damage: 0, + weapon_speed: 0, + weapon_cooldown_time_left: 0, + weapon_cooldown_period: 0, + energy_generated_per_turn: 3 + } + } + } + + fn is_constructed(&self) -> bool { + self.construction_time_left == 0 + } + + fn is_shooty(&self) -> bool { + self.is_constructed() && self.weapon_damage > 0 + } +} + +#[test] +fn how_big() { + use std::mem; + assert_eq!(4, mem::size_of::()); + assert_eq!(12, mem::size_of::()); + assert_eq!(6, mem::size_of::()); + assert_eq!(112, mem::size_of::()); + assert_eq!(24, mem::size_of::>()); + assert_eq!(24, mem::size_of::>()); + } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..158805a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +extern crate serde; +extern crate serde_json; + +#[macro_use] +extern crate serde_derive; + +pub mod json; +pub mod engine; +pub mod strategy; diff --git a/src/main.rs b/src/main.rs index 4e18c48..22f698d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,6 @@ -extern crate serde; -extern crate serde_json; - -#[macro_use] -extern crate serde_derive; +extern crate zombot; +use zombot::*; +use zombot::engine::command::Command; use std::error::Error; @@ -14,20 +12,14 @@ use std::fs::File; use std::io::prelude::*; use std::process; -mod json; -mod engine; -use engine::command::Command; - fn choose_move(settings: &engine::settings::GameSettings, state: &engine::GameState) -> Command { - state.simulate(&settings, Command::Nothing, Command::Nothing); - Command::Nothing + strategy::sample::choose_move(settings, state) } fn write_command(filename: &str, command: Command) -> Result<(), Box > { let mut file = File::create(filename)?; write!(file, "{}", command)?; - Ok(()) } @@ -36,7 +28,6 @@ fn main() { 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); } }; @@ -45,7 +36,6 @@ fn main() { match write_command(COMMAND_PATH, command) { Ok(()) => {} Err(error) => { - eprintln!("Failed to write the {} file. {}", COMMAND_PATH, error); process::exit(1); } } diff --git a/src/strategy/mod.rs b/src/strategy/mod.rs new file mode 100644 index 0000000..ce8e751 --- /dev/null +++ b/src/strategy/mod.rs @@ -0,0 +1 @@ +pub mod sample; diff --git a/src/strategy/sample.rs b/src/strategy/sample.rs new file mode 100644 index 0000000..bd23916 --- /dev/null +++ b/src/strategy/sample.rs @@ -0,0 +1,38 @@ +use engine; +use engine::command::*; + + +pub fn choose_move(settings: &engine::settings::GameSettings, state: &engine::GameState) -> Command { + if state.player.can_afford_defence_buildings(settings) { + for y in 0..settings.size.y { + if is_under_attack(state, y) { + let p_options = state.unoccupied_player_cells_in_row(settings, y); + if let Some(&p) = p_options.first() { + return Command::Build(p, BuildingType::Defense); + } + } + } + } + + if state.player.can_afford_all_buildings(settings) { + let options = state.unoccupied_player_cells(settings); + let option = options.first(); + let buildings = [BuildingType::Attack, BuildingType::Defense, BuildingType::Energy]; + let building = buildings.first(); + match (option, building) { + (Some(&p), Some(&building)) => Command::Build(p, building), + _ => Command::Nothing + } + } + else { + Command::Nothing + } +} + +fn is_under_attack(state: &engine::GameState, y: u8) -> bool { + let attack = state.opponent_buildings.iter() + .any(|b| b.pos.y == y && b.weapon_damage > 0); + let defences = state.player_buildings.iter() + .any(|b| b.pos.y == y && b.health > 5); + attack && !defences +} -- cgit v1.2.3