Removed branching around energy limiting heuristics
authorJustin Worthe <justin@worthe-it.co.za>
Mon, 27 Aug 2018 19:48:26 +0000 (21:48 +0200)
committerJustin Worthe <justin@worthe-it.co.za>
Mon, 27 Aug 2018 19:48:26 +0000 (21:48 +0200)
src/engine/bitwise_engine.rs
src/engine/constants.rs
src/input/json.rs
src/strategy/monte_carlo.rs

index f8af86d..628fefc 100644 (file)
@@ -34,8 +34,6 @@ pub struct Player {
 
     pub iron_curtain_available: bool,
     pub iron_curtain_remaining: u8,
-
-    pub energy_towers_with_heuristics: u64,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -75,9 +73,6 @@ impl BitwiseGameState {
         BitwiseGameState::update_iron_curtain(&mut self.player, self.round);
         BitwiseGameState::update_iron_curtain(&mut self.opponent, self.round);
 
-        self.player.update_energy_towers_with_heuristics();
-        self.opponent.update_energy_towers_with_heuristics();
-
         self.round += 1;
 
         self.update_status();
@@ -436,7 +431,6 @@ impl Player {
             tesla_cooldowns: ArrayVec::new(),
             iron_curtain_available: false,
             iron_curtain_remaining: 0,
-            energy_towers_with_heuristics: 0
         }
     }
 
@@ -459,58 +453,4 @@ impl Player {
         debug_assert!(point.to_either_bitfield() & self.occupied == 0);
         point
     }
-
-    pub fn update_energy_towers_with_heuristics(&mut self) {
-        self.energy_towers_with_heuristics = self.occupied;
-        for y in 0..MAP_HEIGHT {
-            let mask = 255u64 << (y*SINGLE_MAP_WIDTH);
-            let isolated_row = self.energy_towers & mask;
-            let row_count = isolated_row.count_ones();
-            self.energy_towers_with_heuristics |= if row_count >= ENERGY_MAX_IN_ROW {
-                mask
-            } else {
-                0
-            };
-        }
-    }
-
-    pub fn unoccupied_energy_cell_count(&self) -> usize {
-        self.energy_towers_with_heuristics.count_zeros() as usize
-    }
-    pub fn location_of_unoccupied_energy_cell(&self, i: usize) -> Point  {
-        let bit = find_bit_index_from_rank(self.energy_towers_with_heuristics, i as u64);
-        let point = Point { index: bit };
-        debug_assert!(point.to_either_bitfield() & self.occupied == 0);
-        point
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn energy_occupied_marks_empty_rows_appropriately() {
-        let mut player = Player::empty();
-        player.energy_towers = 0;
-        player.occupied = 0;
-        player.update_energy_towers_with_heuristics();
-
-        let expected = 0;
-        let actual = player.energy_towers_with_heuristics;
-
-        assert_eq!(expected, actual);
-    }
-        #[test]
-    fn energy_occupied_marks_full_first_row_appropriately() {
-        let mut player = Player::empty();
-        player.energy_towers = 0x00_07; //3 energy towers in first row, don't build more
-        player.occupied = 0x07_07; //3 more towers in second row, can still build by them
-        player.update_energy_towers_with_heuristics();
-
-        let expected = 0x07_ff;
-        let actual = player.energy_towers_with_heuristics;
-
-        assert_eq!(expected, actual);
-    }
 }
index 71d937d..9ece36d 100644 (file)
@@ -26,8 +26,6 @@ pub const ENERGY_GENERATED_TOWER: u16 = 3;
 pub const ENERGY_PRICE: u16 = 20;
 pub const ENERGY_CONSTRUCTION_TIME: u8 = 1;
 
-pub const ENERGY_MAX_IN_ROW: u32 = 3;
-
 pub const IRON_CURTAIN_PRICE: u16 = 100;
 pub const IRON_CURTAIN_UNLOCK_INTERVAL: u16 = 30;
 pub const IRON_CURTAIN_DURATION: u8 = 6;
index 6c83563..843f228 100644 (file)
@@ -137,8 +137,6 @@ impl State {
                 }
             }
         }
-        player.update_energy_towers_with_heuristics();
-        opponent.update_energy_towers_with_heuristics();
             
         bitwise_engine::BitwiseGameState::new(
             player, opponent,
index 27caea8..7672dff 100644 (file)
@@ -2,6 +2,7 @@ use engine::command::*;
 use engine::status::GameStatus;
 use engine::bitwise_engine::{Player, BitwiseGameState};
 use engine::constants::*;
+use engine::geometry::*;
 
 use std::fmt;
 
@@ -18,7 +19,7 @@ use time::{Duration, PreciseTime};
 use rayon::prelude::*;
 
 //TODO Rethink / adjust these?
-#[cfg(feature = "energy-cutoff")] pub const ENERGY_PRODUCTION_CUTOFF: u16 = 100;
+#[cfg(feature = "energy-cutoff")] pub const ENERGY_PRODUCTION_CUTOFF: u16 = 50;
 #[cfg(feature = "energy-cutoff")] pub const ENERGY_STORAGE_CUTOFF: u16 = 100;
 
 pub fn choose_move(state: &BitwiseGameState, start_time: PreciseTime, max_time: Duration) -> Command {
@@ -162,30 +163,17 @@ fn simulate_to_endstate<R: Rng>(command_score: &mut CommandScore, state: &Bitwis
 
 fn random_move<R: Rng>(player: &Player, rng: &mut R) -> Command {
     let free_positions_count = player.unoccupied_cell_count();
-    let unoccupied_energy_cell_count = player.unoccupied_energy_cell_count();
 
-    let open_energy_spot = unoccupied_energy_cell_count > 0;
     let open_building_spot = free_positions_count > 0;
 
-    let all_buildings = sensible_buildings(player, open_building_spot, open_energy_spot);
+    let all_buildings = sensible_buildings(player, open_building_spot);
 
     let iron_curtain_count = if player.can_build_iron_curtain() { 5 } else { 0 };
     let nothing_count = 1;
 
     let building_choice_index = rng.gen_range(0, all_buildings.len() + nothing_count + iron_curtain_count);
 
-    let choice_is_building = building_choice_index < all_buildings.len();
-    let choice_is_energy = choice_is_building && all_buildings[building_choice_index] == BuildingType::Energy;
-
-    if choice_is_energy {
-        let position_choice = rng.gen_range(0, unoccupied_energy_cell_count);
-        Command::Build(
-            player.location_of_unoccupied_energy_cell(position_choice),
-            BuildingType::Energy
-        )
-
-    }
-    else if choice_is_building {
+    if building_choice_index < all_buildings.len() {
         let position_choice = rng.gen_range(0, free_positions_count);
         Command::Build(
             player.location_of_unoccupied_cell(position_choice),
@@ -223,18 +211,6 @@ impl CommandScore {
         }
     }
 
-    fn with_seeded_stalemate(command: Command) -> CommandScore {
-        CommandScore {
-            command,
-            victories: 0,
-            defeats: 0,
-            draws: 0,
-            stalemates: 0,
-            attempts: 1,
-            next_seed: INIT_SEED
-        }
-    }
-
     fn add_victory(&mut self, next_seed: [u8; 16]) {
         self.victories += 1;
         self.attempts += 1;
@@ -264,14 +240,13 @@ impl CommandScore {
     }
 
     fn init_command_scores(state: &BitwiseGameState) -> Vec<CommandScore> {
-        let unoccupied_cells = (0..state.player.unoccupied_cell_count()).map(|i| state.player.location_of_unoccupied_cell(i)).collect::<Vec<_>>();
-        let unoccupied_energy_cells = (0..state.player.unoccupied_energy_cell_count()).map(|i| state.player.location_of_unoccupied_energy_cell(i)).collect::<Vec<_>>();
-
-        let open_building_spot = unoccupied_cells.len() > 0;
-        let open_energy_spot = unoccupied_energy_cells.len() > 0;
+        let unoccupied_cells_count = state.player.unoccupied_cell_count();
+        let unoccupied_cells = (0..unoccupied_cells_count)
+            .map(|i| state.player.location_of_unoccupied_cell(i));
 
+        let open_building_spot = unoccupied_cells_count > 0;
         
-        let all_buildings = sensible_buildings(&state.player, open_building_spot, open_energy_spot);
+        let all_buildings = sensible_buildings(&state.player, open_building_spot);
 
         let building_command_count = unoccupied_cells.len()*all_buildings.len();
         
@@ -281,11 +256,9 @@ impl CommandScore {
             commands.push(CommandScore::new(Command::IronCurtain));
         }
 
-        for &building in &all_buildings {
-            let cells = if building == BuildingType::Energy { &unoccupied_energy_cells } else { &unoccupied_cells };
-            for position in cells {
-
-                commands.push(CommandScore::new(Command::Build(*position, building)));
+        for position in unoccupied_cells {
+            for &building in &all_buildings {
+                commands.push(CommandScore::new(Command::Build(position, building)));
             }
         }
 
@@ -301,7 +274,7 @@ impl fmt::Display for CommandScore {
 
 
 #[cfg(not(feature = "energy-cutoff"))]
-fn sensible_buildings(player: &Player, open_building_spot: bool, open_energy_spot: bool) -> ArrayVec<[BuildingType;4]> {
+fn sensible_buildings(player: &Player, open_building_spot: bool) -> ArrayVec<[BuildingType;4]> {
     let mut result = ArrayVec::new();
     if !open_building_spot {
         return result;
@@ -313,7 +286,7 @@ fn sensible_buildings(player: &Player, open_building_spot: bool, open_energy_spo
     if MISSILE_PRICE <= player.energy {
         result.push(BuildingType::Attack);
     }
-    if ENERGY_PRICE <= player.energy && open_energy_spot {
+    if ENERGY_PRICE <= player.energy {
         result.push(BuildingType::Energy);
     }
     if TESLA_PRICE <= player.energy && !player.has_max_teslas() {
@@ -324,7 +297,7 @@ fn sensible_buildings(player: &Player, open_building_spot: bool, open_energy_spo
 }
 
 #[cfg(feature = "energy-cutoff")]
-fn sensible_buildings(player: &Player, open_building_spot: bool, open_energy_spot: bool) -> ArrayVec<[BuildingType;4]> {
+fn sensible_buildings(player: &Player, open_building_spot: bool) -> ArrayVec<[BuildingType;4]> {
     let mut result = ArrayVec::new();
     if !open_building_spot {
         return result;
@@ -339,7 +312,7 @@ fn sensible_buildings(player: &Player, open_building_spot: bool, open_energy_spo
     if MISSILE_PRICE <= player.energy {
         result.push(BuildingType::Attack);
     }
-    if ENERGY_PRICE <= player.energy && open_energy_spot && needs_energy {
+    if ENERGY_PRICE <= player.energy && needs_energy {
         result.push(BuildingType::Energy);
     }
     if TESLA_PRICE <= player.energy && !player.has_max_teslas() {