Added initial benchmarks
authorJustin Worthe <justin@worthe-it.co.za>
Sun, 13 May 2018 17:09:26 +0000 (19:09 +0200)
committerJustin Worthe <justin@worthe-it.co.za>
Sun, 13 May 2018 17:09:26 +0000 (19:09 +0200)
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
benches/engine.rs [new file with mode: 0644]
src/engine/mod.rs

index 7703fc6..01abf5d 100644 (file)
@@ -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 (file)
index 0000000..129d687
--- /dev/null
@@ -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::<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 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<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()));
+}
+
+criterion_group!(benches, full_simulation_benchmark, full_simulation_benchmark_against_number_of_buildings);
+criterion_main!(benches);
index 41acb23..7b6db30 100644 (file)
@@ -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,