summaryrefslogtreecommitdiff
path: root/src/game.rs
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2019-04-25 20:28:46 +0200
committerJustin Worthe <justin@worthe-it.co.za>2019-04-25 20:28:46 +0200
commitec9041a9526b52910aafac1f7c0acfc8215ac107 (patch)
treee87541ff0f442f137f4e5c797014bfa8311c6f3f /src/game.rs
parent4978b4f27d7a0e6058d04e7184600bf835070a8b (diff)
Made the state object avoid any heap allocations
Diffstat (limited to 'src/game.rs')
-rw-r--r--src/game.rs115
1 files changed, 98 insertions, 17 deletions
diff --git a/src/game.rs b/src/game.rs
index 0d57028..434828a 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -2,17 +2,22 @@ use crate::geometry::*;
use crate::command::Command;
use crate::json;
+use arrayvec::ArrayVec;
+
+#[derive(Debug, PartialEq, Eq)]
pub struct GameBoard {
pub players: [Player; 2],
- pub powerups: Vec<Powerup>,
+ pub powerups: ArrayVec<[Powerup; 2]>,
pub map: Map,
}
+#[derive(Debug, PartialEq, Eq)]
pub struct Player {
pub active_worm: usize,
- pub worms: Vec<Worm>
+ pub worms: ArrayVec<[Worm; 3]>
}
+#[derive(Debug, PartialEq, Eq)]
pub struct Worm {
pub id: i32,
pub health: i32,
@@ -21,23 +26,26 @@ pub struct Worm {
pub weapon_range: u8
}
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Powerup {
Health(Point2d<i8>, i32)
}
+#[derive(Debug, PartialEq, Eq)]
pub struct Map {
pub size: u8,
/// This is 2d, each row is size long
- pub cells: Vec<CellType>
+ pub cells: ArrayVec<[CellType; 2048]>
}
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CellType {
Air,
Dirt,
DeepSpace,
}
-
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SimulationOutcome {
PlayerWon(usize),
Draw,
@@ -98,23 +106,52 @@ impl GameBoard {
}
pub fn simulate(&mut self, moves: [Command; 2]) -> SimulationOutcome {
- // TODO: Command validation
- // TODO: Move collision case
- /*if let [Command::Move(x1, y1), Command::Move(x2, y2)] = moves {
+ match moves {
+ [Command::Move(x1, y1), Command::Move(x2, y2)] if x1 == x2 && y1 == y2 => {
+ // TODO: Get this from some sort of config rather
+ let damage = 20;
+
+
+ debug_assert_eq!(Some(CellType::Air), self.map.at(Point2d::new(x1, y1)));
+ // Worms have a 50% chance of swapping places
+ // here. I'm treating that as an edge case that I
+ // don't need to handle for now.
+ for player in &mut self.players {
+ player.active_worm_mut().health -= damage;
+ }
+ },
+ _ => {
+ for player_index in 0..moves.len() {
+ if let Command::Move(x, y) = moves[player_index] {
+ debug_assert_eq!(Some(CellType::Air), self.map.at(Point2d::new(x, y)));
- }*/
+ let worm = self.players[player_index].active_worm_mut();
- for player_index in 0..moves.len() {
- if let Command::Move(x, y) = moves[player_index] {
- let worm = self.players[player_index].active_worm_mut();
- worm.position.x = x;
- worm.position.y = y;
+ debug_assert!(
+ (worm.position.x - x).abs() <= 1 &&
+ (worm.position.y - y).abs() <= 1
+ );
+
+ worm.position.x = x;
+ worm.position.y = y;
+ }
+ }
}
}
for player_index in 0..moves.len() {
if let Command::Dig(x, y) = moves[player_index] {
- if let Some(c) = self.map.at(Point2d::new(x, y)) {
+ println!("Player {} is digging {}, {}", player_index, x, y);
+ debug_assert!(
+ Some(CellType::Dirt) == self.map.at(Point2d::new(x, y)) ||
+ Some(CellType::Air) == self.map.at(Point2d::new(x, y))
+ );
+ debug_assert!{
+ (self.players[player_index].active_worm().position.x - x).abs() <= 1 &&
+ (self.players[player_index].active_worm().position.y - y).abs() <= 1
+ };
+
+ if let Some(c) = self.map.at_mut(Point2d::new(x, y)) {
*c = CellType::Air;
}
}
@@ -122,7 +159,33 @@ impl GameBoard {
for player_index in 0..moves.len() {
if let Command::Shoot(dir) = moves[player_index] {
- // TODO: Shoot
+ let (center, weapon_range, weapon_damage) = {
+ let worm = self.players[player_index].active_worm();
+ (worm.position, worm.weapon_range, worm.weapon_damage)
+ };
+ let diff = dir.as_vec();
+
+ let range = if dir.is_diagonal() {
+ ((weapon_range as f32 + 1.) / 2f32.sqrt()).floor() as i8
+ } else {
+ weapon_range as i8
+ };
+
+ for distance in 1..=range {
+ let target = center + diff * distance;
+ match self.map.at(target) {
+ Some(CellType::Air) => {
+ let target_worm: Option<&mut Worm> = self.players.iter_mut()
+ .flat_map(|p| p.worms.iter_mut())
+ .find(|w| w.position == target);
+ if let Some(target_worm) = target_worm {
+ target_worm.health -= weapon_damage;
+ break;
+ }
+ },
+ _ => break
+ }
+ }
}
}
@@ -143,7 +206,13 @@ impl GameBoard {
// Update the active worm
player.active_worm = (player.active_worm + 1) % player.worms.len();
}
- SimulationOutcome::Continue
+
+ match (self.players[0].worms.len(), self.players[1].worms.len()) {
+ (0, 0) => SimulationOutcome::Draw,
+ (_, 0) => SimulationOutcome::PlayerWon(0),
+ (0, _) => SimulationOutcome::PlayerWon(1),
+ _ => SimulationOutcome::Continue
+ }
}
}
@@ -154,13 +223,25 @@ impl Player {
.find(|w| w.id == id)
}
+ fn active_worm(&self) -> &Worm {
+ &self.worms[self.active_worm]
+ }
+
fn active_worm_mut(&mut self) -> &mut Worm {
&mut self.worms[self.active_worm]
}
}
impl Map {
- fn at(&mut self, p: Point2d<i8>) -> Option<&mut CellType> {
+ fn at(&self, p: Point2d<i8>) -> Option<CellType> {
+ if p.y < 0 || p.x < 0 || p.y as u8 >= self.size || p.x as u8 >= self.size {
+ None
+ } else {
+ Some(self.cells[p.y as usize * self.size as usize + p.x as usize])
+ }
+ }
+
+ fn at_mut(&mut self, p: Point2d<i8>) -> Option<&mut CellType> {
if p.y < 0 || p.x < 0 || p.y as u8 >= self.size || p.x as u8 >= self.size {
None
} else {