From 286763000e4e5919c07f2840c64ecc7932530175 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Mon, 25 Jun 2018 20:26:05 +0200 Subject: Updated test cases and made engine work correctly according to tests I don't think a tesla appeared in this match. I need to contrive a bot to build one. --- src/engine/command.rs | 2 +- src/engine/mod.rs | 89 ++++++++++++++++++++++++++------------------- src/input/json.rs | 2 +- src/strategy/monte_carlo.rs | 21 +++++------ 4 files changed, 62 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/engine/command.rs b/src/engine/command.rs index 7a2594d..bcfc352 100644 --- a/src/engine/command.rs +++ b/src/engine/command.rs @@ -13,7 +13,7 @@ impl fmt::Display for Command { match *self { Command::Nothing => write!(f, ""), Command::Build(p, b) => write!(f, "{},{},{}", p.x, p.y, b as u8), - Command::Deconstruct(p) => write!(f, "3,{},{}", p.x, p.y), + Command::Deconstruct(p) => write!(f, "{},{},3", p.x, p.y), } } } diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 15b7a4d..a04f875 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -119,6 +119,11 @@ impl GameState { return; } + GameState::perform_construct_command(&mut self.player_unconstructed_buildings, &mut self.player_buildings, &mut self.player, &mut self.unoccupied_player_cells, settings, player_command, &settings.size); + GameState::perform_construct_command(&mut self.opponent_unconstructed_buildings, &mut self.opponent_buildings, &mut self.opponent, &mut self.unoccupied_opponent_cells, settings, opponent_command, &settings.size); + GameState::perform_deconstruct_command(&mut self.player_unconstructed_buildings, &mut self.player_buildings, &mut self.player, &mut self.unoccupied_player_cells, player_command); + GameState::perform_deconstruct_command(&mut self.opponent_unconstructed_buildings, &mut self.opponent_buildings, &mut self.opponent, &mut self.unoccupied_opponent_cells, opponent_command); + GameState::update_construction(&mut self.player_unconstructed_buildings, &mut self.player_buildings, &mut self.player); GameState::update_construction(&mut self.opponent_unconstructed_buildings, &mut self.opponent_buildings, &mut self.opponent); @@ -138,47 +143,44 @@ impl GameState { GameState::add_energy(&mut self.player); GameState::add_energy(&mut self.opponent); - - GameState::perform_command(&mut self.player_unconstructed_buildings, &mut self.player_buildings, &mut self.player, &mut self.unoccupied_player_cells, settings, player_command, &settings.size); - GameState::perform_command(&mut self.opponent_unconstructed_buildings, &mut self.opponent_buildings, &mut self.opponent, &mut self.unoccupied_opponent_cells, settings, opponent_command, &settings.size); GameState::update_status(self); } - fn perform_command(unconstructed_buildings: &mut Vec, buildings: &mut Vec, player: &mut Player, unoccupied_cells: &mut Vec, settings: &GameSettings, command: Command, size: &Point) { - match command { - Command::Nothing => { }, - Command::Build(p, b) => { - let blueprint = settings.building_settings(b); + fn perform_construct_command(unconstructed_buildings: &mut Vec, buildings: &mut Vec, player: &mut Player, unoccupied_cells: &mut Vec, settings: &GameSettings, command: Command, size: &Point) { + if let Command::Build(p, b) = command { + let blueprint = settings.building_settings(b); - // This is used internally. I should not be making - // invalid moves! - 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); + // This is used internally. I should not be making + // invalid moves! + 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); - player.energy -= blueprint.price; - unconstructed_buildings.push(UnconstructedBuilding::new(p, blueprint)); - - let to_remove_index = unoccupied_cells.iter().position(|&pos| pos == p).unwrap(); - unoccupied_cells.swap_remove(to_remove_index); - }, - Command::Deconstruct(p) => { - let to_remove_index = buildings.iter().position(|ref b| b.pos == p); - if let Some(i) = to_remove_index { - buildings.swap_remove(i); - } - let unconstructed_to_remove_index = unconstructed_buildings.iter().position(|ref b| b.pos == p); - if let Some(i) = unconstructed_to_remove_index { - unconstructed_buildings.swap_remove(i); - } - - debug_assert!(to_remove_index.is_some() || unconstructed_to_remove_index.is_some()); - - player.energy += 5; - - unoccupied_cells.push(p); - }, + player.energy -= blueprint.price; + unconstructed_buildings.push(UnconstructedBuilding::new(p, blueprint)); + + let to_remove_index = unoccupied_cells.iter().position(|&pos| pos == p).unwrap(); + unoccupied_cells.swap_remove(to_remove_index); + } + } + fn perform_deconstruct_command(unconstructed_buildings: &mut Vec, buildings: &mut Vec, player: &mut Player, unoccupied_cells: &mut Vec, command: Command) { + if let Command::Deconstruct(p) = command { + let to_remove_index = buildings.iter().position(|ref b| b.pos == p); + let unconstructed_to_remove_index = unconstructed_buildings.iter().position(|ref b| b.pos == p); + debug_assert!(to_remove_index.is_some() || unconstructed_to_remove_index.is_some()); + + if let Some(i) = to_remove_index { + player.energy_generated -= buildings[i].energy_generated_per_turn; + buildings.swap_remove(i); + } + if let Some(i) = unconstructed_to_remove_index { + unconstructed_buildings.swap_remove(i); + } + + player.energy += 5; + + unoccupied_cells.push(p); } } @@ -209,7 +211,7 @@ impl GameState { 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() { + for &y in [tesla.pos.y.saturating_sub(1), tesla.pos.y, tesla.pos.y.saturating_add(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 { @@ -233,7 +235,7 @@ impl GameState { 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() { + for &y in [tesla.pos.y.saturating_sub(1), tesla.pos.y, tesla.pos.y.saturating_add(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 { @@ -332,6 +334,18 @@ impl GameState { } result } + + + pub fn occupied_player_cells(&self) -> Vec { + self.player_unconstructed_buildings.iter().map(|b| b.pos) + .chain(self.player_buildings.iter().map(|b| b.pos)) + .collect() + } + pub fn occupied_opponent_cells(&self) -> Vec { + self.opponent_unconstructed_buildings.iter().map(|b| b.pos) + .chain(self.opponent_buildings.iter().map(|b| b.pos)) + .collect() + } } impl GameStatus { @@ -376,7 +390,6 @@ impl Player { } result } - } impl UnconstructedBuilding { diff --git a/src/input/json.rs b/src/input/json.rs index 95dbd46..a2f6d8c 100644 --- a/src/input/json.rs +++ b/src/input/json.rs @@ -188,7 +188,7 @@ impl BuildingBlueprint { engine::settings::BuildingSettings { price: self.price, health: self.health, - construction_time: self.construction_time-2, + construction_time: self.construction_time-1, weapon_damage: self.weapon_damage, weapon_speed: self.weapon_speed, weapon_cooldown_period: self.weapon_cooldown_period, diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index 1ea18db..18b8acc 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -76,18 +76,18 @@ 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(&settings, &state.unoccupied_player_cells, &all_buildings, rng) + random_move(&state.unoccupied_player_cells, &state.occupied_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(&settings, &state.unoccupied_opponent_cells, &all_buildings, rng) + random_move(&state.unoccupied_opponent_cells, &state.occupied_opponent_cells(), &all_buildings, rng) } -fn random_move(settings: &GameSettings, all_positions: &[Point], all_buildings: &[BuildingType], rng: &mut R) -> Command { +fn random_move(free_positions: &[Point], occupied_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 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; @@ -98,12 +98,12 @@ fn random_move(settings: &GameSettings, all_positions: &[Point], all_bui Command::Nothing } else if choice_index < building_command_count { Command::Build( - all_positions[choice_index/all_buildings.len()], + free_positions[choice_index/all_buildings.len()], all_buildings[choice_index%all_buildings.len()] ) } else { Command::Deconstruct( - all_positions[choice_index-building_command_count] + occupied_positions[choice_index-building_command_count] ) } } @@ -176,11 +176,8 @@ 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))); + for &position in &state.occupied_player_cells() { + commands.push(CommandScore::new(Command::Deconstruct(position))); } commands -- cgit v1.2.3