diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.toml | 11 | ||||
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | benches/engine.rs | 164 | ||||
-rw-r--r-- | src/bin/perf-test.rs | 46 | ||||
-rw-r--r-- | src/strategy/monte_carlo.rs | 24 | ||||
-rw-r--r-- | tests/bigstate.json | 1 |
7 files changed, 44 insertions, 210 deletions
@@ -9,3 +9,4 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk /perf.data +/perf.data.old @@ -11,16 +11,9 @@ rand = "0.4.2" time = "0.1.4" rayon = "1.0.1" -[dev-dependencies] -criterion = "0.2" -lazy_static = "1.0" - -[[bench]] -name = "engine" -harness = false - [profile.release] debug = true [features] -benchmarking = []
\ No newline at end of file +benchmarking = [] +single-threaded = [] @@ -4,8 +4,11 @@ build: test: cargo test --release +bench: + cargo run --release --features "benchmarking" --bin perf-test + profile: - cargo build --release --features "benchmarking" + cargo build --release --features "benchmarking single-threaded" mkdir -p target/profile sudo perf record -F 1000 -a -g target/release/perf-test sudo perf script > target/profile/out.perf @@ -16,4 +19,4 @@ clean: cargo clean -.PHONY: build test profile clean +.PHONY: build test bench profile clean diff --git a/benches/engine.rs b/benches/engine.rs deleted file mode 100644 index 1f6c125..0000000 --- a/benches/engine.rs +++ /dev/null @@ -1,164 +0,0 @@ -#[macro_use] -extern crate criterion; -use criterion::Criterion; - -#[macro_use] -extern crate lazy_static; - -extern crate zombot; -use zombot::engine::{GameState, Player, GameStatus, Building, Missile}; -use zombot::engine::settings::{GameSettings, BuildingSettings}; -use zombot::engine::geometry::Point; -use zombot::engine::command::{Command, BuildingType}; - -extern crate rand; -use rand::{thread_rng, Rng}; - -fn create_example_state(settings: &GameSettings, - player_buildings: usize, opponent_buildings: usize, - player_missiles: usize, opponent_missiles: usize -) -> GameState { - GameState { - status: GameStatus::Continue, - player: Player { - energy: 30, - health: 100 - }, - opponent: Player { - energy: 30, - health: 100 - }, - player_buildings: (0..player_buildings).map(|_| create_player_building(settings)).collect(), - opponent_buildings: (0..opponent_buildings).map(|_| create_player_building(settings)).collect(), - player_missiles: (0..player_missiles).map(|_| create_missile(settings)).collect(), - opponent_missiles: (0..opponent_missiles).map(|_| create_missile(settings)).collect() - } -} - -fn create_example_settings() -> GameSettings { - GameSettings { - size: Point::new(10,10), - energy_income: 5, - energy: BuildingSettings { - price: 20, - health: 5, - construction_time: 1, - weapon_damage: 0, - weapon_speed: 0, - weapon_cooldown_period: 0, - energy_generated_per_turn: 3 - }, - defence: BuildingSettings { - price: 20, - health: 5, - construction_time: 1, - weapon_damage: 0, - weapon_speed: 0, - weapon_cooldown_period: 0, - energy_generated_per_turn: 3 - }, - attack: BuildingSettings { - price: 20, - health: 5, - construction_time: 1, - weapon_damage: 0, - weapon_speed: 0, - weapon_cooldown_period: 0, - energy_generated_per_turn: 3 - } - } -} - -fn create_player_building(settings: &GameSettings) -> Building { - let all_positions = (0..settings.size.y) - .flat_map(|y| (0..settings.size.x/2).map(|x| Point::new(x, y)).collect::<Vec<_>>()) - .collect::<Vec<_>>(); - let all_buildings = BuildingType::all(); - - let mut rng = thread_rng(); - let position = rng.choose(&all_positions).unwrap(); - let building = rng.choose(&all_buildings).unwrap(); - let blueprint = settings.building_settings(*building); - - Building::new(*position, blueprint) -} - -fn create_opponent_building(settings: &GameSettings) -> Building { - let all_positions = (0..settings.size.y) - .flat_map(|y| (settings.size.x/2..settings.size.x).map(|x| Point::new(x, y)).collect::<Vec<_>>()) - .collect::<Vec<_>>(); - let all_buildings = BuildingType::all(); - - let mut rng = thread_rng(); - let position = rng.choose(&all_positions).unwrap(); - let building = rng.choose(&all_buildings).unwrap(); - let blueprint = settings.building_settings(*building); - - Building::new(*position, blueprint) -} - -fn create_missile(settings: &GameSettings) -> Missile { - let all_positions = (0..settings.size.y) - .flat_map(|y| (settings.size.x/2..settings.size.x).map(|x| Point::new(x, y)).collect::<Vec<_>>()) - .collect::<Vec<_>>(); - let mut rng = thread_rng(); - let position = rng.choose(&all_positions).unwrap(); - - Missile { - pos: *position, - damage: 5, - speed: 1 - } -} - - -fn full_simulation_benchmark(c: &mut Criterion) { - let settings = create_example_settings(); - let state = create_example_state(&settings, 5, 5, 5, 5); - - let player_command = Command::Build(Point::new(0,0),BuildingType::Defence); - let opponent_command = Command::Build(Point::new(4,4),BuildingType::Energy); - c.bench_function("full simulation", move |b| b.iter(|| state.simulate(&settings, player_command, opponent_command))); -} - -fn full_simulation_benchmark_against_number_of_buildings(c: &mut Criterion) { - let settings = create_example_settings(); - - lazy_static! { - static ref STATES: Vec<GameState> = { - let settings = create_example_settings(); - (0..10) - .map(|i| create_example_state(&settings, i*2, 0, 0, 0)) - .collect::<Vec<_>>() - }; - } - - let player_command = Command::Build(Point::new(0,0),BuildingType::Defence); - let opponent_command = Command::Build(Point::new(4,4),BuildingType::Energy); - - c.bench_function_over_inputs("player buildings variable", move |b, &state_index| b.iter(|| STATES[state_index].simulate(&settings, player_command, opponent_command)), (0..STATES.len())); -} - -fn full_simulation_benchmark_against_number_of_missiles(c: &mut Criterion) { - let settings = create_example_settings(); - - lazy_static! { - static ref STATES: Vec<GameState> = { - let settings = create_example_settings(); - (0..10) - .map(|i| create_example_state(&settings, 2, 5, i*2, i*2)) - .collect::<Vec<_>>() - }; - } - - let player_command = Command::Build(Point::new(0,0),BuildingType::Defence); - let opponent_command = Command::Build(Point::new(4,4),BuildingType::Energy); - - c.bench_function_over_inputs("player missiles variable", move |b, &state_index| b.iter(|| STATES[state_index].simulate(&settings, player_command, opponent_command)), (0..STATES.len())); -} - -criterion_group!(benches, - full_simulation_benchmark, - full_simulation_benchmark_against_number_of_buildings, - full_simulation_benchmark_against_number_of_missiles); -criterion_main!(benches); diff --git a/src/bin/perf-test.rs b/src/bin/perf-test.rs index 835267e..03da160 100644 --- a/src/bin/perf-test.rs +++ b/src/bin/perf-test.rs @@ -3,35 +3,20 @@ extern crate time; use time::{PreciseTime, Duration}; use zombot::*; -use zombot::engine::command::Command; - -use std::error::Error; const STATE_PATH: &str = "tests/state0.json"; +const STATE_BIG_PATH: &str = "tests/bigstate.json"; -const COMMAND_PATH: &str = "command.txt"; - -use std::fs::File; -use std::io::prelude::*; use std::process; -fn choose_move(settings: &engine::settings::GameSettings, state: &engine::GameState, start_time: &PreciseTime) -> Command { - let max_time = Duration::milliseconds(1950); - strategy::monte_carlo::choose_move(settings, state, start_time, max_time) -} - - -fn write_command(filename: &str, command: Command) -> Result<(), Box<Error> > { - let mut file = File::create(filename)?; - write!(file, "{}", command)?; - Ok(()) +fn main() { + normal_state(); + big_state(); } - -fn main() { +fn normal_state() { + println!("Normal size state file"); let start_time = PreciseTime::now(); - - println!("Reading in state.json file"); let (settings, state) = match json::read_state_from_file(STATE_PATH) { Ok(ok) => ok, Err(error) => { @@ -39,15 +24,20 @@ fn main() { process::exit(1); } }; - let command = choose_move(&settings, &state, &start_time); + let max_time = Duration::milliseconds(1950); + strategy::monte_carlo::choose_move(&settings, &state, &start_time, max_time); +} - match write_command(COMMAND_PATH, command) { - Ok(()) => {} +fn big_state() { + println!("Big state file"); + let start_time = PreciseTime::now(); + let (settings, state) = match json::read_state_from_file(STATE_BIG_PATH) { + Ok(ok) => ok, Err(error) => { - println!("Error while writing command file: {}", error); + println!("Error while parsing JSON file: {}", error); process::exit(1); } - } - - println!("Elapsed time: {}", start_time.to(PreciseTime::now())); + }; + let max_time = Duration::milliseconds(1950); + strategy::monte_carlo::choose_move(&settings, &state, &start_time, max_time); } diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index b7025c5..fe0462f 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -8,19 +8,29 @@ const MAX_MOVES: u16 = 400; use time::{Duration, PreciseTime}; +#[cfg(not(feature = "single-threaded"))] use rayon::prelude::*; pub fn choose_move(settings: &GameSettings, state: &GameState, start_time: &PreciseTime, max_time: Duration) -> Command { - println!("Using MONTE_CARLO strategy"); - let mut command_scores = CommandScore::init_command_scores(settings, state); loop { - command_scores.par_iter_mut() - .for_each(|score| { - let mut rng = thread_rng(); - simulate_to_endstate(score, settings, state, &mut rng); - }); + #[cfg(feature = "single-threaded")] + { + command_scores.iter_mut() + .for_each(|score| { + let mut rng = thread_rng(); + simulate_to_endstate(score, settings, state, &mut rng); + }); + } + #[cfg(not(feature = "single-threaded"))] + { + command_scores.par_iter_mut() + .for_each(|score| { + let mut rng = thread_rng(); + simulate_to_endstate(score, settings, state, &mut rng); + }); + } if start_time.to(PreciseTime::now()) > max_time { break; } diff --git a/tests/bigstate.json b/tests/bigstate.json new file mode 100644 index 0000000..dd15670 --- /dev/null +++ b/tests/bigstate.json @@ -0,0 +1 @@ +{"gameDetails":{"round":0,"mapWidth":20,"mapHeight":10,"roundIncomeEnergy":5,"buildingPrices":{"ENERGY":20,"ATTACK":30,"DEFENSE":30},"buildingsStats":{"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"}]]} |