diff options
-rw-r--r-- | src/engine/bitwise_engine.rs | 2 | ||||
-rw-r--r-- | src/engine/command.rs | 25 | ||||
-rw-r--r-- | src/strategy/monte_carlo.rs | 32 |
3 files changed, 44 insertions, 15 deletions
diff --git a/src/engine/bitwise_engine.rs b/src/engine/bitwise_engine.rs index 873b6e5..d54ccc0 100644 --- a/src/engine/bitwise_engine.rs +++ b/src/engine/bitwise_engine.rs @@ -333,7 +333,7 @@ impl Player { } pub fn can_build_iron_curtain(&self) -> bool { - self.iron_curtain_available && self.iron_curtain_remaining == 0 && self.energy >= IRON_CURTAIN_PRICE + self.iron_curtain_available && self.iron_curtain_remaining == 0 } pub fn unoccupied_cell_count(&self) -> usize { self.occupied.count_zeros() as usize } diff --git a/src/engine/command.rs b/src/engine/command.rs index d026bca..764e3cb 100644 --- a/src/engine/command.rs +++ b/src/engine/command.rs @@ -1,4 +1,5 @@ use std::fmt; +use super::constants::*; use super::geometry::Point; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -18,6 +19,19 @@ impl fmt::Display for Command { } } +impl Command { + pub fn cant_build_yet(&self, energy: u16) -> bool { + use self::Command::*; + + match self { + Nothing => false, + Build(_, b) => b.cant_build_yet(energy), + IronCurtain => energy < IRON_CURTAIN_PRICE + } + } +} + + #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BuildingType { @@ -38,4 +52,15 @@ impl BuildingType { if id <= 4 && id != 3 { Some(unsafe { mem::transmute(id) }) } else { None } } + pub fn cant_build_yet(&self, energy: u16) -> bool { + use self::BuildingType::*; + + let required = match self { + Defence => DEFENCE_PRICE, + Attack => MISSILE_PRICE, + Energy => ENERGY_PRICE, + Tesla => TESLA_PRICE + }; + energy < required + } } diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index b8d89aa..971fc1d 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -28,7 +28,7 @@ pub fn choose_move(state: &BitwiseGameState, start_time: PreciseTime, max_time: let command = { let best_command_score = simulate_options_to_timeout(&mut command_scores, state, start_time, max_time); match best_command_score { - Some(best_command_score) => best_command_score.command, + Some(best) if !best.starts_with_nothing => best.command, _ => Command::Nothing } }; @@ -139,15 +139,21 @@ fn simulate_all_options_once(command_scores: &mut[CommandScore], state: &Bitwise fn simulate_to_endstate<R: Rng>(command_score: &mut CommandScore, state: &BitwiseGameState, rng: &mut R) { let mut state_mut = state.clone(); - let opponent_first = random_move(&state_mut.opponent, rng); - let mut status = state_mut.simulate(command_score.command, opponent_first); + let mut status = GameStatus::Continue; //state_mut.simulate(command_score.command, opponent_first); + let mut first_move_made = false; for _ in 0..MAX_MOVES { if status != GameStatus::Continue { break; } - let player_command = random_move(&state_mut.player, rng); + let player_command = if first_move_made { + random_move(&state_mut.player, rng) + } else { + let do_nothing = command_score.command.cant_build_yet(state_mut.player.energy); + first_move_made = !do_nothing; + if do_nothing { Command::Nothing } else { command_score.command } + }; let opponent_command = random_move(&state_mut.opponent, rng); status = state_mut.simulate(player_command, opponent_command); } @@ -169,7 +175,7 @@ fn random_move<R: Rng>(player: &Player, rng: &mut R) -> Command { let all_buildings = sensible_buildings(player, open_building_spot); - let iron_curtain_count = if player.can_build_iron_curtain() { 5 } else { 0 }; + let iron_curtain_count = if player.can_build_iron_curtain() && player.energy >= IRON_CURTAIN_PRICE { 1 } else { 0 }; let nothing_count = 1; let building_choice_index = rng.gen_range(0, all_buildings.len() + nothing_count + iron_curtain_count); @@ -191,6 +197,7 @@ fn random_move<R: Rng>(player: &Player, rng: &mut R) -> Command { #[derive(Debug)] struct CommandScore { command: Command, + starts_with_nothing: bool, victories: u32, defeats: u32, draws: u32, @@ -200,9 +207,9 @@ struct CommandScore { } impl CommandScore { - fn new(command: Command) -> CommandScore { + fn new(command: Command, starts_with_nothing: bool) -> CommandScore { CommandScore { - command, + command, starts_with_nothing, victories: 0, defeats: 0, draws: 0, @@ -245,21 +252,18 @@ impl CommandScore { 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); + let all_buildings = [BuildingType::Defence, BuildingType::Attack, BuildingType::Energy, BuildingType::Tesla]; let building_command_count = unoccupied_cells.len()*all_buildings.len(); - let mut commands = Vec::with_capacity(building_command_count + 2); - commands.push(CommandScore::new(Command::Nothing)); + let mut commands = Vec::with_capacity(building_command_count + 1); if state.player.can_build_iron_curtain() { - commands.push(CommandScore::new(Command::IronCurtain)); + commands.push(CommandScore::new(Command::IronCurtain, state.player.energy < IRON_CURTAIN_PRICE)); } for position in unoccupied_cells { for &building in &all_buildings { - commands.push(CommandScore::new(Command::Build(position, building))); + commands.push(CommandScore::new(Command::Build(position, building), building.cant_build_yet(state.player.energy))); } } |