From dd78789f242814bc750d886cc2d0c8f0877ade7c Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Sun, 13 May 2018 19:09:26 +0200 Subject: Added initial benchmarks There's a lot of room for improvement here. Specifically, I should separate the internal representation from the test interface. Have it provide functionality for creating random valid states. --- Cargo.toml | 10 ++++- benches/engine.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/engine/mod.rs | 2 +- 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 benches/engine.rs diff --git a/Cargo.toml b/Cargo.toml index 7703fc6..01abf5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,12 @@ serde = "1.0.43" serde_json = "1.0.16" rand = "0.4.2" -time = "0.1.4" \ No newline at end of file +time = "0.1.4" + +[dev-dependencies] +criterion = "0.2" +lazy_static = "1.0" + +[[bench]] +name = "engine" +harness = false \ No newline at end of file diff --git a/benches/engine.rs b/benches/engine.rs new file mode 100644 index 0000000..129d687 --- /dev/null +++ b/benches/engine.rs @@ -0,0 +1,130 @@ +#[macro_use] +extern crate criterion; +use criterion::Criterion; + +#[macro_use] +extern crate lazy_static; + +extern crate zombot; +use zombot::engine::{GameState, Player, GameStatus, Building}; +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: Vec::new(), + opponent_missiles: Vec::new() + } +} + +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::>()) + .collect::>(); + 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::>()) + .collect::>(); + 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 full_simulation_benchmark(c: &mut Criterion) { + let settings = create_example_settings(); + let state = create_example_state(&settings, 5, 5, 0, 0); + + 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 = { + let settings = create_example_settings(); + (0..10) + .map(|i| create_example_state(&settings, i*2, 0, 0, 0)) + .collect::>() + }; + } + + 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())); +} + +criterion_group!(benches, full_simulation_benchmark, full_simulation_benchmark_against_number_of_buildings); +criterion_main!(benches); diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 41acb23..7b6db30 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -240,7 +240,7 @@ impl Player { } impl Building { - fn new(pos: Point, blueprint: &BuildingSettings) -> Building { + pub fn new(pos: Point, blueprint: &BuildingSettings) -> Building { Building { pos: pos, health: blueprint.health, -- cgit v1.2.3