Skip to content

Instantly share code, notes, and snippets.

@mackwic
Created January 7, 2018 16:22
Show Gist options
  • Save mackwic/08b7b8bb1b88058401f4b1bb0cc69f14 to your computer and use it in GitHub Desktop.
Save mackwic/08b7b8bb1b88058401f4b1bb0cc69f14 to your computer and use it in GitHub Desktop.
extern crate nalgebra;
#[cfg(test)]
extern crate rspec;
#[cfg(test)]
#[macro_use]
extern crate expectest;
use nalgebra::{Vector2, Point2};
#[derive(Clone, Debug)]
pub struct Map {
tiles: Vec<Option<()>>,
size: Vector2<i32>,
player_spawn: Point2<f32>,
}
impl Map {
pub fn new(size: Vector2<i32>) -> Self {
Map {
tiles: vec![None; (size.x * size.y) as usize],
size,
player_spawn: Point2::new(0.0, 0.0),
}
}
pub fn size(&self) -> Vector2<i32> {
self.size
}
pub fn player_spawn(&self) -> Point2<f32> {
self.player_spawn
}
pub fn set_player_spawn(&mut self, position: Point2<f32>) {
self.player_spawn = position
}
pub fn add_enemy_spawn(&mut self, _position: Point2<f32>) {
}
pub fn get_at(&self, position: Point2<i32>) -> Result<Option<()>, MapError> {
if self.in_bounds(position) {
Ok(self.tiles[self.index_at(position)])
} else {
Err(MapError::OutOfBounds { position })
}
}
pub fn set_at(&mut self, position: Point2<i32>, value: Option<()>) -> Result<(), MapError> {
if self.in_bounds(position) {
let index = self.index_at(position);
self.tiles[index] = value;
Ok(())
} else {
Err(MapError::OutOfBounds { position })
}
}
fn in_bounds(&self, position: Point2<i32>) -> bool {
if position.x >= 0 && position.y >= 0 &&
position.x < self.size.x && position.y < self.size.y {
true
} else {
false
}
}
fn index_at(&self, position: Point2<i32>) -> usize {
(position.x + position.y * self.size.x) as usize
}
}
#[derive(Debug, PartialEq)]
pub enum MapError {
OutOfBounds { position: Point2<i32> },
}
#[cfg(test)]
mod tests {
use nalgebra::{Vector2, Point2};
use super::{Map, MapError};
use expectest::prelude::*;
use rspec;
use rspec::*;
#[test]
fn error_handling_spec() {
let base_x = 1;
let base_y = 1;
let base_map = Map::new(Vector2::new(base_x, base_y));
rspec::run(&describe("error handling", base_map, |ctx| {
ctx.specify("MapError::OutOfBounds", |ctx| {
ctx.it("errs when position X is over", move |map| {
// arrange
let out_position = Point2::new(base_x + 1, base_y);
// act
let result = map.get_at(out_position);
// assert
// XXX: note the absence of the semi colon at the end. This is an alternative
// to assert_eq!
result == Err(MapError::OutOfBounds { position: out_position })
});
ctx.it("errs when position Y is over", move |map| {
// arrange
let out_position = Point2::new(base_x, base_y + 1);
// act
let result = map.get_at(out_position);
// assert
result == Err(MapError::OutOfBounds { position: out_position })
});
ctx.it("errs when position X is under", move |map| {
// arrange
let out_position = Point2::new(base_x - 1, base_y);
// act
let result = map.get_at(out_position);
// assert
result == Err(MapError::OutOfBounds { position: out_position })
});
ctx.it("errs when position Y is under (with bools)", move |map| {
// arrange
let out_position = Point2::new(base_x, base_y - 1);
// act
let result = map.get_at(out_position);
// assert
// XXX reversed condition with assert_eq!
result != Err(MapError::OutOfBounds { position: out_position })
});
ctx.it("errs when position Y is under (with assert)", move |map| {
// arrange
let out_position = Point2::new(base_x, base_y - 1);
// act
let result = map.get_at(out_position);
// assert
// XXX reversed condition with assert_eq!
assert_ne!(result, Err(MapError::OutOfBounds { position: out_position }))
});
ctx.it("errs when position Y is under (with expectest)", move |map| {
// arrange
let out_position = Point2::new(base_x, base_y - 1);
// act
let result = map.get_at(out_position);
// assert
// XXX reversed condition with assert_eq!
expect!(result).not_to(be_equal_to(Err(MapError::OutOfBounds { position: out_position })));
});
});
}));
}
// #[test]
// fn set_at_spec() {
// let base_x = 5;
// let base_y = 5;
// let something = Some(());
// let nothing = None;
// let empty_position = Point2::new(1, 1);
//
// rspec::run(&describe("Map::set_at", (), |ctx| {
// ctx.context("set at empty position is OK", |ctx| {
// ctx.it("set Some(())", move |_| {
// // arrange
// let mut map = Map::new(Vector2::new(base_x, base_y));
// // act
// let result = map.set_at(empty_position, something);
// // assert
// result.is_ok()
// });
//
// ctx.it("set None", move |_| {
// // arrange
// let mut map = Map::new(Vector2::new(base_x, base_y));
// // act
// let result = map.set_at(empty_position, nothing);
// // assert
// result.is_ok()
// });
// });
//
// ctx.context("set at a non-empty position", |ctx| {
// ctx.it("set Some(())", move |_| {
// // arrange
// let mut map = Map::new(Vector2::new(base_x, base_y));
// map.set_at(empty_position, something).unwrap();
// // act
// let result = map.set_at(empty_position, something);
// // assert
// result.is_err()
// });
//
// ctx.it("set None", move |_| {
// // arrange
// let something = None;
// let mut map = Map::new(Vector2::new(base_x, base_y));
// map.set_at(empty_position, something).unwrap();
// // act
// let result = map.set_at(empty_position, something);
// // assert
// result.is_ok()
// });
// });
//
// }));
// }
#[test]
fn it_gets_value_after_set() {
let mut map = Map::new(Vector2::new(5, 5));
let position1 = Point2::new(3, 3);
let position2 = Point2::new(1, 3);
map.set_at(position1, Some(())).unwrap();
map.set_at(position2, None).unwrap();
assert_eq!(map.get_at(position1), Ok(Some(())));
assert_eq!(map.get_at(position2), Ok(None));
}
#[test]
fn it_returns_error_for_out_of_bounds_set() {
let mut map = Map::new(Vector2::new(5, 5));
let result = map.set_at(Point2::new(10, 10), Some(()));
assert!(result.is_err());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment