From dbc008ad4d16072d181e0ac6949fab09a9c05801 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Mon, 27 Aug 2018 21:48:26 +0200 Subject: Removed branching around energy limiting heuristics --- src/engine/bitwise_engine.rs | 60 -------------------------------------------- src/engine/constants.rs | 2 -- src/input/json.rs | 2 -- src/strategy/monte_carlo.rs | 59 ++++++++++++------------------------------- 4 files changed, 16 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/engine/bitwise_engine.rs b/src/engine/bitwise_engine.rs index f8af86d..628fefc 100644 --- a/src/engine/bitwise_engine.rs +++ b/src/engine/bitwise_engine.rs @@ -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); - } } diff --git a/src/engine/constants.rs b/src/engine/constants.rs index 71d937d..9ece36d 100644 --- a/src/engine/constants.rs +++ b/src/engine/constants.rs @@ -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; diff --git a/src/input/json.rs b/src/input/json.rs index 6c83563..843f228 100644 --- a/src/input/json.rs +++ b/src/input/json.rs @@ -137,8 +137,6 @@ impl State { } } } - player.update_energy_towers_with_heuristics(); - opponent.update_energy_towers_with_heuristics(); bitwise_engine::BitwiseGameState::new( player, opponent, diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index 27caea8..7672dff 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -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(command_score: &mut CommandScore, state: &Bitwis fn random_move(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 { - let unoccupied_cells = (0..state.player.unoccupied_cell_count()).map(|i| state.player.location_of_unoccupied_cell(i)).collect::>(); - let unoccupied_energy_cells = (0..state.player.unoccupied_energy_cell_count()).map(|i| state.player.location_of_unoccupied_energy_cell(i)).collect::>(); - - 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() { -- cgit v1.2.3