Added pruning of buying energy buildings behind a feature flag
authorJustin Worthe <justin@worthe-it.co.za>
Sat, 9 Jun 2018 08:27:29 +0000 (10:27 +0200)
committerJustin Worthe <justin@worthe-it.co.za>
Sat, 9 Jun 2018 08:27:29 +0000 (10:27 +0200)
Cargo.toml
src/engine/mod.rs
src/strategy/mod.rs
src/strategy/monte_carlo.rs
src/strategy/sample.rs [deleted file]

index da4623f..4c11e57 100644 (file)
@@ -15,3 +15,4 @@ rayon = "1.0.1"
 [features]
 benchmarking = []
 single-threaded = []
+energy-cutoff = []
index a649453..28583a1 100644 (file)
@@ -8,6 +8,9 @@ use self::settings::{GameSettings, BuildingSettings};
 
 use std::ops::FnMut;
 
+#[cfg(feature = "energy-cutoff")] pub const ENERGY_PRODUCTION_CUTOFF: f32 = 2.;
+#[cfg(feature = "energy-cutoff")] pub const ENERGY_STORAGE_CUTOFF: u16 = 10;
+
 #[derive(Debug, Clone, PartialEq)]
 pub struct GameState {
     pub status: GameStatus,
@@ -259,24 +262,6 @@ impl GameState {
         }
         result
     }
-
-    pub fn player_affordable_buildings(&self, settings: &GameSettings) -> Vec<BuildingType> {
-        GameState::affordable_buildings(self.player.energy, settings)
-    }
-
-    pub fn opponent_affordable_buildings(&self, settings: &GameSettings) -> Vec<BuildingType> {
-        GameState::affordable_buildings(self.opponent.energy, settings)
-    }
-
-    fn affordable_buildings(energy: u16, settings: &GameSettings) -> Vec<BuildingType> {
-        let mut result = Vec::with_capacity(3);
-        for b in BuildingType::all().iter() {
-            if settings.building_settings(*b).price <= energy {
-                result.push(*b);
-            }
-        }
-        result
-    }
 }
 
 impl GameStatus {
@@ -293,21 +278,33 @@ impl Player {
             energy_generated: settings.energy_income + buildings.iter().map(|b| b.energy_generated_per_turn).sum::<u16>()
         }
     }
-    
-    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
+    #[cfg(not(feature = "energy-cutoff"))]
+    pub fn sensible_buildings(&self, settings: &GameSettings) -> Vec<BuildingType> {
+        let mut result = Vec::with_capacity(3);
+        for b in BuildingType::all().iter() {
+            if settings.building_settings(*b).price <= self.energy {
+                result.push(*b);
+            }
+        }
+        result
     }
-    pub fn can_afford_energy_buildings(&self, settings: &GameSettings) -> bool {
-        self.energy >= settings.energy.price
+
+    #[cfg(feature = "energy-cutoff")]
+    pub fn sensible_buildings(&self, settings: &GameSettings) -> Vec<BuildingType> {
+        let mut result = Vec::with_capacity(3);
+        let needs_energy = self.energy_generated as f32 >= ENERGY_PRODUCTION_CUTOFF * settings.max_building_price as f32 &&
+            self.energy >= ENERGY_STORAGE_CUTOFF * settings.max_building_price;
+            
+        for b in BuildingType::all().iter() {
+            let building_setting = settings.building_settings(*b);
+            let affordable = building_setting.price <= self.energy;
+            let energy_producing = building_setting.energy_generated_per_turn > 0;
+            if affordable && (!energy_producing || needs_energy) {
+                result.push(*b);
+            }
+        }
+        result
     }
 
 }
index 9630c48..5b6e779 100644 (file)
@@ -1,2 +1 @@
-pub mod sample;
 pub mod monte_carlo;
index c2f3561..0d813d3 100644 (file)
@@ -75,12 +75,12 @@ fn simulate_to_endstate<R: Rng>(command_score: &mut CommandScore, settings: &Gam
 }
 
 fn random_player_move<R: Rng>(settings: &GameSettings, state: &GameState, rng: &mut R) -> Command {
-    let all_buildings = state.player_affordable_buildings(settings);
+    let all_buildings = state.player.sensible_buildings(settings);
     random_move(&state.unoccupied_player_cells, &all_buildings, rng)
 }
 
 fn random_opponent_move<R: Rng>(settings: &GameSettings, state: &GameState, rng: &mut R) -> Command {
-    let all_buildings = state.opponent_affordable_buildings(settings);
+    let all_buildings = state.opponent.sensible_buildings(settings);
     random_move(&state.unoccupied_opponent_cells, &all_buildings, rng)
 }
 
@@ -151,7 +151,7 @@ impl CommandScore {
     }
     
     fn init_command_scores(settings: &GameSettings, state: &GameState) -> Vec<CommandScore> {
-        let all_buildings = state.player_affordable_buildings(settings);
+        let all_buildings = state.player.sensible_buildings(settings);
 
         let mut commands = Vec::with_capacity(state.unoccupied_player_cells.len()*all_buildings.len()+1);
         commands.push(CommandScore::new(Command::Nothing));
diff --git a/src/strategy/sample.rs b/src/strategy/sample.rs
deleted file mode 100644 (file)
index 370df2f..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-use engine;
-use engine::command::*;
-
-use rand::{thread_rng, Rng};
-
-pub fn choose_move(settings: &engine::settings::GameSettings, state: &engine::GameState) -> Command {
-    let mut rng = thread_rng();
-    
-    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(y);
-                if let Some(&p) = rng.choose(&p_options) {
-                    return Command::Build(p, BuildingType::Defence);
-                }
-            }
-        }
-    }
-
-    if state.player.can_afford_all_buildings(settings) {
-        let option = rng.choose(&state.unoccupied_player_cells);
-        let buildings = [BuildingType::Attack, BuildingType::Defence, BuildingType::Energy];
-        let building = rng.choose(&buildings);
-        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
-}