diff options
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/bin/perf-test.rs | 2 | ||||
-rw-r--r-- | src/engine/bitwise_engine.rs | 28 | ||||
-rw-r--r-- | src/input/json.rs | 51 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/strategy/monte_carlo.rs | 2 | ||||
-rw-r--r-- | tests/bigstate.json | 1498 | ||||
-rw-r--r-- | tests/expressive_to_bitwise_comparison.rs | 129 | ||||
-rw-r--r-- | tests/live_comparison.rs | 4 | ||||
-rw-r--r-- | tests/monte_carlo_test.rs | 2 |
10 files changed, 200 insertions, 1520 deletions
@@ -11,6 +11,8 @@ rand = "0.4.2" time = "0.1.4" rayon = "1.0.1" +[dev-dependencies] +proptest = "0.7.2" [features] benchmarking = [] diff --git a/src/bin/perf-test.rs b/src/bin/perf-test.rs index 054258f..42b4def 100644 --- a/src/bin/perf-test.rs +++ b/src/bin/perf-test.rs @@ -10,7 +10,7 @@ use std::process; fn main() { let start_time = PreciseTime::now(); - let (settings, state) = match input::json::read_state_from_file(STATE_PATH) { + 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); diff --git a/src/engine/bitwise_engine.rs b/src/engine/bitwise_engine.rs index ca9cf00..bb1dd76 100644 --- a/src/engine/bitwise_engine.rs +++ b/src/engine/bitwise_engine.rs @@ -14,25 +14,25 @@ const MAX_TESLAS: usize = 2; #[derive(Debug, Clone, PartialEq, Eq)] pub struct BitwiseGameState { - status: GameStatus, - player: Player, - opponent: Player, - player_buildings: PlayerBuildings, - opponent_buildings: PlayerBuildings, + pub status: GameStatus, + pub player: Player, + pub opponent: Player, + pub player_buildings: PlayerBuildings, + pub opponent_buildings: PlayerBuildings, } #[derive(Debug, Clone, PartialEq, Eq)] -struct PlayerBuildings { - unconstructed: Vec<UnconstructedBuilding>, - energy_towers: [u8; MAP_HEIGHT], - missile_towers: [[u8; MAP_HEIGHT]; MISSILE_COOLDOWN], - defence_towers: [[u8; MAP_HEIGHT]; DEFENCE_HEALTH], - tesla_towers: [u8; MAP_HEIGHT], +pub struct PlayerBuildings { + pub unconstructed: Vec<UnconstructedBuilding>, + pub buildings: [u64; DEFENCE_HEALTH], - missiles: [[u16; MAP_HEIGHT]; MAP_WIDTH/4], - tesla_cooldowns: [TeslaCooldown; MAX_TESLAS], + pub energy_towers: u64, + pub missile_towers: [u64; MISSILE_COOLDOWN], + + pub missiles: [(u64, u64); MAP_WIDTH/4], + pub tesla_cooldowns: [TeslaCooldown; MAX_TESLAS], - unoccupied: Vec<Point> + pub unoccupied: Vec<Point> } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/input/json.rs b/src/input/json.rs index 6f7cda1..fb88bf0 100644 --- a/src/input/json.rs +++ b/src/input/json.rs @@ -5,9 +5,9 @@ use std::error::Error; use engine; use engine::expressive_engine; +use engine::bitwise_engine; - -pub fn read_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, expressive_engine::ExpressiveGameState), Box<Error>> { +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)?; @@ -18,6 +18,53 @@ pub fn read_state_from_file(filename: &str) -> Result<(engine::settings::GameSet Ok((engine_settings, engine_state)) } +pub fn read_bitwise_state_from_file(filename: &str) -> Result<bitwise_engine::BitwiseGameState, Box<Error>> { + //TODO + Ok(bitwise_engine::BitwiseGameState { + status: engine::GameStatus::Continue, + player: engine::Player { + energy: 0, health: 0, energy_generated: 0 + }, + opponent: engine::Player { + energy: 0, health: 0, energy_generated: 0 + }, + player_buildings: bitwise_engine::PlayerBuildings { + unconstructed: Vec::new(), + buildings: [0,0,0,0], + energy_towers: 0, + missile_towers: [0,0,0], + missiles: [(0,0),(0,0),(0,0),(0,0)], + tesla_cooldowns: [bitwise_engine::TeslaCooldown { + active: false, + pos: engine::geometry::Point::new(0,0), + cooldown: 0 + }, bitwise_engine::TeslaCooldown { + active: false, + pos: engine::geometry::Point::new(0,0), + cooldown: 0 + }], + unoccupied: Vec::new() + }, + opponent_buildings: bitwise_engine::PlayerBuildings { + unconstructed: Vec::new(), + buildings: [0,0,0,0], + energy_towers: 0, + missile_towers: [0,0,0], + missiles: [(0,0),(0,0),(0,0),(0,0)], + tesla_cooldowns: [bitwise_engine::TeslaCooldown { + active: false, + pos: engine::geometry::Point::new(0,0), + cooldown: 0 + }, bitwise_engine::TeslaCooldown { + active: false, + pos: engine::geometry::Point::new(0,0), + cooldown: 0 + }], + unoccupied: Vec::new() + } + }) +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct State { diff --git a/src/main.rs b/src/main.rs index 61e2e55..fa9216e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ fn write_command(filename: &str, command: Command) -> Result<(), Box<Error> > { fn main() { let start_time = PreciseTime::now(); - let (settings, state) = match input::json::read_state_from_file(STATE_PATH) { + 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); diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index dae74bc..19e663d 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -185,7 +185,7 @@ fn sensible_buildings(settings: &GameSettings, player: &Player, has_max_teslas: 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; + let is_tesla = *b == BuildingType::Tesla; if affordable && (!is_tesla || !has_max_teslas) { result.push(*b); } diff --git a/tests/bigstate.json b/tests/bigstate.json deleted file mode 100644 index 2ad555f..0000000 --- a/tests/bigstate.json +++ /dev/null @@ -1,1498 +0,0 @@ -{ - "gameDetails": { - "round": 0, - "mapWidth": 20, - "mapHeight": 10, - "roundIncomeEnergy": 5, - "buildingPrices": { - "TESLA": 300, - "ENERGY": 20, - "ATTACK": 30, - "DEFENSE": 30 - }, - "buildingsStats": { - "TESLA": { - "health": 5, - "constructionTime": 11, - "price": 300, - "weaponDamage": 20, - "weaponSpeed": 0, - "weaponCooldownPeriod": 10, - "energyGeneratedPerTurn": 0, - "destroyMultiplier": 1, - "constructionScore": 1 - }, - "ENERGY": { - "health": 5, - "constructionTime": 2, - "price": 20, - "weaponDamage": 0, - "weaponSpeed": 0, - "weaponCooldownPeriod": 0, - "energyGeneratedPerTurn": 3, - "destroyMultiplier": 1, - "constructionScore": 1 - }, - "ATTACK": { - "health": 5, - "constructionTime": 2, - "price": 30, - "weaponDamage": 5, - "weaponSpeed": 1, - "weaponCooldownPeriod": 3, - "energyGeneratedPerTurn": 0, - "destroyMultiplier": 1, - "constructionScore": 1 - }, - "DEFENSE": { - "health": 20, - "constructionTime": 4, - "price": 30, - "weaponDamage": 0, - "weaponSpeed": 0, - "weaponCooldownPeriod": 0, - "energyGeneratedPerTurn": 0, - "destroyMultiplier": 1, - "constructionScore": 1 - } - } - }, - "players": [ - { - "playerType": "A", - "energy": 20, - "health": 100, - "hitsTaken": 0, - "score": 0 - }, - { - "playerType": "B", - "energy": 20, - "health": 100, - "hitsTaken": 0, - "score": 0 - } - ], - "gameMap": [ - [ - { - "x": 0, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 0, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 1, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 2, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 3, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 4, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 5, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 6, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 7, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 8, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ], - [ - { - "x": 0, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 1, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 2, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 3, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 4, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 5, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 6, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 7, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 8, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 9, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "A" - }, - { - "x": 10, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 11, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 12, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 13, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 14, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 15, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 16, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 17, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 18, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - }, - { - "x": 19, - "y": 9, - "buildings": [], - "missiles": [], - "cellOwner": "B" - } - ] - ] -} diff --git a/tests/expressive_to_bitwise_comparison.rs b/tests/expressive_to_bitwise_comparison.rs new file mode 100644 index 0000000..c89c542 --- /dev/null +++ b/tests/expressive_to_bitwise_comparison.rs @@ -0,0 +1,129 @@ +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 proptest::prelude::*; + +use rand::{Rng, XorShiftRng, SeedableRng}; + + +const STATE_PATH: &str = "tests/state0.json"; + +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"); + + let mut expected_status = GameStatus::Continue; + while expected_status == GameStatus::Continue { + let player_command = random_player_move(&settings, &expressive_state, &mut rng); + let opponent_command = random_opponent_move(&settings, &expressive_state, &mut rng); + + expected_status = expressive_state.simulate(&settings, player_command, opponent_command); + let actual_status = bitwise_state.simulate(&settings, player_command, opponent_command); + + assert_eq!(&expected_status, &actual_status); + assert_eq!(build_bitwise_from_expressive(&expressive_state), bitwise_state.clone()); + } + } +} + + + +fn random_player_move<R: Rng, GS: GameState>(settings: &GameSettings, state: &GS, rng: &mut R) -> Command { + let all_buildings = sensible_buildings(settings, &state.player(), state.player_has_max_teslas()); + random_move(&state.unoccupied_player_cells(), &all_buildings, rng) +} + +fn random_opponent_move<R: Rng, GS: GameState>(settings: &GameSettings, state: &GS, rng: &mut R) -> Command { + let all_buildings = sensible_buildings(settings, &state.opponent(), state.opponent_has_max_teslas()); + random_move(&state.unoccupied_opponent_cells(), &all_buildings, rng) +} + +fn random_move<R: Rng>(free_positions: &[Point], all_buildings: &[BuildingType], rng: &mut R) -> Command { + + let building_command_count = free_positions.len()*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 { + Command::Build( + free_positions[choice_index/all_buildings.len()], + 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 { + //TODO + bitwise_engine::BitwiseGameState { + status: expressive.status, + player: expressive.player.clone(), + opponent: expressive.opponent.clone(), + player_buildings: bitwise_engine::PlayerBuildings { + unconstructed: Vec::new(), + buildings: [0,0,0,0], + energy_towers: 0, + missile_towers: [0,0,0], + missiles: [(0,0),(0,0),(0,0),(0,0)], + tesla_cooldowns: [bitwise_engine::TeslaCooldown { + active: false, + pos: Point::new(0,0), + cooldown: 0 + }, bitwise_engine::TeslaCooldown { + active: false, + pos: Point::new(0,0), + cooldown: 0 + }], + unoccupied: Vec::new() + }, + opponent_buildings: bitwise_engine::PlayerBuildings { + unconstructed: Vec::new(), + buildings: [0,0,0,0], + energy_towers: 0, + missile_towers: [0,0,0], + missiles: [(0,0),(0,0),(0,0),(0,0)], + tesla_cooldowns: [bitwise_engine::TeslaCooldown { + active: false, + pos: Point::new(0,0), + cooldown: 0 + }, bitwise_engine::TeslaCooldown { + active: false, + pos: Point::new(0,0), + cooldown: 0 + }], + unoccupied: Vec::new() + } + } +} diff --git a/tests/live_comparison.rs b/tests/live_comparison.rs index 20dbb2f..91d3530 100644 --- a/tests/live_comparison.rs +++ b/tests/live_comparison.rs @@ -20,12 +20,12 @@ fn it_successfully_simulates_replay_with_teslas() { } fn test_from_replay(replay_folder: &str, length: usize) { - let (settings, mut state) = json::read_state_from_file(&format!("{}/Round 000/state.json", replay_folder)).unwrap(); + let (settings, mut state) = json::read_expressive_state_from_file(&format!("{}/Round 000/state.json", replay_folder)).unwrap(); for i in 0..length { let player = read_player_command(&format!("{}/Round {:03}/PlayerCommand.txt", replay_folder, i)); let opponent = read_opponent_command(&format!("{}/Round {:03}/OpponentCommand.txt", replay_folder, i), &settings); - let (_, mut expected_state) = json::read_state_from_file(&format!("{}/Round {:03}/state.json", replay_folder, i+1)).unwrap(); + let (_, mut expected_state) = json::read_expressive_state_from_file(&format!("{}/Round {:03}/state.json", replay_folder, i+1)).unwrap(); state.simulate(&settings, player, opponent); state.sort(); diff --git a/tests/monte_carlo_test.rs b/tests/monte_carlo_test.rs index 479b36d..43476fd 100644 --- a/tests/monte_carlo_test.rs +++ b/tests/monte_carlo_test.rs @@ -10,7 +10,7 @@ const STATE_PATH: &str = "tests/state0.json"; #[test] fn it_does_a_normal_turn_successfully() { let start_time = PreciseTime::now(); - let (settings, state) = match input::json::read_state_from_file(STATE_PATH) { + let (settings, state) = match input::json::read_expressive_state_from_file(STATE_PATH) { Ok(ok) => ok, Err(error) => panic!("Error while parsing JSON file: {}", error) }; |