From 7bf7d8d977733cb02258b4a79faf2417c52e9323 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Mon, 25 Jun 2018 19:04:29 +0200 Subject: Compilation, allowing new moves to be chosen, and missile move order --- src/engine/mod.rs | 64 +++++++++++++++++++++++++++------------------ src/strategy/monte_carlo.rs | 33 ++++++++++++++++++----- 2 files changed, 66 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 13ac0ac..15b7a4d 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -198,34 +198,48 @@ impl GameState { } fn fire_teslas(player: &mut Player, player_buildings: &mut Vec, opponent: &mut Player, opponent_buildings: &mut Vec, settings: &GameSettings) { - for tesla in player_buildings.iter().filter(|b| b.weapon_damage == 20) { - if tesla.pos.x + 1 >= settings.size.x/2 { - opponent.health = opponent.health.saturating_sub(settings.tesla.weapon_damage); - } - 'player_col_loop: for x in tesla.pos.x+1..tesla.pos.x+(settings.size.x/2)+2 { - for &y in [tesla.pos.y - 1, tesla.pos.y, tesla.pos.y + 1].iter() { - let target_point = Point::new(x, y); - for b in 0..opponent_buildings.len() { - if opponent_buildings[b].pos == target_point && opponent_buildings[b].health > 0 { - opponent_buildings[b].health = opponent_buildings[b].health.saturating_sub(settings.tesla.weapon_damage); - continue 'player_col_loop; + for tesla in player_buildings.iter_mut().filter(|b| b.weapon_damage == 20) { + if tesla.weapon_cooldown_time_left > 0 { + tesla.weapon_cooldown_time_left -= 1; + } else if player.energy >= 100 { + player.energy -= 100; + tesla.weapon_cooldown_time_left = tesla.weapon_cooldown_period; + + if tesla.pos.x + 1 >= settings.size.x/2 { + opponent.health = opponent.health.saturating_sub(settings.tesla.weapon_damage); + } + 'player_col_loop: for x in tesla.pos.x+1..tesla.pos.x+(settings.size.x/2)+2 { + for &y in [tesla.pos.y - 1, tesla.pos.y, tesla.pos.y + 1].iter() { + let target_point = Point::new(x, y); + for b in 0..opponent_buildings.len() { + if opponent_buildings[b].pos == target_point && opponent_buildings[b].health > 0 { + opponent_buildings[b].health = opponent_buildings[b].health.saturating_sub(settings.tesla.weapon_damage); + continue 'player_col_loop; + } } } } } } - for tesla in opponent_buildings.iter().filter(|b| b.weapon_damage == 20) { - if tesla.pos.x <= settings.size.x/2 { - player.health = player.health.saturating_sub(settings.tesla.weapon_damage); - } - 'opponent_col_loop: for x in tesla.pos.x.saturating_sub((settings.size.x/2)+1)..tesla.pos.x { - for &y in [tesla.pos.y - 1, tesla.pos.y, tesla.pos.y + 1].iter() { - let target_point = Point::new(x, y); - for b in 0..player_buildings.len() { - if player_buildings[b].pos == target_point && player_buildings[b].health > 0 { - player_buildings[b].health = player_buildings[b].health.saturating_sub(settings.tesla.weapon_damage); - continue 'opponent_col_loop; + for tesla in opponent_buildings.iter_mut().filter(|b| b.weapon_damage == 20) { + if tesla.weapon_cooldown_time_left > 0 { + tesla.weapon_cooldown_time_left -= 1; + } else if opponent.energy >= 100 { + opponent.energy -= 100; + tesla.weapon_cooldown_time_left = tesla.weapon_cooldown_period; + + if tesla.pos.x <= settings.size.x/2 { + player.health = player.health.saturating_sub(settings.tesla.weapon_damage); + } + 'opponent_col_loop: for x in tesla.pos.x.saturating_sub((settings.size.x/2)+1)..tesla.pos.x { + for &y in [tesla.pos.y - 1, tesla.pos.y, tesla.pos.y + 1].iter() { + let target_point = Point::new(x, y); + for b in 0..player_buildings.len() { + if player_buildings[b].pos == target_point && player_buildings[b].health > 0 { + player_buildings[b].health = player_buildings[b].health.saturating_sub(settings.tesla.weapon_damage); + continue 'opponent_col_loop; + } } } } @@ -253,8 +267,8 @@ impl GameState { fn move_missiles(missiles: &mut Vec, mut wrapping_move_fn: F, opponent_buildings: &mut Vec, opponent: &mut Player, unoccupied_cells: &mut Vec, settings: &GameSettings) where F: FnMut(&mut Point) { let mut missiles_len = missiles.len(); - 'missile_loop: for m in (0..missiles.len()).rev() { - 'speed_loop: for _ in 0..missiles[m].speed { + 'speed_loop: for _ in 0..settings.attack.weapon_speed { + 'missile_loop: for m in (0..missiles.len()).rev() { wrapping_move_fn(&mut missiles[m].pos); if missiles[m].pos.x >= settings.size.x { opponent.health = opponent.health.saturating_sub(missiles[m].damage); @@ -283,8 +297,8 @@ impl GameState { } } } + missiles.truncate(missiles_len); } - missiles.truncate(missiles_len); } fn add_energy(player: &mut Player) { diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index 0d813d3..1ea18db 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -76,25 +76,35 @@ 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, &all_buildings, rng) + random_move(&settings, &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, &all_buildings, rng) + random_move(&settings, &state.unoccupied_opponent_cells, &all_buildings, rng) } -fn random_move(all_positions: &[Point], all_buildings: &[BuildingType], rng: &mut R) -> Command { - let number_of_commands = all_positions.len()*all_buildings.len()+1; +fn random_move(settings: &GameSettings, all_positions: &[Point], all_buildings: &[BuildingType], rng: &mut R) -> Command { + + let building_command_count = all_positions.len()*all_buildings.len(); + let deconstruct_count = (settings.size.x as usize * settings.size.y as usize / 2) - all_positions.len(); + let nothing_count = 1; + + let number_of_commands = building_command_count + deconstruct_count + nothing_count; + let choice_index = rng.gen_range(0, number_of_commands); if choice_index == number_of_commands - 1 { Command::Nothing - } else { + } else if choice_index < building_command_count { Command::Build( all_positions[choice_index/all_buildings.len()], all_buildings[choice_index%all_buildings.len()] ) + } else { + Command::Deconstruct( + all_positions[choice_index-building_command_count] + ) } } @@ -153,7 +163,11 @@ impl CommandScore { fn init_command_scores(settings: &GameSettings, state: &GameState) -> Vec { let all_buildings = state.player.sensible_buildings(settings); - let mut commands = Vec::with_capacity(state.unoccupied_player_cells.len()*all_buildings.len()+1); + 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(); + let nothing_count = 1; + + let mut commands = Vec::with_capacity(building_command_count + deconstruct_count + nothing_count); commands.push(CommandScore::new(Command::Nothing)); for &position in &state.unoccupied_player_cells { @@ -162,6 +176,13 @@ impl CommandScore { } } + for building in &state.player_buildings { + commands.push(CommandScore::new(Command::Deconstruct(building.pos))); + } + for building in &state.player_unconstructed_buildings { + commands.push(CommandScore::new(Command::Deconstruct(building.pos))); + } + commands } } -- cgit v1.2.3