diff options
author | Justin Worthe <justin@worthe-it.co.za> | 2019-05-26 00:28:28 +0200 |
---|---|---|
committer | Justin Worthe <justin@worthe-it.co.za> | 2019-05-26 00:28:28 +0200 |
commit | d37be51f196eebdb8df57c87e8ab5bb684e1dcd9 (patch) | |
tree | 9625bf847698fd4072682839ede1f917c74bebbd /src/strategy.rs | |
parent | 7b3fe83b4bdb943d3d44ed036150d017279cfe05 (diff) |
Score based MCTS
Diffstat (limited to 'src/strategy.rs')
-rw-r--r-- | src/strategy.rs | 146 |
1 files changed, 81 insertions, 65 deletions
diff --git a/src/strategy.rs b/src/strategy.rs index 39bbe66..8e004cf 100644 --- a/src/strategy.rs +++ b/src/strategy.rs @@ -159,8 +159,8 @@ fn mcts(node: &mut Node) -> Score { } fn mcts_move_combo(state: &GameBoard) -> Vec<[Command; 2]> { - let player_moves = heuristic_moves(state, 0); - let opponent_moves = heuristic_moves(state, 1); + let player_moves = valid_moves(state, 0); + let opponent_moves = valid_moves(state, 1); debug_assert!(player_moves.len() > 0, "No player moves"); debug_assert!(player_moves.len() > 0, "No opponent moves"); @@ -183,12 +183,12 @@ fn best_player_move(node: &Node) -> Command { } fn score(state: &GameBoard) -> Score { - let mutiplier = match state.outcome { - SimulationOutcome::PlayerWon(_) => 1000., - _ => 1., - }; Score { - val: mutiplier * (state.players[0].health() - state.players[1].health()) as f32, + val: match state.outcome { + SimulationOutcome::PlayerWon(0) => 10000., + SimulationOutcome::PlayerWon(1) => -10000., + _ => (state.players[0].score() - state.players[1].score()) as f32, + } } } @@ -242,71 +242,87 @@ fn update(node: &mut Node, commands: [Command; 2], score: Score) { node.score_sum += score; } -fn heuristic_moves(state: &GameBoard, player_index: usize) -> Vec<Command> { - let worm = state.players[player_index].active_worm(); +// fn heuristic_moves(state: &GameBoard, player_index: usize) -> Vec<Command> { +// let worm = state.players[player_index].active_worm(); + +// let shoots = state +// .valid_shoot_commands(player_index, worm.position, worm.weapon_range); + +// let closest_powerup = state.powerups +// .iter() +// .min_by_key(|p| (p.position - worm.position).walking_distance()); + +// let average_player_position = Point2d { +// x: state.players[player_index].worms +// .iter() +// .map(|w| w.position.x) +// .sum::<i8>() / state.players[player_index].worms.len() as i8, +// y: state.players[player_index].worms +// .iter() +// .map(|w| w.position.y) +// .sum::<i8>() / state.players[player_index].worms.len() as i8 +// }; + +// 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 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, 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, player_index, opponent.position) +// } else { +// // this shouldn't happen +// debug_assert!(false, "No valid heuristic moves"); +// vec!() +// }; +// commands.push(Command::DoNothing); +// commands +// } + +// 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() +// .filter(|c| match c { +// Command::Move(p) | Command::Dig(p) => (to - *p).walking_distance() < distance, +// _ => false +// }) +// .cloned() +// .collect() +// } - let shoots = state - .valid_shoot_commands(player_index, worm.position, worm.weapon_range); +fn rollout_moves(state: &GameBoard, player_index: usize) -> ArrayVec<[Command; 8]> { + if let Some(worm) = state.players[player_index].active_worm() { - let closest_powerup = state.powerups - .iter() - .min_by_key(|p| (p.position - worm.position).walking_distance()); + let shoots = state.valid_shoot_commands(player_index, worm.position, worm.weapon_range); - let average_player_position = Point2d { - x: state.players[player_index].worms - .iter() - .map(|w| w.position.x) - .sum::<i8>() / state.players[player_index].worms.len() as i8, - y: state.players[player_index].worms - .iter() - .map(|w| w.position.y) - .sum::<i8>() / state.players[player_index].worms.len() as i8 - }; + if !shoots.is_empty() { + return shoots; + } - 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 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, 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, player_index, opponent.position) + // TODO: More directed destruction movements? + state.valid_move_commands(player_index) } else { - // this shouldn't happen - debug_assert!(false, "No valid heuristic moves"); - vec!() - }; - commands.push(Command::DoNothing); - commands + [Command::DoNothing].iter().cloned().collect() + } } -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() - .filter(|c| match c { - Command::Move(p) | Command::Dig(p) => (to - *p).walking_distance() < distance, - _ => false - }) - .cloned() - .collect() -} +fn valid_moves(state: &GameBoard, player_index: usize) -> ArrayVec<[Command; 17]> { + if let Some(worm) = state.players[player_index].active_worm() { -fn rollout_moves(state: &GameBoard, player_index: usize) -> ArrayVec<[Command; 8]> { - let worm = state.players[player_index].active_worm(); - - let shoots = state.valid_shoot_commands(player_index, worm.position, worm.weapon_range); - - if !shoots.is_empty() { - return shoots; + state.valid_shoot_commands(player_index, worm.position, worm.weapon_range) + .iter() + .chain(state.valid_move_commands(player_index).iter()) + .cloned() + .collect() + } else { + [Command::DoNothing].iter().cloned().collect() } - - // TODO: More directed destruction movements? - state.valid_move_commands(player_index) } |