summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2019-07-07 12:03:44 +0200
committerJustin Worthe <justin@worthe-it.co.za>2019-07-07 12:03:44 +0200
commitd385199c48d565d9ffc8948f137d716e534d5d0d (patch)
treedb018fd521e0c854082dd32857c2e135eb47f2f7
parent886d7f75bca7078799074f0b4e7b80c6f8081f5f (diff)
Cleaning up TODOs
-rw-r--r--src/constants.rs4
-rw-r--r--src/game.rs36
-rw-r--r--src/game/map.rs53
-rw-r--r--src/json.rs15
4 files changed, 61 insertions, 47 deletions
diff --git a/src/constants.rs b/src/constants.rs
index 1c34377..94be135 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -176,3 +176,7 @@ pub const KILL_SCORE: i32 = 40;
pub const DIG_SCORE: i32 = 7;
pub const MOVE_SCORE: i32 = 5;
pub const INVALID_COMMAND_SCORE_PENALTY: i32 = 4;
+
+pub const STARTING_BOMBS: u8 = 3;
+
+pub const COLLISSION_DAMAGE: i32 = 20;
diff --git a/src/game.rs b/src/game.rs
index f5bcfa2..56c583b 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -15,7 +15,6 @@ use map::*;
use arrayvec::ArrayVec;
use fnv::FnvHashSet;
-// TODO: How much sense does it actually make to split the worms between the players?
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct GameBoard {
pub round: u16,
@@ -72,7 +71,11 @@ impl GameBoard {
position: Point2d::new(w.position.x, w.position.y),
weapon_damage: commando_damage,
weapon_range: commando_range,
- bombs: if w.health == 100 { 3 } else { 0 }, // TODO: parse and check worm type rather, move these out to constants
+ bombs: if w.profession == json::WormType::Agent {
+ STARTING_BOMBS
+ } else {
+ 0
+ },
})
.collect(),
};
@@ -126,7 +129,17 @@ impl GameBoard {
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: How to update opponent worm bombs?
+ // TODO: How to update opponent worm bombs? One idea:
+ // start the update by passing in the move that I did,
+ // and doing a simulation where the opponent did
+ // nothing. Then, looking at the points that the
+ // opponent actually got, determine if they did a
+ // simple walk / dig / shoot or if they hit multiple
+ // worms, hit worms with bomb levels of damage, or
+ // destroyed a dirt not next to them. I can further
+ // tell if they used a select (number of selects), and
+ // who their new active worm is, and if that worm
+ // could have bombed.
}
}
self.players[0].moves_score = json.my_player.score - json.my_player.health_score();
@@ -218,8 +231,7 @@ impl GameBoard {
fn simulate_moves(&mut self, actions: [Action; 2]) {
match actions {
[Action::Move(p1), Action::Move(p2)] if p1.x == p2.x && p1.y == p2.y => {
- // TODO: Get this from some sort of config rather
- let damage = 20;
+ let damage = COLLISSION_DAMAGE;
debug_assert_eq!(
Some(false),
@@ -308,6 +320,7 @@ impl GameBoard {
// TODO: Destroy health packs
+ // TODO: iter, filter_map, filter, filter_map... flatten this block down a smidge.
for player_index in 0..actions.len() {
if let Action::Bomb(p) = actions[player_index] {
if self.map.at(p).is_some() {
@@ -317,15 +330,12 @@ impl GameBoard {
worm.bombs = worm.bombs.saturating_sub(1);
- // damage as per https://forum.entelect.co.za/uploads/default/original/2X/8/89e6e6cf35791a0448b5a6bbeb63c558ce41804a.jpeg
-
for &(damage_offset, weapon_damage) in BOMB_DAMAGES.iter() {
let target = p + damage_offset;
if self.map.at(target) == Some(true) {
self.map.clear(target);
- // TODO: How does this score get assigned if both players lobbed a banana?
- // (answer, currently all to A, but watch https://forum.entelect.co.za/t/scoring-with-simultaneous-banana-digs/766/1
+ // TODO: Fix this so that simultaneous bomb throwing gives points to both players
self.players[player_index].moves_score += DIG_SCORE;
}
@@ -566,13 +576,15 @@ impl GameBoard {
}
})
.filter(|(dir, range)| {
- // TODO if this filtered all players, I don't need to dedup
let diff = dir.as_vec();
+ // NB: This is up to range EXCLUSIVE, so if there's
+ // anything in the way, even another good shot, skip.
!(1..*range).any(|distance| {
self.map.at(center + diff * distance) != Some(false)
- && !self.players[player_index]
- .worms
+ && !self
+ .players
.iter()
+ .flat_map(|p| p.worms.iter())
.any(|w| w.position == center + diff * distance)
})
})
diff --git a/src/game/map.rs b/src/game/map.rs
index c062c8f..45d25fd 100644
--- a/src/game/map.rs
+++ b/src/game/map.rs
@@ -1,13 +1,13 @@
-use crate::geometry::*;
use crate::constants::*;
+use crate::geometry::*;
#[derive(Default, Debug, PartialEq, Eq, Clone)]
pub struct Map {
- cells: [u64; MAP_U64S]
+ cells: [u64; MAP_U64S],
}
impl Map {
- pub fn at(&self, p: Point2d<i8>) -> Option<bool> {
+ fn internal_index(p: Point2d<i8>) -> Option<(usize, usize)> {
if p.y < 0 || p.y as usize >= MAP_SIZE {
None
} else {
@@ -18,47 +18,32 @@ impl Map {
let global_bit = row_data.start_bit + p.x as usize - row_data.x_offset;
let integer = global_bit / 64;
let bit = global_bit % 64;
- let mask = 1 << bit;
- Some(self.cells[integer] & mask != 0)
+ Some((integer, bit))
}
}
}
+ pub fn at(&self, p: Point2d<i8>) -> Option<bool> {
+ Map::internal_index(p).map(|(integer, bit)| {
+ let mask = 1 << bit;
+ self.cells[integer] & mask != 0
+ })
+ }
+
pub fn set(&mut self, p: Point2d<i8>) {
- if p.y < 0 || p.y as usize >= MAP_SIZE {
- debug_assert!(false, "Tried to set an out of bounds bit, {:?}", p);
+ if let Some((integer, bit)) = Map::internal_index(p) {
+ let mask = 1 << bit;
+ self.cells[integer] |= mask;
} else {
- let row_data = &MAP_ROW_SIZE[p.y as usize];
- if p.x < row_data.x_offset as i8 || p.x as usize >= row_data.x_offset + row_data.len() {
- debug_assert!(false, "Tried to set an out of bounds bit, {:?}", p);
- } else {
- let global_bit = row_data.start_bit + p.x as usize - row_data.x_offset;
- let integer = global_bit / 64;
- let bit = global_bit % 64;
- let mask = 1 << bit;
- self.cells[integer] |= mask;
- }
+ panic!("Tried to set an out of bounds bit, {:?}", p);
}
}
pub fn clear(&mut self, p: Point2d<i8>) {
- if p.y < 0 || p.y as usize >= MAP_SIZE {
- debug_assert!(false, "Tried to set an out of bounds bit, {:?}", p);
+ if let Some((integer, bit)) = Map::internal_index(p) {
+ let mask = !(1 << bit);
+ self.cells[integer] &= mask;
} else {
- let row_data = &MAP_ROW_SIZE[p.y as usize];
- if p.x < row_data.x_offset as i8 || p.x as usize >= row_data.x_offset + row_data.len() {
- debug_assert!(false, "Tried to set an out of bounds bit, {:?}", p);
- } else {
- let global_bit = row_data.start_bit + p.x as usize - row_data.x_offset;
- let integer = global_bit / 64;
- let bit = global_bit % 64;
- let mask = !(1 << bit);
- self.cells[integer] &= mask;
- }
+ panic!("Tried to set an out of bounds bit, {:?}", p);
}
}
}
-
-#[cfg(test)]
-mod test {
- // TODO: Property test for at, set and clear
-}
diff --git a/src/json.rs b/src/json.rs
index 86b35ea..4ac274a 100644
--- a/src/json.rs
+++ b/src/json.rs
@@ -54,6 +54,7 @@ pub struct PlayerWorm {
pub movement_range: u32,
pub weapon: Weapon,
pub banana_bombs: Option<Bomb>,
+ pub profession: WormType,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
@@ -80,6 +81,14 @@ pub struct OpponentWorm {
pub position: Position,
pub digging_range: u32,
pub movement_range: u32,
+ pub profession: WormType,
+}
+
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
+#[serde(rename_all = "PascalCase")]
+pub enum WormType {
+ Commando,
+ Agent,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
@@ -254,7 +263,8 @@ mod test {
"y": 16
},
"diggingRange": 1,
- "movementRange": 1
+ "movementRange": 1,
+ "profession": "Commando"
}
]
}
@@ -355,6 +365,7 @@ mod test {
count: 3,
damage_radius: 2,
}),
+ profession: WormType::Agent,
},
PlayerWorm {
id: 2,
@@ -367,6 +378,7 @@ mod test {
digging_range: 1,
movement_range: 1,
banana_bombs: None,
+ profession: WormType::Commando,
},
],
},
@@ -381,6 +393,7 @@ mod test {
position: Position { x: 31, y: 16 },
digging_range: 1,
movement_range: 1,
+ profession: WormType::Commando,
}],
}],
map: vec![