Removed expressive engine
authorJustin Worthe <justin@worthe-it.co.za>
Thu, 9 Aug 2018 11:10:14 +0000 (13:10 +0200)
committerJustin Worthe <justin@worthe-it.co.za>
Thu, 9 Aug 2018 11:10:14 +0000 (13:10 +0200)
Refocus on the bitwise idea. It's faster, and has more potential for
speed. Also, it works well as a way of thinking on the puzzle as a
whole.

src/bin/perf-test.rs
src/engine/expressive_engine.rs [deleted file]
src/engine/mod.rs
src/input/json.rs
tests/expressive_to_bitwise_comparison.rs [deleted file]

index 8d6a490..8c93f5a 100644 (file)
@@ -13,20 +13,6 @@ fn main() {
     bitwise();
 }
 
-fn _expressive() {
-    println!("Running expressive engine");
-    let start_time = PreciseTime::now();
-    let (settings, state) = match input::json::read_expressive_state_from_file(STATE_PATH) {
-        Ok(ok) => ok,
-        Err(error) => {
-            println!("Error while parsing JSON file: {}", error);
-            process::exit(1);
-        }
-    };
-    let max_time = Duration::milliseconds(MAX_TIME_MILLIS);
-    strategy::monte_carlo::choose_move(&settings, &state, &start_time, max_time);
-}
-
 fn bitwise() {
     println!("Running bitwise engine");
     let start_time = PreciseTime::now();
diff --git a/src/engine/expressive_engine.rs b/src/engine/expressive_engine.rs
deleted file mode 100644 (file)
index 557e0fa..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-use std::ops::FnMut;
-use engine::command::{Command, BuildingType};
-use engine::geometry::Point;
-use engine::settings::{GameSettings, BuildingSettings};
-use engine::{GameStatus, Player, GameState};
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct ExpressiveGameState {
-    pub status: GameStatus,
-    pub player: Player,
-    pub opponent: Player,
-    pub player_unconstructed_buildings: Vec<UnconstructedBuilding>,
-    pub player_buildings: Vec<Building>,
-    pub unoccupied_player_cells: Vec<Point>,
-    pub opponent_unconstructed_buildings: Vec<UnconstructedBuilding>,
-    pub opponent_buildings: Vec<Building>,
-    pub unoccupied_opponent_cells: Vec<Point>,
-    pub player_missiles: Vec<Missile>,
-    pub opponent_missiles: Vec<Missile>
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct UnconstructedBuilding {
-    pub pos: Point,
-    pub health: u8,
-    pub construction_time_left: u8,
-    pub weapon_damage: u8,
-    pub weapon_speed: u8,
-    pub weapon_cooldown_period: u8,
-    pub energy_generated_per_turn: u16
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct Building {
-    pub pos: Point,
-    pub health: u8,
-    pub weapon_damage: u8,
-    pub weapon_speed: u8,
-    pub weapon_cooldown_time_left: u8,
-    pub weapon_cooldown_period: u8,
-    pub energy_generated_per_turn: u16,
-    pub age: u16
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct Missile {
-    pub pos: Point,
-    pub damage: u8,
-    pub speed: u8,
-}
-
-impl GameState for ExpressiveGameState {
-    fn simulate(&mut self, settings: &GameSettings, player_command: Command, opponent_command: Command) -> GameStatus {
-        if self.status.is_complete() {
-            return self.status;
-        }
-
-        ExpressiveGameState::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);
-        ExpressiveGameState::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);
-        ExpressiveGameState::perform_deconstruct_command(&mut self.player_unconstructed_buildings, &mut self.player_buildings,  &mut self.player, &mut self.unoccupied_player_cells, player_command);
-        ExpressiveGameState::perform_deconstruct_command(&mut self.opponent_unconstructed_buildings, &mut self.opponent_buildings, &mut self.opponent, &mut self.unoccupied_opponent_cells, opponent_command);
-        
-        ExpressiveGameState::update_construction(&mut self.player_unconstructed_buildings, &mut self.player_buildings, &mut self.player);
-        ExpressiveGameState::update_construction(&mut self.opponent_unconstructed_buildings, &mut self.opponent_buildings, &mut self.opponent);
-
-        ExpressiveGameState::fire_teslas(&mut self.player, &mut self.player_buildings, &mut self.unoccupied_player_cells, &mut self.opponent, &mut self.opponent_buildings, &mut self.unoccupied_opponent_cells, &settings);
-
-        ExpressiveGameState::add_missiles(&mut self.player_buildings, &mut self.player_missiles);
-        ExpressiveGameState::add_missiles(&mut self.opponent_buildings, &mut self.opponent_missiles);
-
-        ExpressiveGameState::move_missiles(&mut self.player_missiles, |p| p.wrapping_move_right(),
-                                           &mut self.opponent_buildings, &mut self.opponent,
-                                           &mut self.unoccupied_opponent_cells,
-                                           &settings);
-        ExpressiveGameState::move_missiles(&mut self.opponent_missiles, |p| p.wrapping_move_left(),
-                                           &mut self.player_buildings, &mut self.player,
-                                           &mut self.unoccupied_player_cells,
-                                           &settings);
-
-        ExpressiveGameState::add_energy(&mut self.player);
-        ExpressiveGameState::add_energy(&mut self.opponent);
-        
-        ExpressiveGameState::update_status(self);
-
-        self.status
-    }
-
-
-    fn player(&self) -> &Player { &self.player }
-    fn opponent(&self) -> &Player { &self.opponent }
-    fn player_has_max_teslas(&self) -> bool { self.count_player_teslas() >= 2 }
-    fn opponent_has_max_teslas(&self) -> bool { self.count_opponent_teslas() >= 2 }
-
-    fn unoccupied_player_cell_count(&self) -> usize { self.unoccupied_player_cells.len() }
-    fn unoccupied_opponent_cell_count(&self) -> usize { self.unoccupied_opponent_cells.len() }
-    fn location_of_unoccupied_player_cell(&self, i: usize) -> Point  { self.unoccupied_player_cells[i] }
-    fn location_of_unoccupied_opponent_cell(&self, i: usize) -> Point { self.unoccupied_opponent_cells[i] }
-}
-
-impl ExpressiveGameState {
-    pub fn new(
-        player: Player, opponent: Player,
-        player_unconstructed_buildings: Vec<UnconstructedBuilding>, player_buildings: Vec<Building>,
-        opponent_unconstructed_buildings: Vec<UnconstructedBuilding>, opponent_buildings: Vec<Building>,
-        player_missiles: Vec<Missile>, opponent_missiles: Vec<Missile>,
-        settings: &GameSettings) -> ExpressiveGameState {
-        
-        let unoccupied_player_cells = ExpressiveGameState::unoccupied_cells(
-            &player_buildings, &player_unconstructed_buildings, Point::new(0, 0), Point::new(settings.size.x/2, settings.size.y)
-        );
-        let unoccupied_opponent_cells = ExpressiveGameState::unoccupied_cells(
-            &opponent_buildings, &opponent_unconstructed_buildings, Point::new(settings.size.x/2, 0), Point::new(settings.size.x, settings.size.y)
-        );
-        ExpressiveGameState {
-            status: GameStatus::Continue,
-            player, opponent,
-            player_unconstructed_buildings, player_buildings, unoccupied_player_cells,
-            opponent_unconstructed_buildings, opponent_buildings, unoccupied_opponent_cells,
-            player_missiles, opponent_missiles
-        }
-    }
-
-    /**
-     * Sorts the various arrays. Generally not necessary, but useful
-     * for tests that check equality between states.
-     */
-    #[cfg(debug_assertions)]
-    pub fn sort(&mut self) {
-        self.player_unconstructed_buildings.sort_by_key(|b| b.pos);
-        self.player_buildings.sort_by_key(|b| b.pos);
-        self.unoccupied_player_cells.sort();
-        self.opponent_unconstructed_buildings.sort_by_key(|b| b.pos);
-        self.opponent_buildings.sort_by_key(|b| b.pos);
-        self.unoccupied_opponent_cells.sort();
-        self.player_missiles.sort_by_key(|b| b.pos);
-        self.opponent_missiles.sort_by_key(|b| b.pos);
-    }
-
-    fn perform_construct_command(unconstructed_buildings: &mut Vec<UnconstructedBuilding>, buildings: &mut Vec<Building>, player: &mut Player, unoccupied_cells: &mut Vec<Point>, 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);
-            debug_assert!(b != BuildingType::Tesla ||
-                          (unconstructed_buildings.iter().filter(|b| b.weapon_damage == 20).count() +
-                          buildings.iter().filter(|b| b.weapon_damage == 20).count() < 2));
-
-            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<UnconstructedBuilding>, buildings: &mut Vec<Building>, player: &mut Player, unoccupied_cells: &mut Vec<Point>, 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);
-        }
-    }
-
-    fn update_construction(unconstructed_buildings: &mut Vec<UnconstructedBuilding>, buildings: &mut Vec<Building>, player: &mut Player) {
-        let mut buildings_len = unconstructed_buildings.len();
-        for i in (0..buildings_len).rev() {
-            if unconstructed_buildings[i].is_constructed() {
-                player.energy_generated += unconstructed_buildings[i].energy_generated_per_turn;
-                buildings.push(unconstructed_buildings[i].to_building());
-                buildings_len -= 1;
-                unconstructed_buildings.swap(i, buildings_len);
-            } else {
-                unconstructed_buildings[i].construction_time_left -= 1
-            }
-        }
-        unconstructed_buildings.truncate(buildings_len);
-    }
-
-    fn fire_teslas(player: &mut Player, player_buildings: &mut Vec<Building>, player_unoccupied_cells: &mut Vec<Point>, opponent: &mut Player, opponent_buildings: &mut Vec<Building>, opponent_unoccupied_cells: &mut Vec<Point>,settings: &GameSettings) {
-        #[cfg(debug_assertions)]
-        {
-            player_buildings.sort_by(|a, b| b.age.cmp(&a.age).then(a.pos.cmp(&b.pos)));
-            opponent_buildings.sort_by(|a, b| b.age.cmp(&a.age).then(a.pos.cmp(&b.pos)));
-        }
-        
-        for tesla in player_buildings.iter_mut().filter(|b| b.weapon_damage == 20) {
-            tesla.age += 1;
-            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.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 {
-                                opponent_buildings[b].health = opponent_buildings[b].health.saturating_sub(settings.tesla.weapon_damage);
-                                continue 'player_col_loop;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        for tesla in opponent_buildings.iter_mut().filter(|b| b.weapon_damage == 20) {
-            tesla.age += 1;
-            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.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 {
-                                player_buildings[b].health = player_buildings[b].health.saturating_sub(settings.tesla.weapon_damage);
-                                continue 'opponent_col_loop;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        
-        for building in player_buildings.iter().filter(|b| b.health == 0) {
-            player_unoccupied_cells.push(building.pos);
-            player.energy_generated -= building.energy_generated_per_turn;
-        }
-        player_buildings.retain(|b| b.health > 0);
-
-        for building in opponent_buildings.iter().filter(|b| b.health == 0) {
-            opponent_unoccupied_cells.push(building.pos);
-            opponent.energy_generated -= building.energy_generated_per_turn;
-        }
-        opponent_buildings.retain(|b| b.health > 0);
-    }
-        
-    fn add_missiles(buildings: &mut Vec<Building>, missiles: &mut Vec<Missile>) {
-        for building in buildings.iter_mut().filter(|b| b.is_shooty()) {
-            if building.weapon_cooldown_time_left > 0 {
-                building.weapon_cooldown_time_left -= 1;
-            } else {
-                missiles.push(Missile {
-                    pos: building.pos,
-                    speed: building.weapon_speed,
-                    damage: building.weapon_damage,
-                });
-                building.weapon_cooldown_time_left = building.weapon_cooldown_period;
-            }
-        }
-    }
-
-    fn move_missiles<F>(missiles: &mut Vec<Missile>, mut wrapping_move_fn: F, opponent_buildings: &mut Vec<Building>, opponent: &mut Player, unoccupied_cells: &mut Vec<Point>, settings: &GameSettings)
-    where F: FnMut(&mut Point) {
-        let mut missiles_len = missiles.len();
-        '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);
-
-                    missiles_len -= 1;
-                    missiles.swap(m, missiles_len);
-                                        
-                    continue 'missile_loop;
-                }
-                else {
-                    for b in 0..opponent_buildings.len() {
-                        if opponent_buildings[b].pos == missiles[m].pos {
-                            opponent_buildings[b].health = opponent_buildings[b].health.saturating_sub(missiles[m].damage);
-
-                            missiles_len -= 1;
-                            missiles.swap(m, missiles_len);
-
-                            if opponent_buildings[b].health == 0 {
-                                unoccupied_cells.push(opponent_buildings[b].pos);
-                                opponent.energy_generated -= opponent_buildings[b].energy_generated_per_turn;
-                                opponent_buildings.swap_remove(b);
-                            }
-                            //after game engine bug fix, this should go back to missile_loop
-                            continue 'missile_loop;
-                        }
-                    }
-                }
-            }
-            missiles.truncate(missiles_len);
-        }
-    }
-
-    fn add_energy(player: &mut Player) {
-        player.energy += player.energy_generated;
-    }
-
-    fn update_status(state: &mut ExpressiveGameState) {
-        let player_dead = state.player.health == 0;
-        let opponent_dead = state.opponent.health == 0;
-        state.status = match (player_dead, opponent_dead) {
-            (true, true) => GameStatus::Draw,
-            (false, true) => GameStatus::PlayerWon,
-            (true, false) => GameStatus::OpponentWon,
-            (false, false) => GameStatus::Continue,
-        };
-    }
-
-    fn unoccupied_cells(buildings: &[Building], unconstructed_buildings: &[UnconstructedBuilding], bl: Point, tr: Point) -> Vec<Point> {
-        let mut result = Vec::with_capacity((tr.y-bl.y) as usize * (tr.x-bl.x) as usize);
-        for y in bl.y..tr.y {
-            for x in bl.x..tr.x {
-                let pos = Point::new(x, y);
-                if !buildings.iter().any(|b| b.pos == pos) && !unconstructed_buildings.iter().any(|b| b.pos == pos) {
-                    result.push(pos);
-                }
-            }
-        }
-        result
-    }
-
-    pub fn count_player_teslas(&self) -> usize {
-        self.player_unconstructed_buildings.iter().filter(|b| b.weapon_damage == 20).count() +
-            self.player_buildings.iter().filter(|b| b.weapon_damage == 20).count()
-    }
-
-    pub fn count_opponent_teslas(&self) -> usize {
-        self.opponent_unconstructed_buildings.iter().filter(|b| b.weapon_damage == 20).count() +
-            self.opponent_buildings.iter().filter(|b| b.weapon_damage == 20).count()
-    }
-}
-
-impl GameStatus {
-    fn is_complete(&self) -> bool {
-        *self != GameStatus::Continue
-    }
-}
-
-
-
-impl UnconstructedBuilding {
-    pub fn new(pos: Point, blueprint: &BuildingSettings) -> UnconstructedBuilding {
-        UnconstructedBuilding {
-            pos,
-            health: blueprint.health,
-            construction_time_left: blueprint.construction_time,
-            weapon_damage: blueprint.weapon_damage,
-            weapon_speed: blueprint.weapon_speed,
-            weapon_cooldown_period: blueprint.weapon_cooldown_period,
-            energy_generated_per_turn: blueprint.energy_generated_per_turn
-        }
-    }
-    
-    fn is_constructed(&self) -> bool {
-        self.construction_time_left == 0
-    }
-
-    fn to_building(&self) -> Building {
-        Building {
-            pos: self.pos,
-            health: self.health,
-            weapon_damage: self.weapon_damage,
-            weapon_speed: self.weapon_speed,
-            weapon_cooldown_time_left: 0,
-            weapon_cooldown_period: self.weapon_cooldown_period,
-            energy_generated_per_turn: self.energy_generated_per_turn,
-            age: 0
-        }
-    }
-}
-
-impl Building {
-    pub fn new(pos: Point, blueprint: &BuildingSettings) -> Building {
-        Building {
-            pos,
-            health: blueprint.health,
-            weapon_damage: blueprint.weapon_damage,
-            weapon_speed: blueprint.weapon_speed,
-            weapon_cooldown_time_left: 0,
-            weapon_cooldown_period: blueprint.weapon_cooldown_period,
-            energy_generated_per_turn: blueprint.energy_generated_per_turn,
-            age: 0
-        }
-    }
-    
-    fn is_shooty(&self) -> bool {
-        self.weapon_damage > 0 && self.weapon_damage < 20
-    }
-}
-
index a444059..c205d72 100644 (file)
@@ -1,7 +1,6 @@
 pub mod command;
 pub mod geometry;
 pub mod settings;
-pub mod expressive_engine;
 pub mod bitwise_engine;
 pub mod constants;
 
index 000c355..200252a 100644 (file)
@@ -5,21 +5,9 @@ use std::error::Error;
 
 use engine;
 use engine::command;
-use engine::expressive_engine;
 use engine::bitwise_engine;
 use engine::constants::*;
 
-pub fn read_expressive_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, expressive_engine::ExpressiveGameState), Box<Error>> {
-    let mut file = File::open(filename)?;
-    let mut content = String::new();
-    file.read_to_string(&mut content)?;
-    let state: State = serde_json::from_str(content.as_ref())?;
-
-    let engine_settings = state.to_engine_settings();
-    let engine_state = state.to_expressive_engine(&engine_settings);
-    Ok((engine_settings, engine_state))
-}
-
 pub fn read_bitwise_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, bitwise_engine::BitwiseGameState), Box<Error>> {
     let mut file = File::open(filename)?;
     let mut content = String::new();
@@ -99,10 +87,10 @@ struct BuildingState {
     health: u8,
     construction_time_left: i16,
     //price: u16,
-    weapon_damage: u8,
-    weapon_speed: u8,
+    //weapon_damage: u8,
+    //weapon_speed: u8,
     weapon_cooldown_time_left: u8,
-    weapon_cooldown_period: u8,
+    //weapon_cooldown_period: u8,
     //destroy_multiplier: u32,
     //construction_score: u32,
     energy_generated_per_turn: u16,
@@ -115,10 +103,10 @@ struct BuildingState {
 #[derive(Deserialize)]
 #[serde(rename_all = "camelCase")]
 struct MissileState {
-    damage: u8,
-    speed: u8,
-    x: u8,
-    y: u8,
+    //damage: u8,
+    //speed: u8,
+    //x: u8,
+    //y: u8,
     player_type: char
 }
 
@@ -135,22 +123,6 @@ impl State {
         )
     }
     
-    fn to_expressive_engine(&self, settings: &engine::settings::GameSettings) -> expressive_engine::ExpressiveGameState {
-        let player_buildings = self.buildings_to_expressive_engine('A');
-        let opponent_buildings = self.buildings_to_expressive_engine('B');
-        expressive_engine::ExpressiveGameState::new(
-            self.player().to_engine(settings, &player_buildings),
-            self.opponent().to_engine(settings, &opponent_buildings),
-            self.unconstructed_buildings_to_expressive_engine('A'),
-            player_buildings,
-            self.unconstructed_buildings_to_expressive_engine('B'),
-            opponent_buildings,
-            self.missiles_to_expressive_engine('A'),
-            self.missiles_to_expressive_engine('B'),
-            settings
-        )
-    }
-
     fn to_bitwise_engine(&self) -> bitwise_engine::BitwiseGameState {
         let mut player = self.player().to_bitwise_engine();
         let mut opponent = self.opponent().to_bitwise_engine();
@@ -237,39 +209,6 @@ impl State {
             .find(|p| p.player_type == 'B')
             .expect("Opponent character did not appear in state.json")
     }
-
-    fn unconstructed_buildings_to_expressive_engine(&self, player_type: char) -> Vec<expressive_engine::UnconstructedBuilding> {
-        self.game_map.iter()
-            .flat_map(|row| row.iter()
-                      .flat_map(|cell| cell.buildings.iter()
-                                .filter(|b| b.player_type == player_type && b.construction_time_left >= 0)
-                                .map(|b| b.to_expressive_engine_unconstructed())
-                      )
-            )
-            .collect()
-    }
-   
-    fn buildings_to_expressive_engine(&self, player_type: char) -> Vec<expressive_engine::Building> {
-        self.game_map.iter()
-            .flat_map(|row| row.iter()
-                      .flat_map(|cell| cell.buildings.iter()
-                                .filter(|b| b.player_type == player_type && b.construction_time_left < 0)
-                                .map(|b| b.to_expressive_engine())
-                      )
-            )
-            .collect()
-    }
-
-    fn missiles_to_expressive_engine(&self, player_type: char) -> Vec<expressive_engine::Missile> {
-        self.game_map.iter()
-            .flat_map(|row| row.iter()
-                      .flat_map(|cell| cell.missiles.iter()
-                                .filter(|b| b.player_type == player_type)
-                                .map(|b| b.to_expressive_engine())
-                      )
-            )
-            .collect()
-    }
 }
 
 impl BuildingBlueprint {
@@ -287,13 +226,6 @@ impl BuildingBlueprint {
 }
 
 impl Player {
-    fn to_engine(&self, settings: &engine::settings::GameSettings, buildings: &[expressive_engine::Building]) -> engine::Player {
-        engine::Player {
-            energy: self.energy,
-            health: self.health,
-            energy_generated: settings.energy_income + buildings.iter().map(|b| b.energy_generated_per_turn).sum::<u16>()
-        }
-    }
     fn to_bitwise_engine(&self) -> engine::Player {
         engine::Player {
             energy: self.energy,
@@ -304,31 +236,6 @@ impl Player {
 }
 
 impl BuildingState {
-    fn to_expressive_engine(&self) -> expressive_engine::Building {
-        expressive_engine::Building {
-            pos: engine::geometry::Point::new(self.x, self.y),
-            health: self.health,
-            weapon_damage: self.weapon_damage,
-            weapon_speed: self.weapon_speed,
-            weapon_cooldown_time_left: self.weapon_cooldown_time_left,
-            weapon_cooldown_period: self.weapon_cooldown_period,
-            energy_generated_per_turn: self.energy_generated_per_turn,
-            age: self.construction_time_left.abs() as u16
-        }
-    }
-
-    fn to_expressive_engine_unconstructed(&self) -> expressive_engine::UnconstructedBuilding {
-        expressive_engine::UnconstructedBuilding {
-            pos: engine::geometry::Point::new(self.x, self.y),
-            health: self.health,
-            construction_time_left: self.construction_time_left as u8, // > 0 check already happened
-            weapon_damage: self.weapon_damage,
-            weapon_speed: self.weapon_speed,
-            weapon_cooldown_period: self.weapon_cooldown_period,
-            energy_generated_per_turn: self.energy_generated_per_turn,
-        }
-    }
-
     fn to_bitwise_engine_unconstructed(&self) -> bitwise_engine::UnconstructedBuilding {
         bitwise_engine::UnconstructedBuilding {
             pos: engine::geometry::Point::new(self.x, self.y),
@@ -346,13 +253,3 @@ impl BuildingState {
         }
     }
 }
-
-impl MissileState {
-    fn to_expressive_engine(&self) -> expressive_engine::Missile {
-        expressive_engine::Missile {
-            pos: engine::geometry::Point::new(self.x, self.y),
-            damage: self.damage,
-            speed: self.speed,
-        }
-    }
-}
diff --git a/tests/expressive_to_bitwise_comparison.rs b/tests/expressive_to_bitwise_comparison.rs
deleted file mode 100644 (file)
index 72b5731..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-extern crate zombot;
-
-#[macro_use] extern crate proptest;
-extern crate rand;
-
-use zombot::input;
-use zombot::engine::command::{Command, BuildingType};
-use zombot::engine::geometry::Point;
-use zombot::engine::settings::GameSettings;
-use zombot::engine::{GameState, GameStatus, Player};
-
-use zombot::engine::expressive_engine;
-use zombot::engine::bitwise_engine;
-use zombot::engine::constants::*;
-
-use proptest::prelude::*;
-
-use rand::{Rng, XorShiftRng, SeedableRng};
-
-
-const STATE_PATH: &str = "tests/state0.json";
-
-#[test]
-fn reads_into_bitwise_correctly() {
-    test_reading_from_replay("tests/after_200", 64);
-}
-
-fn test_reading_from_replay(replay_folder: &str, length: usize) {
-    for i in 0..length {
-        let state_file = format!("{}/Round {:03}/state.json", replay_folder, i);
-
-        let (_, expressive_state) = input::json::read_expressive_state_from_file(&state_file).expect("Failed to load expressive state");
-        let (_, bitwise_state) = input::json::read_bitwise_state_from_file(&state_file).expect("Failed to load bitwise state");
-
-        assert_eq!(build_bitwise_from_expressive(&expressive_state), bitwise_state.clone(), "\nFailed on state {}\n", i);
-    }
-}
-
-
-proptest! {
-    #[test]
-    fn follows_the_same_random_game_tree(seed in any::<[u32;4]>()) {
-        let mut rng = XorShiftRng::from_seed(seed);
-        
-        let (settings, mut expressive_state) = input::json::read_expressive_state_from_file(STATE_PATH).expect("Failed to load expressive state");
-        let (_, mut bitwise_state) = input::json::read_bitwise_state_from_file(STATE_PATH).expect("Failed to load bitwise state");
-
-        expressive_state.sort();
-
-        let mut expected_status = GameStatus::Continue;
-        while expected_status == GameStatus::Continue {
-            let player_command = random_player_move(&settings, &expressive_state, &bitwise_state, &mut rng);
-            let opponent_command = random_opponent_move(&settings, &expressive_state, &bitwise_state, &mut rng);
-            println!("Player command: {}", player_command);
-            println!("Opponent command: {}", opponent_command);
-
-            expected_status = expressive_state.simulate(&settings, player_command, opponent_command);
-            let actual_status = bitwise_state.simulate(&settings, player_command, opponent_command);
-
-            expressive_state.sort();
-            
-            assert_eq!(&expected_status, &actual_status);
-            assert_eq!(build_bitwise_from_expressive(&expressive_state), bitwise_state.sorted());
-        }
-    }
-}
-
-fn random_player_move<R: Rng, GSE: GameState, GSB: GameState>(settings: &GameSettings, expressive_state: &GSE, bitwise_state: &GSB, rng: &mut R) -> Command {
-    assert_eq!(expressive_state.player_has_max_teslas(), bitwise_state.player_has_max_teslas());
-    let all_buildings = sensible_buildings(settings, &expressive_state.player(), expressive_state.player_has_max_teslas());
-    random_move(&all_buildings, rng, expressive_state.unoccupied_player_cell_count(), |i| expressive_state.location_of_unoccupied_player_cell(i), |i| bitwise_state.location_of_unoccupied_player_cell(i))
-}
-
-fn random_opponent_move<R: Rng, GSE: GameState, GSB: GameState>(settings: &GameSettings, expressive_state: &GSE, bitwise_state: &GSB, rng: &mut R) -> Command {
-    assert_eq!(expressive_state.player_has_max_teslas(), bitwise_state.player_has_max_teslas());
-    let all_buildings = sensible_buildings(settings, &expressive_state.opponent(), expressive_state.opponent_has_max_teslas());
-    random_move(&all_buildings, rng, expressive_state.unoccupied_opponent_cell_count(), |i| expressive_state.location_of_unoccupied_opponent_cell(i), |i| bitwise_state.location_of_unoccupied_opponent_cell(i))
-}
-
-fn random_move<R: Rng, FE:Fn(usize)->Point, FB:Fn(usize)->Point>(all_buildings: &[BuildingType], rng: &mut R, free_positions_count: usize, get_point_expressive: FE, get_point_bitwise: FB) -> Command {
-    let building_command_count = free_positions_count*all_buildings.len();
-    let nothing_count = 1;
-
-    let number_of_commands = building_command_count + nothing_count;
-    
-    let choice_index = rng.gen_range(0, number_of_commands);
-
-    if choice_index == number_of_commands - 1 {
-        Command::Nothing
-    } else {
-        let expressive_point = get_point_expressive(choice_index/all_buildings.len());
-        let bitwise_point = get_point_bitwise(choice_index/all_buildings.len());
-        assert_eq!(expressive_point, bitwise_point);
-        Command::Build(
-            expressive_point,
-            all_buildings[choice_index%all_buildings.len()]
-        )
-    }
-}
-
-fn sensible_buildings(settings: &GameSettings, player: &Player, has_max_teslas: bool) -> Vec<BuildingType> {
-    let mut result = Vec::with_capacity(4);
-    for b in BuildingType::all().iter() {
-        let building_setting = settings.building_settings(*b);
-        let affordable = building_setting.price <= player.energy;
-        let is_tesla = *b == BuildingType::Tesla;
-        if affordable && (!is_tesla || !has_max_teslas) {
-            result.push(*b);
-        }
-    }
-    result
-}
-
-fn build_bitwise_from_expressive(expressive: &expressive_engine::ExpressiveGameState) -> bitwise_engine::BitwiseGameState {
-    let player_unconstructed = expressive.player_unconstructed_buildings.iter()
-        .map(build_bitwise_unconstructed_from_expressive)
-        .collect();
-    let opponent_unconstructed = expressive.opponent_unconstructed_buildings.iter()
-        .map(build_bitwise_unconstructed_from_expressive)
-        .collect();
-    
-    let player_energy = expressive.player_buildings.iter()
-        .filter(|b| identify_building_type(b.weapon_damage, b.energy_generated_per_turn) == BuildingType::Energy)
-        .fold(0, |acc, next| acc | next.pos.to_left_bitfield());
-    let opponent_energy = expressive.opponent_buildings.iter()
-        .filter(|b| identify_building_type(b.weapon_damage, b.energy_generated_per_turn) == BuildingType::Energy)
-        .fold(0, |acc, next| acc | next.pos.to_right_bitfield());
-
-    let mut player_buildings_iter = (0..DEFENCE_HEALTH as u8)
-        .map(|i| expressive.player_buildings.iter()
-             .filter(|b| b.health > i*MISSILE_DAMAGE)
-             .fold(0, |acc, next| acc | next.pos.to_left_bitfield())
-        );
-    let mut opponent_buildings_iter = (0..DEFENCE_HEALTH as u8)
-        .map(|i| expressive.opponent_buildings.iter()
-             .filter(|b| b.health > i*MISSILE_DAMAGE)
-             .fold(0, |acc, next| acc | next.pos.to_right_bitfield())
-        );
-
-    let player_occupied = expressive.player_buildings.iter()
-        .fold(0, |acc, next| acc | next.pos.to_left_bitfield()) |
-    expressive.player_unconstructed_buildings.iter()
-        .fold(0, |acc, next| acc | next.pos.to_left_bitfield());
-    let opponent_occupied = expressive.opponent_buildings.iter()
-        .fold(0, |acc, next| acc | next.pos.to_right_bitfield()) |
-    expressive.opponent_unconstructed_buildings.iter()
-        .fold(0, |acc, next| acc | next.pos.to_right_bitfield());
-
-    let mut player_attack_iter = (0..MISSILE_COOLDOWN_STATES as u8)
-        .map(|i| expressive.player_buildings.iter()
-             .filter(|b| identify_building_type(b.weapon_damage, b.energy_generated_per_turn) == BuildingType::Attack)
-             .filter(|b| b.weapon_cooldown_time_left == i)
-             .fold(0, |acc, next| acc | next.pos.to_left_bitfield())
-        );
-    let mut opponent_attack_iter = (0..MISSILE_COOLDOWN_STATES as u8)
-        .map(|i| expressive.opponent_buildings.iter()
-             .filter(|b| identify_building_type(b.weapon_damage, b.energy_generated_per_turn) == BuildingType::Attack)
-             .filter(|b| b.weapon_cooldown_time_left == i)
-             .fold(0, |acc, next| acc | next.pos.to_right_bitfield())
-        );
-
-    let empty_missiles: [(u64,u64);MISSILE_COOLDOWN_STATES] = [(0,0),(0,0),(0,0),(0,0)];
-    let player_missiles = expressive.player_missiles.iter()
-        .fold(empty_missiles, |acc, m| {
-            let (mut left, mut right) = m.pos.to_bitfield();
-            let mut res = acc.clone();
-            for mut tier in res.iter_mut() {
-                let setting = (!tier.0 & left, !tier.1 & right);
-                tier.0 |= setting.0;
-                tier.1 |= setting.1;
-                left &= !setting.0;
-                right &= !setting.1;
-            }
-            res
-        });
-    let opponent_missiles = expressive.opponent_missiles.iter()
-        .fold(empty_missiles, |acc, m| {
-            let (mut left, mut right) = m.pos.to_bitfield();
-            let mut res = acc.clone();
-            for mut tier in res.iter_mut() {
-                let setting = (!tier.0 & right, !tier.1 & left);
-                tier.0 |= setting.0;
-                tier.1 |= setting.1;
-                right &= !setting.0;
-                left &= !setting.1;
-            }
-            res
-        });
-
-    let null_tesla = bitwise_engine::TeslaCooldown {
-        active: false,
-        pos: Point::new(0,0),
-        cooldown: 0,
-        age: 0
-    };
-    let mut player_tesla_iter = expressive.player_buildings.iter()
-        .filter(|b| identify_building_type(b.weapon_damage, b.energy_generated_per_turn) == BuildingType::Tesla)
-        .map(|b| bitwise_engine::TeslaCooldown {
-            active: true,
-            pos: b.pos,
-            cooldown: b.weapon_cooldown_time_left,
-            age: b.age,
-        });
-    let mut opponent_tesla_iter = expressive.opponent_buildings.iter()
-        .filter(|b| identify_building_type(b.weapon_damage, b.energy_generated_per_turn) == BuildingType::Tesla)
-        .map(|b| bitwise_engine::TeslaCooldown {
-            active: true,
-            pos: b.pos,
-            cooldown: b.weapon_cooldown_time_left,
-            age: b.age,
-        });
-    bitwise_engine::BitwiseGameState {
-        status: expressive.status,
-        player: expressive.player.clone(),
-        opponent: expressive.opponent.clone(),
-        player_buildings: bitwise_engine::PlayerBuildings {
-            unconstructed: player_unconstructed,
-            buildings: [player_buildings_iter.next().unwrap(), player_buildings_iter.next().unwrap(), player_buildings_iter.next().unwrap(), player_buildings_iter.next().unwrap()],
-            occupied: player_occupied,
-            energy_towers: player_energy,
-            missile_towers: [player_attack_iter.next().unwrap(), player_attack_iter.next().unwrap(), player_attack_iter.next().unwrap(), player_attack_iter.next().unwrap()],
-            firing_tower: 0,
-            missiles: player_missiles,
-            tesla_cooldowns: [player_tesla_iter.next().unwrap_or(null_tesla.clone()),
-                              player_tesla_iter.next().unwrap_or(null_tesla.clone())]
-        },
-        opponent_buildings: bitwise_engine::PlayerBuildings {
-            unconstructed: opponent_unconstructed,
-            buildings: [opponent_buildings_iter.next().unwrap(), opponent_buildings_iter.next().unwrap(), opponent_buildings_iter.next().unwrap(), opponent_buildings_iter.next().unwrap()],
-            occupied: opponent_occupied,
-            energy_towers: opponent_energy,
-            missile_towers: [opponent_attack_iter.next().unwrap(), opponent_attack_iter.next().unwrap(), opponent_attack_iter.next().unwrap(), opponent_attack_iter.next().unwrap()],
-            firing_tower: 0,
-            missiles: opponent_missiles,
-            tesla_cooldowns: [opponent_tesla_iter.next().unwrap_or(null_tesla.clone()),
-                              opponent_tesla_iter.next().unwrap_or(null_tesla.clone())]
-        }
-    }
-}
-
-fn build_bitwise_unconstructed_from_expressive(b: &expressive_engine::UnconstructedBuilding) -> bitwise_engine::UnconstructedBuilding {
-    bitwise_engine::UnconstructedBuilding {
-        pos: b.pos,
-        construction_time_left: b.construction_time_left,
-        building_type: identify_building_type(b.weapon_damage, b.energy_generated_per_turn)
-    }
-}
-
-fn identify_building_type(weapon_damage: u8, energy_generated_per_turn: u16) -> BuildingType {
-    match (weapon_damage, energy_generated_per_turn) {
-        (MISSILE_DAMAGE, _) => BuildingType::Attack,
-        (TESLA_DAMAGE, _) => BuildingType::Tesla,
-        (_, ENERGY_GENERATED_TOWER) => BuildingType::Energy,
-        _ => BuildingType::Defence
-    }
-}