From ea78e266cff3f57c39442aefc21295a758419e69 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Thu, 9 Aug 2018 20:40:03 +0200 Subject: Removed dynamic settings It worked really well for round 2 to set constants --- src/strategy/monte_carlo.rs | 96 +++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 42 deletions(-) (limited to 'src/strategy/monte_carlo.rs') diff --git a/src/strategy/monte_carlo.rs b/src/strategy/monte_carlo.rs index d4003bb..cf0d77c 100644 --- a/src/strategy/monte_carlo.rs +++ b/src/strategy/monte_carlo.rs @@ -1,7 +1,8 @@ -use engine::settings::GameSettings; use engine::command::*; use engine::geometry::*; -use engine::{GameState, GameStatus, Player}; +use engine::status::GameStatus; +use engine::bitwise_engine::{Player, BitwiseGameState}; +use engine::constants::*; use rand::{Rng, XorShiftRng, SeedableRng}; @@ -15,9 +16,9 @@ use rayon::prelude::*; #[cfg(feature = "energy-cutoff")] pub const ENERGY_PRODUCTION_CUTOFF: u16 = 30; #[cfg(feature = "energy-cutoff")] pub const ENERGY_STORAGE_CUTOFF: u16 = 45; -pub fn choose_move(settings: &GameSettings, state: &GS, start_time: &PreciseTime, max_time: Duration) -> Command { - let mut command_scores = CommandScore::init_command_scores(settings, state); - let command = simulate_options_to_timeout(&mut command_scores, settings, state, start_time, max_time); +pub fn choose_move(state: &BitwiseGameState, start_time: &PreciseTime, max_time: Duration) -> Command { + let mut command_scores = CommandScore::init_command_scores(state); + let command = simulate_options_to_timeout(&mut command_scores, state, start_time, max_time); match command { Some(command) => command.command, @@ -26,7 +27,7 @@ pub fn choose_move(settings: &GameSettings, state: &GS, start_tim } #[cfg(not(feature = "discard-poor-performers"))] -fn simulate_options_to_timeout<'a, GS: GameState>(command_scores: &'a mut Vec, settings: &GameSettings, state: &GS, start_time: &PreciseTime, max_time: Duration) -> Option<&'a CommandScore> { +fn simulate_options_to_timeout(command_scores: &'a mut Vec, settings: &GameSettings, state: &BitwiseGameState, start_time: &PreciseTime, max_time: Duration) -> Option<&'a CommandScore> { loop { simulate_all_options_once(command_scores, settings, state); if start_time.to(PreciseTime::now()) > max_time { @@ -44,7 +45,7 @@ fn simulate_options_to_timeout<'a, GS: GameState>(command_scores: &'a mut Vec(command_scores: &'a mut Vec, settings: &GameSettings, state: &GS, start_time: &PreciseTime, max_time: Duration) -> Option<&'a CommandScore> { +fn simulate_options_to_timeout<'a>(command_scores: &'a mut Vec, state: &BitwiseGameState, start_time: &PreciseTime, max_time: Duration) -> Option<&'a CommandScore> { use std::cmp; let min_options = cmp::min(command_scores.len(), 5); @@ -53,7 +54,7 @@ fn simulate_options_to_timeout<'a, GS: GameState>(command_scores: &'a mut Vec max { break; } @@ -71,37 +72,37 @@ fn simulate_options_to_timeout<'a, GS: GameState>(command_scores: &'a mut Vec(command_scores: &mut[CommandScore], settings: &GameSettings, state: &GS) { +fn simulate_all_options_once(command_scores: &mut[CommandScore], state: &BitwiseGameState) { command_scores.iter_mut() .for_each(|score| { let mut rng = XorShiftRng::from_seed(score.next_seed); - simulate_to_endstate(score, settings, state, &mut rng); + simulate_to_endstate(score, state, &mut rng); }); } #[cfg(not(feature = "single-threaded"))] -fn simulate_all_options_once(command_scores: &mut[CommandScore], settings: &GameSettings, state: &GS) { +fn simulate_all_options_once(command_scores: &mut[CommandScore], state: &BitwiseGameState) { command_scores.par_iter_mut() .for_each(|score| { let mut rng = XorShiftRng::from_seed(score.next_seed); - simulate_to_endstate(score, settings, state, &mut rng); + simulate_to_endstate(score, state, &mut rng); }); } -fn simulate_to_endstate(command_score: &mut CommandScore, settings: &GameSettings, state: &GS, rng: &mut R) { +fn simulate_to_endstate(command_score: &mut CommandScore, state: &BitwiseGameState, rng: &mut R) { let mut state_mut = state.clone(); - let opponent_first = random_opponent_move(settings, &state_mut, rng); - let mut status = state_mut.simulate(settings, command_score.command, opponent_first); + let opponent_first = random_opponent_move(&state_mut, rng); + let mut status = state_mut.simulate(command_score.command, opponent_first); for _ in 0..MAX_MOVES { if status != GameStatus::Continue { break; } - let player_command = random_player_move(settings, &state_mut, rng); - let opponent_command = random_opponent_move(settings, &state_mut, rng); - status = state_mut.simulate(settings, player_command, opponent_command); + let player_command = random_player_move(&state_mut, rng); + let opponent_command = random_opponent_move(&state_mut, rng); + status = state_mut.simulate(player_command, opponent_command); } let next_seed = [rng.next_u32(), rng.next_u32(), rng.next_u32(), rng.next_u32()]; @@ -113,13 +114,13 @@ fn simulate_to_endstate(command_score: &mut CommandScore, } } -fn random_player_move(settings: &GameSettings, state: &GS, rng: &mut R) -> Command { - let all_buildings = sensible_buildings(settings, &state.player(), state.player_has_max_teslas()); +fn random_player_move(state: &BitwiseGameState, rng: &mut R) -> Command { + let all_buildings = sensible_buildings(&state.player(), state.player_has_max_teslas()); random_move(&all_buildings, rng, state.unoccupied_player_cell_count(), |i| state.location_of_unoccupied_player_cell(i)) } -fn random_opponent_move(settings: &GameSettings, state: &GS, rng: &mut R) -> Command { - let all_buildings = sensible_buildings(settings, &state.opponent(), state.opponent_has_max_teslas()); +fn random_opponent_move(state: &BitwiseGameState, rng: &mut R) -> Command { + let all_buildings = sensible_buildings(&state.opponent(), state.opponent_has_max_teslas()); random_move(&all_buildings, rng, state.unoccupied_opponent_cell_count(), |i| state.location_of_unoccupied_opponent_cell(i)) } @@ -197,8 +198,8 @@ impl CommandScore { } //TODO: Devalue nothing so that it doesn't stand and do nothing when it can do things - fn init_command_scores(settings: &GameSettings, state: &GS) -> Vec { - let all_buildings = sensible_buildings(settings, &state.player(), state.player_has_max_teslas()); + fn init_command_scores(state: &BitwiseGameState) -> Vec { + let all_buildings = sensible_buildings(&state.player(), state.player_has_max_teslas()); let unoccupied_cells = (0..state.unoccupied_player_cell_count()).map(|i| state.location_of_unoccupied_player_cell(i)); @@ -219,36 +220,47 @@ impl CommandScore { } #[cfg(not(feature = "energy-cutoff"))] -fn sensible_buildings(settings: &GameSettings, player: &Player, has_max_teslas: bool) -> Vec { +fn sensible_buildings(player: &Player, has_max_teslas: bool) -> Vec { 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); - } + + if DEFENCE_PRICE <= player.energy { + result.push(BuildingType::Defence); + } + if MISSILE_PRICE <= player.energy { + result.push(BuildingType::Attack); + } + if ENERGY_PRICE <= player.energy { + result.push(BuildingType::Energy); } + if TESLA_PRICE <= player.energy && !has_max_teslas { + result.push(BuildingType::Tesla); + } + result } //TODO: Heuristic that avoids building the initial energy towers all in the same row? +//TODO: Update cutoff to maybe build iron curtains #[cfg(feature = "energy-cutoff")] -fn sensible_buildings(settings: &GameSettings, player: &Player, has_max_teslas: bool) -> Vec { +fn sensible_buildings(player: &Player, has_max_teslas: bool) -> Vec { let mut result = Vec::with_capacity(4); let needs_energy = player.energy_generated <= ENERGY_PRODUCTION_CUTOFF || player.energy <= ENERGY_STORAGE_CUTOFF; - - for b in BuildingType::all().iter() { - let building_setting = settings.building_settings(*b); - let affordable = building_setting.price <= player.energy; - let energy_producing = building_setting.energy_generated_per_turn > 0; - let is_tesla = *b == BuildingType::Tesla; - if affordable && (!energy_producing || needs_energy) && (!is_tesla || !has_max_teslas) { - result.push(*b); - } + + if DEFENCE_PRICE <= player.energy { + result.push(BuildingType::Defence); + } + if MISSILE_PRICE <= player.energy { + result.push(BuildingType::Attack); } + if ENERGY_PRICE <= player.energy && needs_energy { + result.push(BuildingType::Energy); + } + if TESLA_PRICE <= player.energy && !has_max_teslas { + result.push(BuildingType::Tesla); + } + result } -- cgit v1.2.3