Collapsed player info into the rest of the 'buildings' object
authorJustin Worthe <justin@worthe-it.co.za>
Sun, 12 Aug 2018 18:01:34 +0000 (20:01 +0200)
committerJustin Worthe <justin@worthe-it.co.za>
Sun, 12 Aug 2018 18:01:34 +0000 (20:01 +0200)
src/engine/bitwise_engine.rs
src/input/json.rs
src/strategy/monte_carlo.rs

index 1f8bf96..24189ee 100644 (file)
@@ -9,23 +9,17 @@ 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,
index 544e5ed..2152fc2 100644 (file)
@@ -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 {
index 73ebf01..87033cb 100644 (file)
@@ -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<R: Rng>(command_score: &mut CommandScore, state: &Bitwis
 }
 
 fn random_player_move<R: Rng>(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<R: Rng>(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<CommandScore> {
-        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<BuildingType> {
+fn sensible_buildings(player: &Player, has_max_teslas: bool) -> Vec<BuildingType> {
     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<BuildingType> {
+fn sensible_buildings(player: &Player, has_max_teslas: bool) -> Vec<BuildingType> {
     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 {