summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bin/perf-test.rs20
-rw-r--r--src/engine/bitwise_engine.rs31
-rw-r--r--src/engine/expressive_engine.rs7
-rw-r--r--src/engine/mod.rs7
-rw-r--r--src/input/json.rs5
-rw-r--r--src/strategy/monte_carlo.rs17
-rw-r--r--tests/expressive_to_bitwise_comparison.rs19
7 files changed, 78 insertions, 28 deletions
diff --git a/src/bin/perf-test.rs b/src/bin/perf-test.rs
index 42b4def..81dc5a5 100644
--- a/src/bin/perf-test.rs
+++ b/src/bin/perf-test.rs
@@ -9,6 +9,12 @@ const STATE_PATH: &str = "tests/state0.json";
use std::process;
fn main() {
+// expressive();
+ 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,
@@ -20,3 +26,17 @@ fn main() {
let max_time = Duration::milliseconds(1950);
strategy::monte_carlo::choose_move(&settings, &state, &start_time, max_time);
}
+
+fn bitwise() {
+ println!("Running bitwise engine");
+ let start_time = PreciseTime::now();
+ let (settings, state) = match input::json::read_bitwise_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(1950);
+ strategy::monte_carlo::choose_move(&settings, &state, &start_time, max_time);
+}
diff --git a/src/engine/bitwise_engine.rs b/src/engine/bitwise_engine.rs
index e3ca4c6..31040bf 100644
--- a/src/engine/bitwise_engine.rs
+++ b/src/engine/bitwise_engine.rs
@@ -53,8 +53,6 @@ pub struct TeslaCooldown {
}
-const EMPTY: [Point; 0] = [];
-
impl GameState for BitwiseGameState {
fn simulate(&mut self, settings: &GameSettings, player_command: Command, opponent_command: Command) -> GameStatus {
BitwiseGameState::perform_command(settings, &mut self.player, &mut self.player_buildings, player_command); BitwiseGameState::perform_command(settings, &mut self.opponent, &mut self.opponent_buildings, opponent_command);
@@ -82,8 +80,33 @@ impl GameState for BitwiseGameState {
fn opponent(&self) -> &Player { &self.opponent }
fn player_has_max_teslas(&self) -> bool { self.player_buildings.count_teslas() >= MAX_TESLAS }
fn opponent_has_max_teslas(&self) -> bool { self.opponent_buildings.count_teslas() >= MAX_TESLAS }
- fn unoccupied_player_cells(&self) -> &[Point] { &EMPTY } //TODO
- fn unoccupied_opponent_cells(&self) -> &[Point] { &EMPTY } //TODO
+
+ fn unoccupied_player_cell_count(&self) -> usize { self.player_buildings.occupied.count_zeros() as usize }
+ fn unoccupied_opponent_cell_count(&self) -> usize { self.opponent_buildings.occupied.count_zeros() as usize }
+ fn location_of_unoccupied_player_cell(&self, i: usize) -> Point {
+ let mut current = 0;
+ for bit in 0..64 {
+ let is_free = (1 << bit) & self.player_buildings.occupied == 0;
+ if is_free && current == i{
+ return Point::new(bit%SINGLE_MAP_WIDTH, bit/SINGLE_MAP_WIDTH);
+ } else if is_free {
+ current += 1;
+ }
+ }
+ panic!("Didn't find indicated free bit for player");
+ }
+ fn location_of_unoccupied_opponent_cell(&self, i: usize) -> Point {
+ let mut current = 0;
+ for bit in 0..64 {
+ let is_free = (1 << bit) & self.opponent_buildings.occupied == 0;
+ if is_free && current == i{
+ return Point::new((bit%SINGLE_MAP_WIDTH) + SINGLE_MAP_WIDTH, bit/SINGLE_MAP_WIDTH);
+ } else if is_free {
+ current += 1;
+ }
+ }
+ panic!("Didn't find indicated free bit for opponent");
+ }
}
impl BitwiseGameState {
diff --git a/src/engine/expressive_engine.rs b/src/engine/expressive_engine.rs
index 0640d58..b7d7bf2 100644
--- a/src/engine/expressive_engine.rs
+++ b/src/engine/expressive_engine.rs
@@ -89,8 +89,11 @@ impl GameState for ExpressiveGameState {
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_cells(&self) -> &[Point] { &self.unoccupied_player_cells }
- fn unoccupied_opponent_cells(&self) -> &[Point] { &self.unoccupied_opponent_cells }
+
+ 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 {
diff --git a/src/engine/mod.rs b/src/engine/mod.rs
index 39a5f26..d36d0e9 100644
--- a/src/engine/mod.rs
+++ b/src/engine/mod.rs
@@ -15,8 +15,11 @@ pub trait GameState: Clone + Sync {
fn opponent(&self) -> &Player;
fn player_has_max_teslas(&self) -> bool;
fn opponent_has_max_teslas(&self) -> bool;
- fn unoccupied_player_cells(&self) -> &[Point];
- fn unoccupied_opponent_cells(&self) -> &[Point];
+
+ fn unoccupied_player_cell_count(&self) -> usize;
+ fn unoccupied_opponent_cell_count(&self) -> usize;
+ fn location_of_unoccupied_player_cell(&self, i: usize) -> Point;
+ fn location_of_unoccupied_opponent_cell(&self, i: usize) -> Point;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
diff --git a/src/input/json.rs b/src/input/json.rs
index bebb5be..6f0d5e8 100644
--- a/src/input/json.rs
+++ b/src/input/json.rs
@@ -19,14 +19,15 @@ pub fn read_expressive_state_from_file(filename: &str) -> Result<(engine::settin
Ok((engine_settings, engine_state))
}
-pub fn read_bitwise_state_from_file(filename: &str) -> Result<bitwise_engine::BitwiseGameState, Box<Error>> {
+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();
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_bitwise_engine();
- Ok(engine_state)
+ Ok((engine_settings, engine_state))
}
#[derive(Deserialize)]
diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs
index 19e663d..3dc94eb 100644
--- a/src/strategy/monte_carlo.rs
+++ b/src/strategy/monte_carlo.rs
@@ -81,17 +81,16 @@ fn simulate_to_endstate<R: Rng, GS: GameState>(command_score: &mut CommandScore,
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)
+ random_move(&all_buildings, rng, state.unoccupied_player_cell_count(), |i| state.location_of_unoccupied_player_cell(i))
}
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)
+ random_move(&all_buildings, rng, state.unoccupied_opponent_cell_count(), |i| state.location_of_unoccupied_opponent_cell(i))
}
-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();
+fn random_move<R: Rng, F:Fn(usize)->Point>(all_buildings: &[BuildingType], rng: &mut R, free_positions_count: usize, get_point: F) -> Command {
+ let building_command_count = free_positions_count*all_buildings.len();
let nothing_count = 1;
let number_of_commands = building_command_count + nothing_count;
@@ -102,7 +101,7 @@ fn random_move<R: Rng>(free_positions: &[Point], all_buildings: &[BuildingType],
Command::Nothing
} else {
Command::Build(
- free_positions[choice_index/all_buildings.len()],
+ get_point(choice_index/all_buildings.len()),
all_buildings[choice_index%all_buildings.len()]
)
}
@@ -163,13 +162,15 @@ impl CommandScore {
fn init_command_scores<GS: GameState>(settings: &GameSettings, state: &GS) -> Vec<CommandScore> {
let all_buildings = sensible_buildings(settings, &state.player(), state.player_has_max_teslas());
- let building_command_count = state.unoccupied_player_cells().len()*all_buildings.len();
+ let unoccupied_cells = (0..state.unoccupied_player_cell_count()).map(|i| state.location_of_unoccupied_player_cell(i));
+
+ let building_command_count = unoccupied_cells.len()*all_buildings.len();
let nothing_count = 1;
let mut commands = Vec::with_capacity(building_command_count + nothing_count);
commands.push(CommandScore::new(Command::Nothing));
- for &position in state.unoccupied_player_cells() {
+ for position in unoccupied_cells {
for &building in &all_buildings {
commands.push(CommandScore::new(Command::Build(position, building)));
}
diff --git a/tests/expressive_to_bitwise_comparison.rs b/tests/expressive_to_bitwise_comparison.rs
index cb57e3b..4a2a87e 100644
--- a/tests/expressive_to_bitwise_comparison.rs
+++ b/tests/expressive_to_bitwise_comparison.rs
@@ -29,7 +29,7 @@ fn test_reading_from_replay(replay_folder: &str, length: usize) {
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");
+ 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);
}
@@ -42,7 +42,7 @@ proptest! {
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 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 {
@@ -61,18 +61,17 @@ proptest! {
}
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()||true);
- random_move(&state.unoccupied_player_cells(), &all_buildings, rng)
+ let all_buildings = sensible_buildings(settings, &state.player(), true);
+ random_move(&all_buildings, rng, state.unoccupied_player_cell_count(), |i| state.location_of_unoccupied_player_cell(i))
}
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()||true);
- random_move(&state.unoccupied_opponent_cells(), &all_buildings, rng)
+ let all_buildings = sensible_buildings(settings, &state.opponent(), true);
+ random_move(&all_buildings, rng, state.unoccupied_opponent_cell_count(), |i| state.location_of_unoccupied_opponent_cell(i))
}
-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();
+fn random_move<R: Rng, F:Fn(usize)->Point>(all_buildings: &[BuildingType], rng: &mut R, free_positions_count: usize, get_point: F) -> Command {
+ let building_command_count = free_positions_count*all_buildings.len();
let nothing_count = 1;
let number_of_commands = building_command_count + nothing_count;
@@ -83,7 +82,7 @@ fn random_move<R: Rng>(free_positions: &[Point], all_buildings: &[BuildingType],
Command::Nothing
} else {
Command::Build(
- free_positions[choice_index/all_buildings.len()],
+ get_point(choice_index/all_buildings.len()),
all_buildings[choice_index%all_buildings.len()]
)
}