From d2cc33043ad1ca2d67b59ec8ca78a825442e5cda Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Mon, 25 Jun 2018 21:17:11 +0200 Subject: Added rule on maximum two tesla towers --- src/engine/command.rs | 4 ++-- src/engine/mod.rs | 25 +++++++++++++++++++++---- src/engine/settings.rs | 2 +- src/strategy/monte_carlo.rs | 21 ++++++++------------- 4 files changed, 32 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/engine/command.rs b/src/engine/command.rs index bcfc352..3ea0fbe 100644 --- a/src/engine/command.rs +++ b/src/engine/command.rs @@ -19,7 +19,7 @@ impl fmt::Display for Command { } #[repr(u8)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BuildingType { Defence = 0, Attack = 1, @@ -35,7 +35,7 @@ impl BuildingType { pub fn from_u8(id: u8) -> Option { use std::mem; - if id < 4 && id != 3 { Some(unsafe { mem::transmute(id) }) } else { None } + if id <= 4 && id != 3 { Some(unsafe { mem::transmute(id) }) } else { None } } } diff --git a/src/engine/mod.rs b/src/engine/mod.rs index a04f875..7a39214 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -156,6 +156,9 @@ impl GameState { debug_assert!(!buildings.iter().any(|b| b.pos == p)); debug_assert!(p.x < size.x && p.y < size.y); debug_assert!(player.energy >= blueprint.price); + debug_assert!(b != BuildingType::Tesla || + unconstructed_buildings.iter().filter(|b| b.weapon_damage == 20).count() + + buildings.iter().filter(|b| b.weapon_damage == 20).count() < 2); player.energy -= blueprint.price; unconstructed_buildings.push(UnconstructedBuilding::new(p, blueprint)); @@ -346,6 +349,16 @@ impl GameState { .chain(self.opponent_buildings.iter().map(|b| b.pos)) .collect() } + + pub fn count_player_teslas(&self) -> usize { + self.player_unconstructed_buildings.iter().filter(|b| b.weapon_damage == 20).count() + + self.player_buildings.iter().filter(|b| b.weapon_damage == 20).count() + } + + pub fn count_opponent_teslas(&self) -> usize { + self.opponent_unconstructed_buildings.iter().filter(|b| b.weapon_damage == 20).count() + + self.opponent_buildings.iter().filter(|b| b.weapon_damage == 20).count() + } } impl GameStatus { @@ -364,10 +377,13 @@ impl Player { } #[cfg(not(feature = "energy-cutoff"))] - pub fn sensible_buildings(&self, settings: &GameSettings) -> Vec { + pub fn sensible_buildings(&self, tesla_allowed: bool, settings: &GameSettings) -> Vec { let mut result = Vec::with_capacity(3); for b in BuildingType::all().iter() { - if settings.building_settings(*b).price <= self.energy { + let building_setting = settings.building_settings(*b); + let affordable = building_setting.price <= self.energy; + let is_tesla = building_setting.weapon_damage == 20; + if affordable && (!is_tesla || tesla_allowed) { result.push(*b); } } @@ -375,7 +391,7 @@ impl Player { } #[cfg(feature = "energy-cutoff")] - pub fn sensible_buildings(&self, settings: &GameSettings) -> Vec { + pub fn sensible_buildings(&self, tesla_allowed: bool, settings: &GameSettings) -> Vec { 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 as f32 <= ENERGY_STORAGE_CUTOFF * settings.max_building_price as f32; @@ -384,7 +400,8 @@ impl Player { 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) { + let is_tesla = building_setting.weapon_damage == 20; + if affordable && (!energy_producing || needs_energy) && (!is_tesla || tesla_allowed) { result.push(*b); } } diff --git a/src/engine/settings.rs b/src/engine/settings.rs index 3657cb2..18bdde0 100644 --- a/src/engine/settings.rs +++ b/src/engine/settings.rs @@ -26,7 +26,7 @@ pub struct BuildingSettings { impl GameSettings { pub fn new(size: Point, energy_income: u16, energy: BuildingSettings, defence: BuildingSettings, attack: BuildingSettings, tesla: BuildingSettings) -> GameSettings { - let max_building_price = cmp::max(cmp::max(energy.price, defence.price), attack.price); + let max_building_price = cmp::max(cmp::max(cmp::max(energy.price, defence.price), attack.price), tesla.price); GameSettings { size, energy_income, max_building_price, energy, defence, attack, tesla diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index 18b8acc..dbeac2f 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -75,36 +75,31 @@ fn simulate_to_endstate(command_score: &mut CommandScore, settings: &Gam } fn random_player_move(settings: &GameSettings, state: &GameState, rng: &mut R) -> Command { - let all_buildings = state.player.sensible_buildings(settings); - random_move(&state.unoccupied_player_cells, &state.occupied_player_cells(), &all_buildings, rng) + let all_buildings = state.player.sensible_buildings(state.count_player_teslas() < 2, settings); + random_move(&state.unoccupied_player_cells, &all_buildings, rng) } fn random_opponent_move(settings: &GameSettings, state: &GameState, rng: &mut R) -> Command { - let all_buildings = state.opponent.sensible_buildings(settings); - random_move(&state.unoccupied_opponent_cells, &state.occupied_opponent_cells(), &all_buildings, rng) + let all_buildings = state.opponent.sensible_buildings(state.count_opponent_teslas() < 2, settings); + random_move(&state.unoccupied_opponent_cells, &all_buildings, rng) } -fn random_move(free_positions: &[Point], occupied_positions: &[Point], all_buildings: &[BuildingType], rng: &mut R) -> Command { +fn random_move(free_positions: &[Point], all_buildings: &[BuildingType], rng: &mut R) -> Command { let building_command_count = free_positions.len()*all_buildings.len(); - let deconstruct_count = occupied_positions.len(); let nothing_count = 1; - let number_of_commands = building_command_count + deconstruct_count + nothing_count; + let number_of_commands = building_command_count + nothing_count; let choice_index = rng.gen_range(0, number_of_commands); if choice_index == number_of_commands - 1 { Command::Nothing - } else if choice_index < building_command_count { + } else { Command::Build( free_positions[choice_index/all_buildings.len()], all_buildings[choice_index%all_buildings.len()] ) - } else { - Command::Deconstruct( - occupied_positions[choice_index-building_command_count] - ) } } @@ -161,7 +156,7 @@ impl CommandScore { } fn init_command_scores(settings: &GameSettings, state: &GameState) -> Vec { - let all_buildings = state.player.sensible_buildings(settings); + let all_buildings = state.player.sensible_buildings(state.count_player_teslas() < 2, settings); let building_command_count = state.unoccupied_player_cells.len()*all_buildings.len(); let deconstruct_count = (settings.size.x as usize *settings.size.y as usize / 2) - state.unoccupied_player_cells.len(); -- cgit v1.2.3