summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2019-06-27 18:58:04 +0200
committerJustin Worthe <justin@worthe-it.co.za>2019-06-27 18:58:04 +0200
commit81e869d0579a257bd823f9629a1b4ec3b6a297f9 (patch)
tree11b8e2b00d32de52f122b19262cff8e7552dffc2
parent0e3548c13634e078b71c022ac49a3cea7e0c420d (diff)
Starting to allow selecting from all of the new moves
-rw-r--r--src/game.rs34
-rw-r--r--src/strategy.rs35
2 files changed, 53 insertions, 16 deletions
diff --git a/src/game.rs b/src/game.rs
index d3d6636..9423e72 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -377,8 +377,21 @@ impl GameBoard {
(player_index + 1)%2
}
+ pub fn valid_selects(&self, player_index: usize) -> ArrayVec<[i32; 2]> {
+ if self.players[player_index].select_moves > 0 {
+ self.players[player_index].worms
+ .iter()
+ .enumerate()
+ .filter(|(p, _w)| self.players[player_index].active_worm != *p)
+ .map(|(_p, w)| w.id)
+ .collect()
+ } else {
+ ArrayVec::new()
+ }
+ }
+
pub fn valid_move_commands(&self, player_index: usize) -> ArrayVec<[Command;8]> {
- // TODO: This might also involve selects
+ // TODO: Select and move
if let Some(worm) = self.players[player_index].active_worm() {
Direction::all()
.iter()
@@ -395,11 +408,24 @@ impl GameBoard {
ArrayVec::new()
}
}
+
+ pub fn valid_shoot_commands(&self) -> ArrayVec<[Command;24]> {
+ // TODO: Select and shoot
+ Direction::all()
+ .iter()
+ .map(|d| Command::new(Action::Shoot(*d)))
+ .collect()
+ }
+
+ pub fn valid_bomb_commands(&self, player_index: usize) -> Vec<Command> {
+ // TODO: Bombs
+ // TODO: Select and bomb
+ unimplemented!("TODO")
+ }
- pub fn valid_shoot_commands(&self, player_index: usize, center: Point2d<i8>, weapon_range: u8) -> ArrayVec<[Command;8]> {
- // TODO: We might also throw bombs
+ pub fn sensible_shoot_commands(&self, player_index: usize, center: Point2d<i8>, weapon_range: u8) -> ArrayVec<[Command;8]> {
let range = weapon_range as i8;
- let dir_range = ((weapon_range as f32 + 1.) / 2f32.sqrt()).floor() as i8;
+ let dir_range = ((f32::from(weapon_range) + 1.) / 2f32.sqrt()).floor() as i8;
self.players[GameBoard::opponent(player_index)].worms
.iter()
diff --git a/src/strategy.rs b/src/strategy.rs
index 4c86dfd..46cb2cd 100644
--- a/src/strategy.rs
+++ b/src/strategy.rs
@@ -131,8 +131,11 @@ 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 unexplored = if new_state.outcome == SimulationOutcome::Continue {
+ mcts_move_combo(&new_state)
+ } else {
+ Vec::new()
+ };
let new_node = Node {
state: new_state,
@@ -166,7 +169,7 @@ fn mcts_move_combo(state: &GameBoard) -> Vec<[Command; 2]> {
let mut result = Vec::with_capacity(player_moves.len() * opponent_moves.len());
for p in &player_moves {
for o in &opponent_moves {
- result.push([p.clone(), o.clone()]);
+ result.push([*p, *o]);
}
}
@@ -178,7 +181,7 @@ fn best_player_move(node: &Node) -> Command {
.iter()
.max_by_key(|(_command, score_sum)| score_sum.avg())
.map(|(command, _score_sum)| *command)
- .unwrap_or(Command::new(Action::DoNothing))
+ .unwrap_or_else(|| Command::new(Action::DoNothing))
}
fn score(state: &GameBoard) -> Score {
@@ -202,11 +205,11 @@ fn rollout(state: &GameBoard) -> Score {
player_moves
.choose(&mut rng)
.cloned()
- .unwrap_or(Command::new(Action::DoNothing)),
+ .unwrap_or_else(|| Command::new(Action::DoNothing)),
opponent_moves
.choose(&mut rng)
.cloned()
- .unwrap_or(Command::new(Action::DoNothing)),
+ .unwrap_or_else(|| Command::new(Action::DoNothing)),
]);
}
@@ -228,29 +231,30 @@ fn choose_one_existing(node: &Node, player_index: usize) -> Command {
as i32
})
.map(|(command, _score_sum)| *command)
- .unwrap_or(Command::new(Action::DoNothing))
+ .unwrap_or_else(|| Command::new(Action::DoNothing))
}
fn update(node: &mut Node, commands: [Command; 2], score: Score) {
*node.player_score_sums[0]
.entry(commands[0])
- .or_insert(ScoreSum::new()) += score;
+ .or_insert_with(ScoreSum::new) += score;
*node.player_score_sums[1]
.entry(commands[1])
- .or_insert(ScoreSum::new()) += score;
+ .or_insert_with(ScoreSum::new) += score;
node.score_sum += score;
}
fn rollout_moves(state: &GameBoard, player_index: usize) -> ArrayVec<[Command; 8]> {
+ // TODO: Have this return one move, chosen randomly?
+ // TODO: Allow new select / bomb moves
if let Some(worm) = state.players[player_index].active_worm() {
- let shoots = state.valid_shoot_commands(player_index, worm.position, worm.weapon_range);
+ let shoots = state.sensible_shoot_commands(player_index, worm.position, worm.weapon_range);
if !shoots.is_empty() {
return shoots;
}
- // TODO: More directed destruction movements?
state.valid_move_commands(player_index)
} else {
[Command::new(Action::DoNothing)].into_iter().cloned().collect()
@@ -258,11 +262,18 @@ fn rollout_moves(state: &GameBoard, player_index: usize) -> ArrayVec<[Command; 8
}
fn valid_moves(state: &GameBoard, player_index: usize) -> ArrayVec<[Command; 17]> {
+ // TODO: Move / Dig, Shoot, Bomb, Select to another worm and repeat
+ // 24 move/digs
+ // 24 shoots
+ // 109 bombs (sub those out of range)
+ // 1 nothing
+ // TOTAL: 158 possible moves
if let Some(worm) = state.players[player_index].active_worm() {
- state.valid_shoot_commands(player_index, worm.position, worm.weapon_range)
+ state.valid_shoot_commands()
.iter()
.chain(state.valid_move_commands(player_index).iter())
+ .chain(state.valid_bomb_commands(player_index).iter())
.cloned()
.collect()
} else {