summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2019-08-06 20:05:35 +0200
committerJustin Worthe <justin@worthe-it.co.za>2019-08-06 20:05:35 +0200
commit298d67d4fdb36f8fb81ad6d8e817345e3d692558 (patch)
tree4a97cd018fc3a5ea7c6ecd698e8ceb62a94a30ee
parent416ad2d3a0b6bf28b343d0951d6f8723bd63aef2 (diff)
More snowball implementation. Now with freezing your opponent!
-rw-r--r--src/constants.rs16
-rw-r--r--src/constants/lava.rs1
-rw-r--r--src/game.rs72
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<i8>, i32); BOMB_DAMAGED_SPACES] = [
(Vec2d::new(0, 0), 20),
];
+pub const SNOWBALL_FREEZES_SPACES: usize = 9;
+pub const SNOWBALL_FREEZES: [Vec2d<i8>; 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]) {