diff --git a/src/game.rs b/src/game.rs index 049b647..84ce0ee 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,7 +1,23 @@ use crate::level::Level; use crate::player::Player; +pub const LEVELS: usize = 2; + pub struct Game<'game> { pub player: &'game mut Player, - pub levels: Vec<&'game mut Level>, + pub levels: Vec, +} + +impl Game<'_> { + pub fn new(p: &mut Player) -> Game { + let mut v: Vec = Vec::with_capacity(LEVELS); + for _ in 0..LEVELS { + let mut l = Level::new(); + v.push(l); + } + Game { + player: p, + levels: v, + } + } } \ No newline at end of file diff --git a/src/level.rs b/src/level.rs index 0ff215d..3f52b95 100644 --- a/src/level.rs +++ b/src/level.rs @@ -1,38 +1,115 @@ +use std::cmp::{max,min}; +use crate::position::Position; + +pub const LEVEL_WIDTH: usize = 50; +pub const LEVEL_HEIGHT: usize = 25; + #[derive(Copy, Clone, Debug, PartialEq)] -enum LevelElement { +enum StructureElement { Wall, Floor, StairDown, StairUp, + Unknown, } #[derive(Copy, Clone, Debug, PartialEq)] pub struct Level { - structure: [[LevelElement; 25]; 80], + structure: [[StructureElement; LEVEL_HEIGHT]; LEVEL_WIDTH], + discovered: [[bool; LEVEL_HEIGHT]; LEVEL_WIDTH], } impl Level { pub fn new() -> Level { - let mut s = [[LevelElement::Wall; 25]; 80]; - s[4][4] = LevelElement::StairDown; - s[75][20] = LevelElement::StairUp; + let mut s = [[StructureElement::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH]; + for x in 2..LEVEL_WIDTH - 2 { + for y in 2..LEVEL_HEIGHT - 2 { + s[x][y] = StructureElement::Floor; + } + } Level { - structure: s + structure: s, + discovered: [[false; LEVEL_HEIGHT]; LEVEL_WIDTH], } } - pub fn get_element(&self, x: usize, y: usize) -> Option { - if x >= 80 || y >= 25 { + pub fn get_element(&self, x: i16, y: i16) -> Option { + if x < 0 || y < 0 { return None; } + let x = x as usize; + let y = y as usize; + if x >= LEVEL_WIDTH || y >= LEVEL_HEIGHT { + return None; + } + if !self.discovered[x][y] { + return Some(StructureElement::Unknown); + } Some(self.structure[x][y]) } + /// discover the area with in the level around the given position + pub fn discover(&mut self, pos: &Position) { + let x = pos.get_x(); + let y = pos.get_y(); + + // uncover fields directly next to the player + for x_r in max(x - 1, 0)..=min(x + 1, LEVEL_WIDTH - 1) { + for y_r in max(y - 1, 0)..=min(y + 1, LEVEL_HEIGHT - 1) { + self.discovered[x_r][y_r] = true; + } + } + + // uncover fields up to 2 fields right of the player + for x_r in x..=min(x + 2, LEVEL_WIDTH - 1) { + self.discovered[x_r][y] = true; + if self.structure[x_r][y] == StructureElement::Wall { + break; + } + } + + // uncover fields up to 2 fields below of the player + for y_r in y..=min(y + 2, LEVEL_HEIGHT - 1) { + self.discovered[x][y_r] = true; + if self.structure[x][y_r] == StructureElement::Wall { + break; + } + } + + // uncover fields up to 2 fields left of the player + for x_r in (max(x, 2)..x + 2).rev() { + self.discovered[x_r - 2][y] = true; + if self.structure[x_r - 2][y] == StructureElement::Wall { + break; + } + } + + // uncover fields up to 2 fields above of the player + for y_r in (max(y, 2)..y + 2).rev() { + self.discovered[x][y_r - 2] = true; + if self.structure[x][y_r - 2] == StructureElement::Wall { + break; + } + } + } } #[test] fn test_get_element() { let l = Level::new(); - assert_eq!(l.get_element(0, 0).unwrap(), LevelElement::Wall); - assert_eq!(l.get_element(4, 4).unwrap(), LevelElement::StairDown); - assert_eq!(l.get_element(79, 24).unwrap(), LevelElement::Wall); - assert_eq!(l.get_element(80, 25), None); + assert_eq!(l.get_element(-1, -1), None); + assert_eq!(l.get_element(0, 0).unwrap(), StructureElement::Unknown); + assert_eq!(l.get_element(LEVEL_WIDTH as i16 - 1, LEVEL_HEIGHT as i16 - 1).unwrap(), StructureElement::Unknown); + assert_eq!(l.get_element(LEVEL_WIDTH as i16, LEVEL_HEIGHT as i16), None); +} + +#[test] +fn test_discover_get_element() { + let mut l = Level::new(); + assert_eq!(l.get_element(10, 10).unwrap(), StructureElement::Unknown); + let p = Position::new(0, 10, 10); + l.discover(&p); + assert_eq!(l.get_element(10, 10).unwrap(), StructureElement::Floor); + assert_eq!(l.get_element(9, 10).unwrap(), StructureElement::Floor); + assert_eq!(l.get_element(10, 9).unwrap(), StructureElement::Floor); + assert_eq!(l.get_element(11, 10).unwrap(), StructureElement::Floor); + assert_eq!(l.get_element(10, 11).unwrap(), StructureElement::Floor); } diff --git a/src/main.rs b/src/main.rs index f0efdca..f2d6408 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,13 +6,11 @@ mod game; mod player; mod level; mod position; +mod monster; fn main() { let mut p = Player::new("Teddy Tester", 10); - let g = Game { - player: &mut p, - levels: Vec::new() - }; + let g = Game::new(&mut p); println!("{}",g.player.get_name()); println!("{}",g.player.get_life()); diff --git a/src/monster.rs b/src/monster.rs new file mode 100644 index 0000000..4ab207c --- /dev/null +++ b/src/monster.rs @@ -0,0 +1,50 @@ +use std::cmp::{max, min}; + +use crate::position::Position; + +pub struct Monster { + life: usize, + position: Position, +} + +impl Monster { + pub fn new(life: usize) -> Self { + Monster { + life, + position: Position::new(0, 0, 0), + } + } + pub fn get_life(&self) -> usize { self.life } + pub fn is_dead(&self) -> bool { self.life <= 0 } + pub fn decrease_life(&mut self, by: i16) { + self.life = max(0, self.life as i16 - by) as usize; + } + pub fn get_position(&mut self) -> &mut Position { + &mut self.position + } +} + +#[test] +fn monsters_can_move() { + let mut m = Monster::new(2); + assert_eq!(m.get_position(), &Position::new(0, 0, 0)); + m.get_position().change(1, 2); + assert_eq!(m.get_position(), &Position::new(0, 1, 2)); + m.get_position().change(2, 1); + assert_eq!(m.get_position(), &Position::new(0, 3, 3)); + m.get_position().set(1, 2, 3); + m.get_position().change(2, 1); + assert_eq!(m.get_position(), &Position::new(1, 4, 4)); +} + +#[test] +fn monsters_can_die() { + let mut m = Monster::new(2); + assert_eq!(m.get_life(), 2); + assert_eq!(m.is_dead(), false); + m.decrease_life(1); + assert_eq!(m.get_life(), 1); + m.decrease_life(2); + assert_eq!(m.get_life(), 0); + assert_eq!(m.is_dead(), true); +} \ No newline at end of file diff --git a/src/player.rs b/src/player.rs index ed2e6cd..05dbca2 100644 --- a/src/player.rs +++ b/src/player.rs @@ -12,7 +12,7 @@ impl Player { pub fn new(name: &str, max_life: i16) -> Player { Player { name: name.to_string(), - position: Position::new(0, 1, 1), + position: Position::new(0, 0, 0), life: max_life, max_life, } @@ -26,6 +26,9 @@ impl Player { pub fn get_life(&self) -> i16 { self.life } + pub fn get_position(&mut self) -> &mut Position { + &mut self.position + } } #[test] @@ -54,4 +57,17 @@ fn test_change_life() { assert_eq!(p.life, 10); p.change_life(-12); assert_eq!(p.life, 0); -} \ No newline at end of file +} + +#[test] +fn player_can_move() { + let mut p = Player::new("Teddy Tester", 10); + assert_eq!(p.get_position(), &Position::new(0, 0, 0)); + p.get_position().change(1, 2); + assert_eq!(p.get_position(), &Position::new(0, 1, 2)); + p.get_position().change(2, 1); + assert_eq!(p.get_position(), &Position::new(0, 3, 3)); + p.get_position().set(1, 2, 3); + p.get_position().change(2, 1); + assert_eq!(p.get_position(), &Position::new(1, 4, 4)); +} diff --git a/src/position.rs b/src/position.rs index 92e21d7..e86985b 100644 --- a/src/position.rs +++ b/src/position.rs @@ -1,15 +1,33 @@ +#[derive(PartialEq, Debug)] pub struct Position { - level: u8, - x: u8, - y: u8, + level: usize, + x: usize, + y: usize, } impl Position { - pub fn new(level: u8, x: u8, y: u8) -> Self { + pub fn new(level: usize, x: usize, y: usize) -> Self { Self { level, x, y, } } + pub fn change(&mut self, dx: i16, dy: i16) { + self.x = ((self.x as i16) + dx) as usize; + self.y = ((self.y as i16) + dy) as usize; + } + pub fn set(&mut self, level: usize, x: usize, y: usize) { + self.level = level; + self.x = x; + self.y = y; + } + + pub fn get_x(&self) -> usize { + self.x + } + + pub fn get_y(&self) -> usize { + self.y + } } \ No newline at end of file