diff options
author | Justin Worthe <justin@worthe-it.co.za> | 2019-05-21 13:27:25 +0200 |
---|---|---|
committer | Justin Worthe <justin@worthe-it.co.za> | 2019-05-21 13:27:25 +0200 |
commit | 63da94f7f1b25eddeb9ffd379f37c1a32e750fdb (patch) | |
tree | 83bd2670e948b16b37890e3ee9785f3672e0d32d /src/strategy.rs | |
parent | b93a9c643485c720a0711ddaf90872b7c6f006c8 (diff) |
More robust game logic and reasoning
Diffstat (limited to 'src/strategy.rs')
-rw-r--r-- | src/strategy.rs | 70 |
1 files changed, 19 insertions, 51 deletions
diff --git a/src/strategy.rs b/src/strategy.rs index 16d639b..8d2eea5 100644 --- a/src/strategy.rs +++ b/src/strategy.rs @@ -9,6 +9,7 @@ use time::{Duration, PreciseTime}; use rand; use rand::prelude::*; +use arrayvec::ArrayVec; pub fn choose_move(state: &GameBoard, start_time: &PreciseTime, max_time: Duration) -> Command { let mut root_node = Node { @@ -110,6 +111,7 @@ fn mcts(node: &mut Node) -> Score { let mut new_state = node.state.clone(); new_state.simulate(commands); let score = rollout(&new_state); + // TODO: This could overshoot, trying to estimate from concluded game let unexplored = mcts_move_combo(&new_state); let new_node = Node { @@ -219,16 +221,11 @@ fn update(node: &mut Node, commands: [Command; 2], score: Score) { node.score_sum += score; } -// TODO: Remove all invalid moves onto other worms - fn heuristic_moves(state: &GameBoard, player_index: usize) -> Vec<Command> { let worm = state.players[player_index].active_worm(); - let mut shoots = state - .find_targets(player_index, worm.position, worm.weapon_range) - .iter() - .map(|d| Command::Shoot(*d)) - .collect::<Vec<_>>(); + let shoots = state + .valid_shoot_commands(player_index, worm.position, worm.weapon_range); let closest_powerup = state.powerups .iter() @@ -245,30 +242,20 @@ fn heuristic_moves(state: &GameBoard, player_index: usize) -> Vec<Command> { .sum::<i8>() / state.players[player_index].worms.len() as i8 }; - let closest_opponent = state.players[(player_index + 1) % 2].worms + let closest_opponent = state.players[GameBoard::opponent(player_index)].worms .iter() .min_by_key(|w| (w.position - average_player_position).walking_distance()); let mut commands = if !shoots.is_empty() { // we're in combat now. Feel free to move anywhere. - let mut moves = Direction::all() - .iter() - .map(Direction::as_vec) - .map(|d| worm.position + d) - .filter_map(|p| match state.map.at(p) { - Some(false) => Some(Command::Move(p.x, p.y)), - Some(true) => Some(Command::Dig(p.x, p.y)), - _ => None, - }) - .collect::<Vec<_>>(); - moves.append(&mut shoots); - moves + let moves = state.valid_move_commands(player_index); + moves.iter().chain(shoots.iter()).cloned().collect() } else if let Some(powerup) = closest_powerup { // there are powerups! Let's go grab the closest one. - moves_towards(state, worm.position, powerup.position) + moves_towards(state, player_index, powerup.position) } else if let Some(opponent) = closest_opponent { // we're not currently in combat. Let's go find the closest worm. - moves_towards(state, worm.position, opponent.position) + moves_towards(state, player_index, opponent.position) } else { // this shouldn't happen debug_assert!(false, "No valid heuristic moves"); @@ -278,46 +265,27 @@ fn heuristic_moves(state: &GameBoard, player_index: usize) -> Vec<Command> { commands } -fn moves_towards(state: &GameBoard, from: Point2d<i8>, to: Point2d<i8>) -> Vec<Command> { - let distance = (to - from).walking_distance(); - Direction::all() +fn moves_towards(state: &GameBoard, player_index: usize, to: Point2d<i8>) -> Vec<Command> { + let distance = (to - state.players[player_index].active_worm().position).walking_distance(); + state.valid_move_commands(player_index) .iter() - .map(Direction::as_vec) - .map(|d| from + d) - .filter(|p| (to - *p).walking_distance() < distance) - .filter_map(|p| match state.map.at(p) { - Some(false) => Some(Command::Move(p.x, p.y)), - Some(true) => Some(Command::Dig(p.x, p.y)), - _ => None, + .filter(|c| match c { + Command::Move(p) | Command::Dig(p) => (to - *p).walking_distance() < distance, + _ => false }) + .cloned() .collect() } -fn rollout_moves(state: &GameBoard, player_index: usize) -> Vec<Command> { +fn rollout_moves(state: &GameBoard, player_index: usize) -> ArrayVec<[Command; 8]> { let worm = state.players[player_index].active_worm(); - let shoots = state - .find_targets(player_index, worm.position, worm.weapon_range) - .iter() - .map(|d| Command::Shoot(*d)) - .collect::<Vec<_>>(); + let shoots = state.valid_shoot_commands(player_index, worm.position, worm.weapon_range); if !shoots.is_empty() { return shoots; } // TODO: More directed destruction movements? - let mut moves = Direction::all() - .iter() - .map(Direction::as_vec) - .map(|d| worm.position + d) - .filter_map(|p| match state.map.at(p) { - Some(false) => Some(Command::Move(p.x, p.y)), - Some(true) => Some(Command::Dig(p.x, p.y)), - _ => None, - }) - .collect::<Vec<_>>(); - - moves.push(Command::DoNothing); - moves + state.valid_move_commands(player_index) } |