From 298d67d4fdb36f8fb81ad6d8e817345e3d692558 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Tue, 6 Aug 2019 20:05:35 +0200 Subject: More snowball implementation. Now with freezing your opponent! --- src/constants.rs | 16 ++++++++++++ src/constants/lava.rs | 1 + src/game.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 08e39dd..d796e57 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -173,6 +173,19 @@ pub const BOMB_DAMAGES: [(Vec2d, i32); BOMB_DAMAGED_SPACES] = [ (Vec2d::new(0, 0), 20), ]; +pub const SNOWBALL_FREEZES_SPACES: usize = 9; +pub const SNOWBALL_FREEZES: [Vec2d; SNOWBALL_FREEZES_SPACES] = [ + Vec2d::new(-1, -1), + Vec2d::new(0, -1), + Vec2d::new(1, -1), + Vec2d::new(-1, 0), + Vec2d::new(0, 0), + Vec2d::new(1, 0), + Vec2d::new(-1, 1), + Vec2d::new(0, 1), + Vec2d::new(1, 1), +]; + pub const MISSED_ATTACK_SCORE: i32 = 2; pub const ATTACK_SCORE_MULTIPLIER: i32 = 2; pub const KILL_SCORE: i32 = 40; @@ -190,3 +203,6 @@ pub const LAVA_DAMAGE: i32 = 3; pub const LAVA_ROUND_START: usize = 100; pub const LAVA_ROUND_END: usize = 350; pub const MAX_ROUNDS: usize = 400; + +pub const FREEZE_DURATION: u8 = 5; +pub const FREEZE_SCORE: i32 = 17; diff --git a/src/constants/lava.rs b/src/constants/lava.rs index ebc17b1..dc0d064 100644 --- a/src/constants/lava.rs +++ b/src/constants/lava.rs @@ -1,6 +1,7 @@ use crate::constants::*; use crate::game::map::Map; +#[allow(clippy::all)] pub const LAVA_MAP: [Map; MAX_ROUNDS as usize + 1] = [ Map { cells: [ diff --git a/src/game.rs b/src/game.rs index fca740d..7ab7725 100644 --- a/src/game.rs +++ b/src/game.rs @@ -129,15 +129,36 @@ impl GameBoard { worm.health = w.health; worm.position = Point2d::new(w.position.x, w.position.y); worm.bombs = w.banana_bombs.as_ref().map(|b| b.count).unwrap_or(0); + worm.snowballs = w.snowballs.as_ref().map(|b| b.count).unwrap_or(0); } } for w in json.opponents.iter().flat_map(|o| &o.worms) { if let Some(worm) = self.players[1].find_worm_mut(w.id) { worm.health = w.health; worm.position = Point2d::new(w.position.x, w.position.y); - // TODO: Update number of bombs / snowballs based on previous move } } + + // TODO: Good enough for now, but what if these worms are frozen? + if json + .opponents + .iter() + .any(|o| o.previous_command.starts_with("banana")) + { + for worm in &mut self.players[1].worms { + worm.bombs = worm.bombs.saturating_sub(1); + } + } + if json + .opponents + .iter() + .any(|o| o.previous_command.starts_with("snowball")) + { + for worm in &mut self.players[1].worms { + worm.snowballs = worm.snowballs.saturating_sub(1); + } + } + self.players[0].moves_score = json.my_player.score - json.my_player.health_score(); self.players[1].moves_score = json.opponents[0].score - json.opponents[0].health_score(); @@ -184,6 +205,7 @@ impl GameBoard { pub fn simulate(&mut self, moves: [Command; 2]) { self.simulate_worms_on_lava(); self.simulate_tick_frozen_timers(); + self.simulate_select(moves); let actions = self.identify_actions(moves); @@ -193,6 +215,9 @@ impl GameBoard { self.simulate_bombs(actions); // TODO: Question order of actions on the forums self.simulate_snowballs(actions); + // This check needs to happen again because the worm may have + // been frozen on the previous command. + let actions = self.identify_actions(moves); self.simulate_shoots(actions); for player in &mut self.players { @@ -248,6 +273,7 @@ impl GameBoard { moves .iter() .zip(self.players.iter_mut()) + .filter(|(_m, player)| !player.active_worm_is_frozen()) .for_each(|(m, player)| { if let Some(worm) = m.worm { debug_assert!( @@ -351,7 +377,7 @@ impl GameBoard { fn simulate_bombs(&mut self, actions: [Action; 2]) { // NB: Damage radius has the cell distance rounded UP, throwing range has the cell distance rounded DOWN - let map_clone = self.map.clone(); + let map_clone: Map = self.map; for player_index in 0..actions.len() { if let Action::Bomb(p) = actions[player_index] { @@ -408,7 +434,47 @@ impl GameBoard { } pub fn simulate_snowballs(&mut self, actions: [Action; 2]) { - // TODO: simulalte snowballs + let map_clone: Map = self.map; + + for player_index in 0..actions.len() { + if let Action::Snowball(p) = actions[player_index] { + if self.map.at(p).is_some() { + if let Some(worm) = self.players[player_index].active_worm_mut() { + debug_assert!( + worm.snowballs > 0, + "Worm is throwing a snowball it doesn't have" + ); + debug_assert!((worm.position - p).magnitude_squared() < 6 * 6); // max range is 5, but it's 5 after rounding down + + worm.snowballs = worm.snowballs.saturating_sub(1); + + for &freeze_offset in SNOWBALL_FREEZES.iter() { + let target = p + freeze_offset; + + let target_own_worm: Option<&mut Worm> = self.players[player_index] + .worms + .iter_mut() + .find(|w| w.position == target); + + if let Some(target_worm) = target_own_worm { + target_worm.rounds_until_unfrozen = FREEZE_DURATION; + self.players[player_index].moves_score -= FREEZE_SCORE; + } + + let target_opponent_worm: Option<&mut Worm> = self.players + [GameBoard::opponent(player_index)] + .worms + .iter_mut() + .find(|w| w.position == target); + if let Some(target_worm) = target_opponent_worm { + target_worm.rounds_until_unfrozen = FREEZE_DURATION; + self.players[player_index].moves_score += FREEZE_SCORE; + } + } + } + } + } + } } fn simulate_shoots(&mut self, actions: [Action; 2]) { -- cgit v1.2.3