From 629c70c86b0bb29d2d0c281add9d0d826a11c419 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Sun, 12 Aug 2018 20:01:34 +0200 Subject: Collapsed player info into the rest of the 'buildings' object --- src/engine/bitwise_engine.rs | 246 +++++++++++++++++++++---------------------- src/input/json.rs | 37 +++---- src/strategy/monte_carlo.rs | 14 +-- 3 files changed, 140 insertions(+), 157 deletions(-) diff --git a/src/engine/bitwise_engine.rs b/src/engine/bitwise_engine.rs index 1f8bf96..24189ee 100644 --- a/src/engine/bitwise_engine.rs +++ b/src/engine/bitwise_engine.rs @@ -8,24 +8,18 @@ use arrayvec::ArrayVec; const LEFT_COL_MASK: u64 = 0x0101_0101_0101_0101; const RIGHT_COL_MASK: u64 = 0x8080_8080_8080_8080; -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Player { - pub energy: u16, - pub health: u8 -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct BitwiseGameState { pub status: GameStatus, pub player: Player, pub opponent: Player, - pub player_buildings: PlayerBuildings, - pub opponent_buildings: PlayerBuildings, pub round: u16 } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct PlayerBuildings { +pub struct Player { + pub energy: u16, + pub health: u8, pub unconstructed: ArrayVec<[UnconstructedBuilding; MAX_CONCURRENT_CONSTRUCTION]>, pub buildings: [u64; DEFENCE_HEALTH], pub occupied: u64, @@ -59,25 +53,25 @@ pub struct TeslaCooldown { impl BitwiseGameState { pub fn simulate(&mut self, player_command: Command, opponent_command: Command) -> GameStatus { - BitwiseGameState::perform_command(&mut self.player, &mut self.player_buildings, player_command); - BitwiseGameState::perform_command(&mut self.opponent, &mut self.opponent_buildings, opponent_command); + BitwiseGameState::perform_command(&mut self.player, player_command); + BitwiseGameState::perform_command(&mut self.opponent, opponent_command); - BitwiseGameState::update_construction(&mut self.player_buildings); - BitwiseGameState::update_construction(&mut self.opponent_buildings); + BitwiseGameState::update_construction(&mut self.player); + BitwiseGameState::update_construction(&mut self.opponent); - BitwiseGameState::add_missiles(&mut self.player_buildings); - BitwiseGameState::add_missiles(&mut self.opponent_buildings); + BitwiseGameState::add_missiles(&mut self.player); + BitwiseGameState::add_missiles(&mut self.opponent); - BitwiseGameState::fire_teslas(&mut self.player, &mut self.player_buildings, &mut self.opponent, &mut self.opponent_buildings); + BitwiseGameState::fire_teslas(&mut self.player, &mut self.opponent); - BitwiseGameState::move_and_collide_missiles(&mut self.player, &mut self.player_buildings, &mut self.opponent_buildings.missiles); - BitwiseGameState::move_and_collide_missiles(&mut self.opponent, &mut self.opponent_buildings, &mut self.player_buildings.missiles); + BitwiseGameState::move_and_collide_missiles(&mut self.player, &mut self.opponent.missiles); + BitwiseGameState::move_and_collide_missiles(&mut self.opponent, &mut self.player.missiles); - BitwiseGameState::add_energy(&mut self.player, &mut self.player_buildings); - BitwiseGameState::add_energy(&mut self.opponent, &mut self.opponent_buildings); + BitwiseGameState::add_energy(&mut self.player); + BitwiseGameState::add_energy(&mut self.opponent); - BitwiseGameState::update_iron_curtain(&mut self.player_buildings, self.round); - BitwiseGameState::update_iron_curtain(&mut self.opponent_buildings, self.round); + BitwiseGameState::update_iron_curtain(&mut self.player, self.round); + BitwiseGameState::update_iron_curtain(&mut self.opponent, self.round); self.round += 1; @@ -85,30 +79,28 @@ impl BitwiseGameState { self.status } - pub fn player(&self) -> &Player { &self.player } - pub fn opponent(&self) -> &Player { &self.opponent } - pub fn player_has_max_teslas(&self) -> bool { self.player_buildings.count_teslas() >= TESLA_MAX } - pub fn opponent_has_max_teslas(&self) -> bool { self.opponent_buildings.count_teslas() >= TESLA_MAX } + pub fn player_has_max_teslas(&self) -> bool { self.player.count_teslas() >= TESLA_MAX } + pub fn opponent_has_max_teslas(&self) -> bool { self.opponent.count_teslas() >= TESLA_MAX } pub fn player_can_build_iron_curtain(&self) -> bool { - self.player_buildings.iron_curtain_available && self.player_buildings.iron_curtain_remaining == 0 && self.player.energy >= IRON_CURTAIN_PRICE + self.player.iron_curtain_available && self.player.iron_curtain_remaining == 0 && self.player.energy >= IRON_CURTAIN_PRICE } pub fn opponent_can_build_iron_curtain(&self) -> bool { - self.opponent_buildings.iron_curtain_available && self.opponent_buildings.iron_curtain_remaining == 0 && self.opponent.energy >= IRON_CURTAIN_PRICE + self.opponent.iron_curtain_available && self.opponent.iron_curtain_remaining == 0 && self.opponent.energy >= IRON_CURTAIN_PRICE } - pub fn unoccupied_player_cell_count(&self) -> usize { self.player_buildings.occupied.count_zeros() as usize } - pub fn unoccupied_opponent_cell_count(&self) -> usize { self.opponent_buildings.occupied.count_zeros() as usize } + pub fn unoccupied_player_cell_count(&self) -> usize { self.player.occupied.count_zeros() as usize } + pub fn unoccupied_opponent_cell_count(&self) -> usize { self.opponent.occupied.count_zeros() as usize } pub fn location_of_unoccupied_player_cell(&self, i: usize) -> Point { - let bit = find_bit_index_from_rank(self.player_buildings.occupied, i as u64); + let bit = find_bit_index_from_rank(self.player.occupied, i as u64); let point = Point { index: bit }; - debug_assert!(point.to_either_bitfield() & self.player_buildings.occupied == 0); + debug_assert!(point.to_either_bitfield() & self.player.occupied == 0); point } pub fn location_of_unoccupied_opponent_cell(&self, i: usize) -> Point { - let bit = find_bit_index_from_rank(self.opponent_buildings.occupied, i as u64); + let bit = find_bit_index_from_rank(self.opponent.occupied, i as u64); let point = Point { index: bit }; - debug_assert!(point.to_either_bitfield() & self.opponent_buildings.occupied == 0); + debug_assert!(point.to_either_bitfield() & self.opponent.occupied == 0); point } } @@ -145,13 +137,11 @@ fn find_bit_index_from_rank(occupied: u64, i: u64) -> u8 { impl BitwiseGameState { pub fn new( player: Player, opponent: Player, - player_buildings: PlayerBuildings, opponent_buildings: PlayerBuildings, round: u16 ) -> BitwiseGameState { BitwiseGameState { status: GameStatus::Continue, player, opponent, - player_buildings, opponent_buildings, round } } @@ -165,48 +155,48 @@ impl BitwiseGameState { pub fn sort(&mut self) { for i in 0..MISSILE_MAX_SINGLE_CELL { for j in i+1..MISSILE_MAX_SINGLE_CELL { - let move_down1 = !self.player_buildings.missiles[i].0 & self.player_buildings.missiles[j].0; - self.player_buildings.missiles[i].0 |= move_down1; - self.player_buildings.missiles[j].0 &= !move_down1; + let move_down1 = !self.player.missiles[i].0 & self.player.missiles[j].0; + self.player.missiles[i].0 |= move_down1; + self.player.missiles[j].0 &= !move_down1; - let move_down2 = !self.player_buildings.missiles[i].1 & self.player_buildings.missiles[j].1; - self.player_buildings.missiles[i].1 |= move_down2; - self.player_buildings.missiles[j].1 &= !move_down2; + let move_down2 = !self.player.missiles[i].1 & self.player.missiles[j].1; + self.player.missiles[i].1 |= move_down2; + self.player.missiles[j].1 &= !move_down2; - let move_down3 = !self.opponent_buildings.missiles[i].0 & self.opponent_buildings.missiles[j].0; - self.opponent_buildings.missiles[i].0 |= move_down3; - self.opponent_buildings.missiles[j].0 &= !move_down3; + let move_down3 = !self.opponent.missiles[i].0 & self.opponent.missiles[j].0; + self.opponent.missiles[i].0 |= move_down3; + self.opponent.missiles[j].0 &= !move_down3; - let move_down4 = !self.opponent_buildings.missiles[i].1 & self.opponent_buildings.missiles[j].1; - self.opponent_buildings.missiles[i].1 |= move_down4; - self.opponent_buildings.missiles[j].1 &= !move_down4; + let move_down4 = !self.opponent.missiles[i].1 & self.opponent.missiles[j].1; + self.opponent.missiles[i].1 |= move_down4; + self.opponent.missiles[j].1 &= !move_down4; } } - self.player_buildings.unconstructed.sort_by_key(|b| b.pos); - self.opponent_buildings.unconstructed.sort_by_key(|b| b.pos); + self.player.unconstructed.sort_by_key(|b| b.pos); + self.opponent.unconstructed.sort_by_key(|b| b.pos); - self.player_buildings.tesla_cooldowns.sort_by_key(|b| b.pos); - self.opponent_buildings.tesla_cooldowns.sort_by_key(|b| b.pos); + self.player.tesla_cooldowns.sort_by_key(|b| b.pos); + self.opponent.tesla_cooldowns.sort_by_key(|b| b.pos); - while self.player_buildings.firing_tower > 0 { - self.player_buildings.firing_tower -= 1; - let zero = self.player_buildings.missile_towers[0]; - for i in 1..self.player_buildings.missile_towers.len() { - self.player_buildings.missile_towers[i-1] = self.player_buildings.missile_towers[i]; + while self.player.firing_tower > 0 { + self.player.firing_tower -= 1; + let zero = self.player.missile_towers[0]; + for i in 1..self.player.missile_towers.len() { + self.player.missile_towers[i-1] = self.player.missile_towers[i]; } - let end = self.player_buildings.missile_towers.len()-1; - self.player_buildings.missile_towers[end] = zero; + let end = self.player.missile_towers.len()-1; + self.player.missile_towers[end] = zero; } - while self.opponent_buildings.firing_tower > 0 { - self.opponent_buildings.firing_tower -= 1; - let zero = self.opponent_buildings.missile_towers[0]; - for i in 1..self.opponent_buildings.missile_towers.len() { - self.opponent_buildings.missile_towers[i-1] = self.opponent_buildings.missile_towers[i]; + while self.opponent.firing_tower > 0 { + self.opponent.firing_tower -= 1; + let zero = self.opponent.missile_towers[0]; + for i in 1..self.opponent.missile_towers.len() { + self.opponent.missile_towers[i-1] = self.opponent.missile_towers[i]; } - let end = self.opponent_buildings.missile_towers.len()-1; - self.opponent_buildings.missile_towers[end] = zero; + let end = self.opponent.missile_towers.len()-1; + self.opponent.missile_towers[end] = zero; } } @@ -217,7 +207,7 @@ impl BitwiseGameState { res } - fn perform_command(player: &mut Player, player_buildings: &mut PlayerBuildings, command: Command) { + fn perform_command(player: &mut Player, command: Command) { match command { Command::Nothing => {}, Command::Build(p, b) => { @@ -238,74 +228,74 @@ impl BitwiseGameState { // This is used internally. I should not be making // invalid moves! - debug_assert!(player_buildings.buildings[0] & bitfield == 0); + debug_assert!(player.buildings[0] & bitfield == 0); debug_assert!(p.x() < FULL_MAP_WIDTH && p.y() < MAP_HEIGHT); debug_assert!(player.energy >= price); debug_assert!(b != BuildingType::Tesla || - player_buildings.count_teslas() < TESLA_MAX); + player.count_teslas() < TESLA_MAX); player.energy -= price; - player_buildings.unconstructed.push(UnconstructedBuilding { + player.unconstructed.push(UnconstructedBuilding { pos: p, construction_time_left: construction_time, building_type: b }); - player_buildings.occupied |= bitfield; + player.occupied |= bitfield; }, Command::Deconstruct(p) => { - let unconstructed_to_remove_index = player_buildings.unconstructed.iter().position(|ref b| b.pos == p); - let deconstruct_mask = !(p.to_either_bitfield() & player_buildings.buildings[0]); + let unconstructed_to_remove_index = player.unconstructed.iter().position(|ref b| b.pos == p); + let deconstruct_mask = !(p.to_either_bitfield() & player.buildings[0]); debug_assert!(deconstruct_mask != 0 || unconstructed_to_remove_index.is_some()); if let Some(i) = unconstructed_to_remove_index { - player_buildings.unconstructed.swap_remove(i); + player.unconstructed.swap_remove(i); } player.energy += DECONSTRUCT_ENERGY; - for tier in 0..player_buildings.buildings.len() { - player_buildings.buildings[tier] &= deconstruct_mask; + for tier in 0..player.buildings.len() { + player.buildings[tier] &= deconstruct_mask; } - player_buildings.energy_towers &= deconstruct_mask; - for tier in 0..player_buildings.missile_towers.len() { - player_buildings.missile_towers[tier] &= deconstruct_mask; + player.energy_towers &= deconstruct_mask; + for tier in 0..player.missile_towers.len() { + player.missile_towers[tier] &= deconstruct_mask; } - player_buildings.tesla_cooldowns.retain(|t| t.pos != p); - player_buildings.occupied &= deconstruct_mask; + player.tesla_cooldowns.retain(|t| t.pos != p); + player.occupied &= deconstruct_mask; }, Command::IronCurtain => { - debug_assert!(player_buildings.iron_curtain_available); + debug_assert!(player.iron_curtain_available); debug_assert!(player.energy >= IRON_CURTAIN_PRICE); player.energy -= IRON_CURTAIN_PRICE; - player_buildings.iron_curtain_available = false; - player_buildings.iron_curtain_remaining = IRON_CURTAIN_DURATION; + player.iron_curtain_available = false; + player.iron_curtain_remaining = IRON_CURTAIN_DURATION; } } } - fn update_construction(player_buildings: &mut PlayerBuildings) { - let mut buildings_len = player_buildings.unconstructed.len(); + fn update_construction(player: &mut Player) { + let mut buildings_len = player.unconstructed.len(); for i in (0..buildings_len).rev() { - if player_buildings.unconstructed[i].construction_time_left == 0 { - let building_type = player_buildings.unconstructed[i].building_type; + if player.unconstructed[i].construction_time_left == 0 { + let building_type = player.unconstructed[i].building_type; let health = if building_type == BuildingType::Defence { DEFENCE_HEALTH } else { 1 }; - let pos = player_buildings.unconstructed[i].pos; + let pos = player.unconstructed[i].pos; let bitfield = pos.to_either_bitfield(); for health_tier in 0..health { - player_buildings.buildings[health_tier] |= bitfield; + player.buildings[health_tier] |= bitfield; } if building_type == BuildingType::Energy { - player_buildings.energy_towers |= bitfield; + player.energy_towers |= bitfield; } if building_type == BuildingType::Attack { - player_buildings.missile_towers[player_buildings.firing_tower] |= bitfield; + player.missile_towers[player.firing_tower] |= bitfield; } if building_type == BuildingType::Tesla { - player_buildings.tesla_cooldowns.push(TeslaCooldown { + player.tesla_cooldowns.push(TeslaCooldown { pos, cooldown: 0, age: 0 @@ -313,36 +303,36 @@ impl BitwiseGameState { } buildings_len -= 1; - player_buildings.unconstructed.swap(i, buildings_len); + player.unconstructed.swap(i, buildings_len); } else { - player_buildings.unconstructed[i].construction_time_left -= 1 + player.unconstructed[i].construction_time_left -= 1 } } - player_buildings.unconstructed.truncate(buildings_len); + player.unconstructed.truncate(buildings_len); } - fn update_iron_curtain(player_buildings: &mut PlayerBuildings, round: u16) { + fn update_iron_curtain(player: &mut Player, round: u16) { if round != 0 && round % IRON_CURTAIN_UNLOCK_INTERVAL == 0 { - player_buildings.iron_curtain_available = true; + player.iron_curtain_available = true; } - player_buildings.iron_curtain_remaining = player_buildings.iron_curtain_remaining.saturating_sub(1); + player.iron_curtain_remaining = player.iron_curtain_remaining.saturating_sub(1); } - fn fire_teslas(player: &mut Player, player_buildings: &mut PlayerBuildings, opponent: &mut Player, opponent_buildings: &mut PlayerBuildings) { - BitwiseGameState::fire_single_players_teslas_without_cleanup(player, player_buildings, opponent, opponent_buildings); - BitwiseGameState::fire_single_players_teslas_without_cleanup(opponent, opponent_buildings, player, player_buildings); + fn fire_teslas(player: &mut Player, opponent: &mut Player) { + BitwiseGameState::fire_single_players_teslas_without_cleanup(player, opponent); + BitwiseGameState::fire_single_players_teslas_without_cleanup(opponent, player); - BitwiseGameState::update_tesla_activity(player_buildings); - BitwiseGameState::update_tesla_activity(opponent_buildings); + BitwiseGameState::update_tesla_activity(player); + BitwiseGameState::update_tesla_activity(opponent); } - fn fire_single_players_teslas_without_cleanup(player: &mut Player, player_buildings: &mut PlayerBuildings, opponent: &mut Player, opponent_buildings: &mut PlayerBuildings) { - player_buildings.tesla_cooldowns.sort_unstable_by(|a, b| b.age.cmp(&a.age)); - for tesla in player_buildings.tesla_cooldowns.iter_mut() { + fn fire_single_players_teslas_without_cleanup(player: &mut Player, opponent: &mut Player) { + player.tesla_cooldowns.sort_unstable_by(|a, b| b.age.cmp(&a.age)); + for tesla in player.tesla_cooldowns.iter_mut() { tesla.age += 1; if tesla.cooldown > 0 { tesla.cooldown -= 1; - } else if player.energy >= TESLA_FIRING_ENERGY && opponent_buildings.iron_curtain_remaining > 0 { + } else if player.energy >= TESLA_FIRING_ENERGY && opponent.iron_curtain_remaining > 0 { player.energy -= TESLA_FIRING_ENERGY; tesla.cooldown = TESLA_COOLDOWN; } else if player.energy >= TESLA_FIRING_ENERGY { @@ -363,31 +353,31 @@ impl BitwiseGameState { let mut hits = 0; for _ in 0..(if y == 0 || y == MAP_HEIGHT-1 { 2 } else { 3 }) { - hits |= destroy_mask & opponent_buildings.buildings[0]; + hits |= destroy_mask & opponent.buildings[0]; destroy_mask &= !hits; destroy_mask <<= SINGLE_MAP_WIDTH; } - BitwiseGameState::destroy_buildings(opponent_buildings, hits); + BitwiseGameState::destroy_buildings(opponent, hits); } } } - fn add_missiles(player_buildings: &mut PlayerBuildings) { - let mut missiles = player_buildings.missile_towers[player_buildings.firing_tower]; - for mut tier in &mut player_buildings.missiles { + fn add_missiles(player: &mut Player) { + let mut missiles = player.missile_towers[player.firing_tower]; + for mut tier in &mut player.missiles { let setting = !tier.0 & missiles; tier.0 |= setting; missiles &= !setting; } - player_buildings.firing_tower = (player_buildings.firing_tower + 1) % MISSILE_COOLDOWN_STATES; + player.firing_tower = (player.firing_tower + 1) % MISSILE_COOLDOWN_STATES; } - fn move_and_collide_missiles(opponent: &mut Player, opponent_buildings: &mut PlayerBuildings, player_missiles: &mut [(u64, u64); MISSILE_MAX_SINGLE_CELL]) { + fn move_and_collide_missiles(opponent: &mut Player, player_missiles: &mut [(u64, u64); MISSILE_MAX_SINGLE_CELL]) { let mut destroyed = 0; let mut damaging = 0; for _ in 0..MISSILE_SPEED { for missile in player_missiles.iter_mut() { - let swapping_sides = if opponent_buildings.iron_curtain_remaining > 0 { 0 } else { missile.0 & RIGHT_COL_MASK }; + let swapping_sides = if opponent.iron_curtain_remaining > 0 { 0 } else { missile.0 & RIGHT_COL_MASK }; let about_to_hit_opponent = missile.1 & LEFT_COL_MASK; missile.0 = (missile.0 & !RIGHT_COL_MASK) << 1; @@ -397,9 +387,9 @@ impl BitwiseGameState { let mut hits = 0; for health_tier in (0..DEFENCE_HEALTH).rev() { - hits = opponent_buildings.buildings[health_tier] & missile.1; + hits = opponent.buildings[health_tier] & missile.1; missile.1 &= !hits; - opponent_buildings.buildings[health_tier] &= !hits; + opponent.buildings[health_tier] &= !hits; } destroyed |= hits; } @@ -407,11 +397,11 @@ impl BitwiseGameState { let damage = damaging.count_ones() as u8 * MISSILE_DAMAGE; opponent.health = opponent.health.saturating_sub(damage); - BitwiseGameState::destroy_buildings(opponent_buildings, destroyed); - BitwiseGameState::update_tesla_activity(opponent_buildings); + BitwiseGameState::destroy_buildings(opponent, destroyed); + BitwiseGameState::update_tesla_activity(opponent); } - fn destroy_buildings(buildings: &mut PlayerBuildings, hit_mask: u64) { + fn destroy_buildings(buildings: &mut Player, hit_mask: u64) { let deconstruct_mask = !hit_mask; buildings.energy_towers &= deconstruct_mask; @@ -424,14 +414,14 @@ impl BitwiseGameState { buildings.occupied &= deconstruct_mask; } - fn update_tesla_activity(buildings: &mut PlayerBuildings) { + fn update_tesla_activity(buildings: &mut Player) { let occupied = buildings.occupied; buildings.tesla_cooldowns.retain(|t| (t.pos.to_either_bitfield() & occupied) != 0); } - fn add_energy(player: &mut Player, player_buildings: &mut PlayerBuildings) { - player.energy += player_buildings.energy_generated(); + fn add_energy(player: &mut Player) { + player.energy += player.energy_generated(); } fn update_status(&mut self) { @@ -447,14 +437,16 @@ impl BitwiseGameState { } -impl PlayerBuildings { +impl Player { pub fn count_teslas(&self) -> usize { self.tesla_cooldowns.len() + self.unconstructed.iter().filter(|t| t.building_type == BuildingType::Tesla).count() } - pub fn empty() -> PlayerBuildings { - PlayerBuildings { + pub fn empty() -> Player { + Player { + health: 0, + energy: 0, unconstructed: ArrayVec::new(), buildings: [0; DEFENCE_HEALTH], occupied: 0, diff --git a/src/input/json.rs b/src/input/json.rs index 544e5ed..2152fc2 100644 --- a/src/input/json.rs +++ b/src/input/json.rs @@ -73,26 +73,27 @@ struct MissileState { impl State { fn to_bitwise_engine(&self) -> bitwise_engine::BitwiseGameState { let json_player = self.player(); - let player = json_player.to_bitwise_engine(); let json_opponent = self.opponent(); - let opponent = json_opponent.to_bitwise_engine(); - let mut player_buildings = bitwise_engine::PlayerBuildings::empty(); - let mut opponent_buildings = bitwise_engine::PlayerBuildings::empty(); + let mut player = bitwise_engine::Player::empty(); + let mut opponent = bitwise_engine::Player::empty(); // TODO roll the player into the playerbuildings and remove this duplication - player_buildings.iron_curtain_available = json_player.iron_curtain_available; - player_buildings.iron_curtain_remaining = if json_player.active_iron_curtain_lifetime < 0 { + player.health = json_player.health; + player.energy = json_player.energy; + player.iron_curtain_available = json_player.iron_curtain_available; + player.iron_curtain_remaining = if json_player.active_iron_curtain_lifetime < 0 { 0 } else { json_player.active_iron_curtain_lifetime as u8 }; - opponent_buildings.iron_curtain_available = json_opponent.iron_curtain_available; - opponent_buildings.iron_curtain_remaining = if json_opponent.active_iron_curtain_lifetime < 0 { + opponent.health = json_opponent.health; + opponent.energy = json_opponent.energy; + opponent.iron_curtain_available = json_opponent.iron_curtain_available; + opponent.iron_curtain_remaining = if json_opponent.active_iron_curtain_lifetime < 0 { 0 } else { json_opponent.active_iron_curtain_lifetime as u8 }; - for row in &self.game_map { for cell in row { @@ -101,9 +102,9 @@ impl State { let building_type = building.convert_building_type(); let mut bitwise_buildings = if building.player_type == 'A' { - &mut player_buildings + &mut player } else { - &mut opponent_buildings + &mut opponent }; let bitfield = point.to_either_bitfield(); @@ -138,9 +139,9 @@ impl State { for missile in &cell.missiles { let (mut left, mut right) = engine::geometry::Point::new_double_bitfield(cell.x, cell.y, missile.player_type == 'A'); let mut bitwise_buildings = if missile.player_type == 'A' { - &mut player_buildings + &mut player } else { - &mut opponent_buildings + &mut opponent }; for mut tier in bitwise_buildings.missiles.iter_mut() { @@ -156,7 +157,6 @@ impl State { bitwise_engine::BitwiseGameState::new( player, opponent, - player_buildings, opponent_buildings, self.game_details.round ) } @@ -174,15 +174,6 @@ impl State { } } -impl Player { - fn to_bitwise_engine(&self) -> engine::bitwise_engine::Player { - engine::bitwise_engine::Player { - energy: self.energy, - health: self.health - } - } -} - impl BuildingState { fn to_bitwise_engine_unconstructed(&self) -> bitwise_engine::UnconstructedBuilding { bitwise_engine::UnconstructedBuilding { diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index 73ebf01..87033cb 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -1,7 +1,7 @@ use engine::command::*; use engine::geometry::*; use engine::status::GameStatus; -use engine::bitwise_engine::{Player, PlayerBuildings, BitwiseGameState}; +use engine::bitwise_engine::{Player, BitwiseGameState}; use engine::constants::*; use rand::{Rng, XorShiftRng, SeedableRng}; @@ -115,12 +115,12 @@ fn simulate_to_endstate(command_score: &mut CommandScore, state: &Bitwis } fn random_player_move(state: &BitwiseGameState, rng: &mut R) -> Command { - let all_buildings = sensible_buildings(&state.player, &state.player_buildings, state.player_has_max_teslas()); + let all_buildings = sensible_buildings(&state.player, state.player_has_max_teslas()); random_move(&all_buildings, state.player_can_build_iron_curtain(), rng, state.unoccupied_player_cell_count(), |i| state.location_of_unoccupied_player_cell(i)) } fn random_opponent_move(state: &BitwiseGameState, rng: &mut R) -> Command { - let all_buildings = sensible_buildings(&state.opponent, &state.opponent_buildings, state.opponent_has_max_teslas()); + let all_buildings = sensible_buildings(&state.opponent, state.opponent_has_max_teslas()); random_move(&all_buildings, state.opponent_can_build_iron_curtain(), rng, state.unoccupied_opponent_cell_count(), |i| state.location_of_unoccupied_opponent_cell(i)) } @@ -199,7 +199,7 @@ impl CommandScore { //TODO: Devalue nothing so that it doesn't stand and do nothing when it can do things fn init_command_scores(state: &BitwiseGameState) -> Vec { - let all_buildings = sensible_buildings(&state.player, &state.player_buildings, state.player_has_max_teslas()); + let all_buildings = sensible_buildings(&state.player, state.player_has_max_teslas()); let unoccupied_cells = (0..state.unoccupied_player_cell_count()).map(|i| state.location_of_unoccupied_player_cell(i)); @@ -222,7 +222,7 @@ impl CommandScore { } #[cfg(not(feature = "energy-cutoff"))] -fn sensible_buildings(player: &Player, _player_buildings: &PlayerBuildings, has_max_teslas: bool) -> Vec { +fn sensible_buildings(player: &Player, has_max_teslas: bool) -> Vec { let mut result = Vec::with_capacity(4); if DEFENCE_PRICE <= player.energy { @@ -245,9 +245,9 @@ fn sensible_buildings(player: &Player, _player_buildings: &PlayerBuildings, has_ //TODO: Heuristic that avoids building the initial energy towers all in the same row? Max energy in a row? //TODO: Update cutoff to maybe build iron curtains #[cfg(feature = "energy-cutoff")] -fn sensible_buildings(player: &Player, player_buildings: &PlayerBuildings, has_max_teslas: bool) -> Vec { +fn sensible_buildings(player: &Player, has_max_teslas: bool) -> Vec { let mut result = Vec::with_capacity(4); - let needs_energy = player_buildings.energy_generated() <= ENERGY_PRODUCTION_CUTOFF || + let needs_energy = player.energy_generated() <= ENERGY_PRODUCTION_CUTOFF || player.energy <= ENERGY_STORAGE_CUTOFF; if DEFENCE_PRICE <= player.energy { -- cgit v1.2.3