about summary refs log tree commit diff
path: root/src/types
diff options
context:
space:
mode:
Diffstat (limited to 'src/types')
-rw-r--r--src/types/collision.rs9
-rw-r--r--src/types/command.rs41
-rw-r--r--src/types/direction.rs13
-rw-r--r--src/types/entity_map.rs430
-rw-r--r--src/types/menu.rs31
-rw-r--r--src/types/mod.rs504
6 files changed, 0 insertions, 1028 deletions
diff --git a/src/types/collision.rs b/src/types/collision.rs
deleted file mode 100644
index 59c60e69ee50..000000000000
--- a/src/types/collision.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-/// Describes a kind of game collision
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Collision {
-    /// Stop moving - you can't move there!
-    Stop,
-
-    /// Moving into an entity at the given position indicates combat
-    Combat,
-}
diff --git a/src/types/command.rs b/src/types/command.rs
deleted file mode 100644
index 17ca4d280fd8..000000000000
--- a/src/types/command.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use super::Direction;
-use super::Direction::*;
-use termion::event::Key;
-use termion::event::Key::{Char, Ctrl};
-
-pub enum Command {
-    /// Quit the game
-    Quit,
-
-    /// Move the character in a direction
-    Move(Direction),
-
-    /// Pick up any item(s) at the current position
-    PickUp,
-
-    /// Display the previous message
-    PreviousMessage,
-}
-
-impl Command {
-    pub fn from_key(k: Key) -> Option<Command> {
-        use Command::*;
-        match k {
-            Char('q') => Some(Quit),
-
-            Char('h') | Char('a') | Key::Left => Some(Move(Left)),
-            Char('k') | Char('w') | Key::Up => Some(Move(Up)),
-            Char('j') | Char('s') | Key::Down => Some(Move(Down)),
-            Char('l') | Char('d') | Key::Right => Some(Move(Right)),
-            Char('y') => Some(Move(UpLeft)),
-            Char('u') => Some(Move(UpRight)),
-            Char('b') => Some(Move(DownLeft)),
-            Char('n') => Some(Move(DownRight)),
-
-            Ctrl('p') => Some(PreviousMessage),
-            Char(',') => Some(PickUp),
-
-            _ => None,
-        }
-    }
-}
diff --git a/src/types/direction.rs b/src/types/direction.rs
deleted file mode 100644
index 9b5c0991da8d..000000000000
--- a/src/types/direction.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use proptest_derive::Arbitrary;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub enum Direction {
-    Left,
-    Up,
-    Down,
-    Right,
-    UpLeft,
-    UpRight,
-    DownRight,
-    DownLeft,
-}
diff --git a/src/types/entity_map.rs b/src/types/entity_map.rs
deleted file mode 100644
index 202d8b593e15..000000000000
--- a/src/types/entity_map.rs
+++ /dev/null
@@ -1,430 +0,0 @@
-use crate::entities::entity::Identified;
-use crate::entities::EntityID;
-use crate::types::Neighbors;
-use crate::types::Position;
-use crate::types::Positioned;
-use crate::types::PositionedMut;
-use alga::general::{
-    AbstractMagma, AbstractMonoid, AbstractSemigroup, Additive, Identity,
-};
-use std::collections::{hash_map, BTreeMap, HashMap};
-use std::iter::FromIterator;
-
-#[derive(Debug, Clone, Default)]
-pub struct EntityMap<A> {
-    by_position: BTreeMap<Position, Vec<EntityID>>,
-    by_id: HashMap<EntityID, A>,
-    last_id: EntityID,
-}
-
-impl<A: PartialEq> PartialEq for EntityMap<A> {
-    fn eq(&self, other: &Self) -> bool {
-        self.by_position == other.by_position && self.by_id == other.by_id
-    }
-}
-impl<A: Eq> Eq for EntityMap<A> {}
-
-const BY_POS_INVARIANT: &str =
-    "Invariant: All references in EntityMap.by_position should point to existent references in by_id";
-
-impl<A> EntityMap<A> {
-    pub fn new() -> EntityMap<A> {
-        EntityMap {
-            by_position: BTreeMap::new(),
-            by_id: HashMap::new(),
-            last_id: 0,
-        }
-    }
-
-    pub fn len(&self) -> usize {
-        self.by_id.len()
-    }
-
-    /// Returns a list of all entities at the given position
-    pub fn at<'a>(&'a self, pos: Position) -> Vec<&'a A> {
-        self.by_position
-            .get(&pos)
-            .iter()
-            .flat_map(|eids| {
-                eids.iter()
-                    .map(|eid| self.by_id.get(eid).expect(BY_POS_INVARIANT))
-            })
-            .collect()
-    }
-
-    /// Remove all entities at the given position
-    pub fn remove_all_at(&mut self, pos: Position) {
-        if let Some(eids) = self.by_position.remove(&pos) {
-            for eid in eids {
-                self.by_id.remove(&eid).expect(BY_POS_INVARIANT);
-            }
-        }
-    }
-
-    pub fn get(&self, id: EntityID) -> Option<&A> {
-        self.by_id.get(&id)
-    }
-
-    pub fn get_mut(&mut self, id: EntityID) -> Option<&mut A> {
-        self.by_id.get_mut(&id)
-    }
-
-    pub fn entities(&self) -> impl Iterator<Item = &A> {
-        self.by_id.values()
-    }
-
-    pub fn entities_mut(&mut self) -> impl Iterator<Item = &mut A> {
-        self.by_id.values_mut()
-    }
-
-    pub fn ids(&self) -> hash_map::Keys<'_, EntityID, A> {
-        self.by_id.keys()
-    }
-
-    pub fn drain(&mut self) -> Drain<'_, A> {
-        let ids = self.ids().copied().collect::<Vec<_>>();
-        Drain {
-            map: self,
-            ids_iter: Box::new(ids.into_iter()),
-        }
-    }
-
-    fn next_id(&mut self) -> EntityID {
-        self.last_id += 1;
-        self.last_id
-    }
-}
-
-impl<A: Positioned + Identified<EntityID>> EntityMap<A> {
-    pub fn insert(&mut self, mut entity: A) -> EntityID {
-        let pos = entity.position();
-        let entity_id = self.next_id();
-        entity.set_id(entity_id);
-        self.by_id.entry(entity_id).or_insert(entity);
-        self.by_position
-            .entry(pos)
-            .or_insert_with(Vec::new)
-            .push(entity_id);
-        entity_id
-    }
-
-    /// Remove the entity with the given ID
-    pub fn remove(&mut self, id: EntityID) -> Option<A> {
-        self.by_id.remove(&id).map(|e| {
-            let mut empty = false;
-            let position = e.position();
-
-            if let Some(es) = self.by_position.get_mut(&position) {
-                es.retain(|e| *e != id);
-                if es.is_empty() {
-                    empty = true;
-                }
-            }
-
-            if empty {
-                self.by_position.remove(&position);
-            }
-            e
-        })
-    }
-
-    /// Moves all elements from `other` into `Self`, leathing `other` empty.
-    pub fn append(&mut self, other: &mut Self) {
-        // TODO there's probably some perf opportunities here by calling
-        // reserve() on stuff
-        for (_, entity) in other.drain() {
-            self.insert(entity);
-        }
-    }
-
-    /// Gets all 8 neighbors of the given position.
-    pub fn neighbors<'a>(
-        &'a self,
-        position: Position,
-    ) -> Neighbors<Vec<(EntityID, &'a A)>> {
-        Neighbors::of_position(position)
-            .map(|pos| self.at(*pos))
-            .mapmap(&|e| (e.id(), *e))
-    }
-
-    pub fn neighbor_entities<'a>(
-        &'a self,
-        position: Position,
-    ) -> Neighbors<Vec<&'a A>> {
-        self.neighbors(position).mapmap(&|(_eid, ent)| *ent)
-    }
-
-    pub fn check_invariants(&self) {
-        for (id, ent) in &self.by_id {
-            assert_eq!(*id, ent.id());
-        }
-
-        for (pos, ents) in &self.by_position {
-            for eid in ents {
-                let ent = self.by_id.get(eid).unwrap();
-                assert_eq!(*pos, ent.position())
-            }
-        }
-    }
-}
-
-impl<'a, A: Positioned + Identified<EntityID>> IntoIterator
-    for &'a EntityMap<A>
-{
-    type Item = (&'a EntityID, &'a A);
-    type IntoIter = std::collections::hash_map::Iter<'a, EntityID, A>;
-    fn into_iter(self) -> Self::IntoIter {
-        (&self.by_id).iter()
-    }
-}
-
-impl<A: Positioned + Identified<EntityID>> IntoIterator for EntityMap<A> {
-    type Item = (EntityID, A);
-    type IntoIter = std::collections::hash_map::IntoIter<EntityID, A>;
-    fn into_iter(self) -> Self::IntoIter {
-        self.by_id.into_iter()
-    }
-}
-
-impl<A: Positioned + Identified<EntityID>> FromIterator<A> for EntityMap<A> {
-    fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
-        let mut em = EntityMap::new();
-        for ent in iter {
-            em.insert(ent);
-        }
-        em
-    }
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq + Clone> AbstractMagma<Additive>
-    for EntityMap<A>
-{
-    fn operate(&self, right: &Self) -> Self {
-        let mut by_position = self.by_position.clone();
-        by_position.append(&mut right.by_position.clone());
-
-        let mut by_id = self.by_id.clone();
-        for (k, v) in right.by_id.clone() {
-            by_id.insert(k, v);
-        }
-
-        EntityMap {
-            by_position,
-            by_id,
-            last_id: self.last_id.max(right.last_id),
-        }
-    }
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq + Clone>
-    AbstractSemigroup<Additive> for EntityMap<A>
-{
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq> Identity<Additive>
-    for EntityMap<A>
-{
-    fn identity() -> Self {
-        EntityMap::new()
-    }
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq + Clone> AbstractMonoid<Additive>
-    for EntityMap<A>
-{
-}
-
-impl<A: PositionedMut> EntityMap<A> {
-    pub fn update_position(
-        &mut self,
-        entity_id: EntityID,
-        new_position: Position,
-    ) {
-        let mut old_pos = None;
-        if let Some(entity) = self.by_id.get_mut(&entity_id) {
-            if entity.position() == new_position {
-                return;
-            }
-            old_pos = Some(entity.position());
-            entity.set_position(new_position);
-        }
-
-        if let Some(p) = old_pos {
-            if let Some(es) = self.by_position.get_mut(&p) {
-                es.retain(|e| *e != entity_id);
-            }
-
-            self.by_position
-                .entry(new_position)
-                .or_insert_with(Vec::new)
-                .push(entity_id);
-        }
-    }
-}
-
-pub struct Drain<'a, A> {
-    map: &'a mut EntityMap<A>,
-    ids_iter: Box<dyn Iterator<Item = EntityID> + 'a>,
-}
-
-impl<A: Positioned + Identified<EntityID>> Iterator for Drain<'_, A> {
-    type Item = (EntityID, A);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.ids_iter
-            .next()
-            .map(|eid| (eid, self.map.remove(eid).expect(BY_POS_INVARIANT)))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::types::PositionedMut;
-    use proptest::prelude::*;
-    use proptest_derive::Arbitrary;
-
-    #[derive(Debug, Arbitrary, PartialEq, Eq, Clone)]
-    struct TestEntity {
-        _id: Option<EntityID>,
-        position: Position,
-        name: String,
-    }
-
-    impl Positioned for TestEntity {
-        fn position(&self) -> Position {
-            self.position
-        }
-    }
-
-    impl PositionedMut for TestEntity {
-        fn set_position(&mut self, pos: Position) {
-            self.position = pos
-        }
-    }
-
-    impl Identified<EntityID> for TestEntity {
-        fn opt_id(&self) -> Option<EntityID> {
-            self._id
-        }
-
-        fn set_id(&mut self, id: EntityID) {
-            self._id = Some(id);
-        }
-    }
-
-    fn gen_entity_map() -> BoxedStrategy<EntityMap<TestEntity>> {
-        any::<Vec<TestEntity>>()
-            .prop_map(|ents| {
-                ents.iter().cloned().collect::<EntityMap<TestEntity>>()
-            })
-            .boxed()
-    }
-
-    proptest! {
-        #![proptest_config(ProptestConfig::with_cases(10))]
-
-        #[test]
-        fn test_entity_map_len(items: Vec<TestEntity>) {
-            let mut map = EntityMap::new();
-            assert_eq!(map.len(), 0);
-            for ent in &items {
-                map.insert(ent.clone());
-            }
-            assert_eq!(map.len(), items.len());
-        }
-
-        #[test]
-        fn test_entity_map_getset(
-            mut em in gen_entity_map(),
-            ent: TestEntity
-        ) {
-            em.insert(ent.clone());
-            assert!(em.at(ent.position).iter().any(|e| e.name == ent.name))
-        }
-
-        #[test]
-        fn test_entity_map_set_iter_contains(
-            mut em in gen_entity_map(),
-            ent: TestEntity
-        ) {
-            em.insert(ent.clone());
-            assert!(em.entities().any(|e| e.name == ent.name))
-        }
-
-        #[test]
-        fn test_update_position(
-            mut em in gen_entity_map(),
-            ent: TestEntity,
-            new_position: Position,
-        ) {
-            let original_position = ent.position();
-            let entity_id = em.insert(ent.clone());
-            em.update_position(entity_id, new_position);
-
-            if new_position != original_position {
-                assert!(em.at(original_position).iter().all(|e| e.name != ent.name));
-            }
-            assert_eq!(
-                em.get(entity_id).map(|e| e.position()),
-                Some(new_position)
-            );
-            assert!(
-                em.at(new_position).iter().map(
-                    |e| e.name.clone()).any(|en| en == ent.name),
-            )
-        }
-
-        #[test]
-        fn test_remove_all_at(
-            mut em in gen_entity_map(),
-            pos: Position,
-        ) {
-            em.remove_all_at(pos);
-            assert_eq!(em.at(pos).len(), 0);
-        }
-
-        #[test]
-        fn test_entity_map_semigroup_laws(
-            em1 in gen_entity_map(),
-            em2 in gen_entity_map(),
-            em3 in gen_entity_map(),
-        ) {
-            assert!(AbstractSemigroup::prop_is_associative((em1, em2, em3)));
-        }
-
-        fn test_entity_map_monoid_laws(
-            em in gen_entity_map(),
-        ) {
-            assert!(
-                AbstractMonoid::prop_operating_identity_element_is_noop((em,))
-            );
-        }
-
-        #[test]
-        fn test_entity_map_append(
-            mut target in gen_entity_map(),
-            mut source in gen_entity_map(),
-        ) {
-            let orig_target = target.clone();
-            let orig_source = source.clone();
-
-            target.append(&mut source);
-            target.check_invariants();
-
-            assert_eq!(source, EntityMap::new());
-
-            for ent in orig_source.entities() {
-                assert!(
-                    target.at(ent.position()).iter().any(|e| e.name == ent.name)
-                );
-            }
-
-            for ent in orig_target.entities() {
-                assert!(
-                    target.at(ent.position()).iter().any(|e| e.name == ent.name)
-                );
-            }
-        }
-    }
-}
diff --git a/src/types/menu.rs b/src/types/menu.rs
deleted file mode 100644
index 63abc837788e..000000000000
--- a/src/types/menu.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use crate::types::Dimensions;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct MenuInfo {
-    pub prompt: String,
-    pub options: Vec<String>,
-}
-
-impl MenuInfo {
-    pub fn new(prompt: String, options: Vec<String>) -> Self {
-        MenuInfo { prompt, options }
-    }
-
-    /// Returns the inner dimensions of a box necessary to draw this menu. Will
-    /// not trim either dimension to the size of the terminal
-    pub fn dimensions(&self) -> Dimensions {
-        Dimensions {
-            w: self
-                .options
-                .iter()
-                .map(|s| s.len())
-                .max()
-                .unwrap_or(0)
-                .max(self.prompt.len()) as u16
-                + 4,
-            h: self.options.len() as u16
-                + if self.prompt.is_empty() { 0 } else { 2 }
-                + 4,
-        }
-    }
-}
diff --git a/src/types/mod.rs b/src/types/mod.rs
deleted file mode 100644
index d417e873d8ca..000000000000
--- a/src/types/mod.rs
+++ /dev/null
@@ -1,504 +0,0 @@
-#![allow(clippy::unit_arg)]
-#![allow(clippy::identity_conversion)]
-
-use std::cmp::max;
-use std::cmp::Ordering;
-use std::ops;
-use std::rc::Rc;
-
-pub mod collision;
-pub mod command;
-pub mod direction;
-pub mod entity_map;
-pub mod menu;
-
-pub use collision::Collision;
-pub use direction::Direction;
-pub use direction::Direction::*;
-use proptest_derive::Arbitrary;
-use termion::cursor;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct Dimensions {
-    #[proptest(strategy = "std::ops::Range::<u16>::from(0..100)")]
-    pub w: u16,
-
-    #[proptest(strategy = "std::ops::Range::<u16>::from(0..100)")]
-    pub h: u16,
-}
-
-pub const ZERO_DIMENSIONS: Dimensions = Dimensions { w: 0, h: 0 };
-pub const UNIT_DIMENSIONS: Dimensions = Dimensions { w: 1, h: 1 };
-
-impl Default for Dimensions {
-    fn default() -> Self {
-        Dimensions { w: 80, h: 20 }
-    }
-}
-
-impl ops::Sub<Dimensions> for Dimensions {
-    type Output = Dimensions;
-    fn sub(self, dims: Dimensions) -> Dimensions {
-        Dimensions {
-            w: self.w - dims.w,
-            h: self.h - dims.h,
-        }
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct BoundingBox {
-    pub dimensions: Dimensions,
-    pub position: Position,
-}
-
-impl BoundingBox {
-    pub fn at_origin(dimensions: Dimensions) -> BoundingBox {
-        BoundingBox {
-            dimensions,
-            position: ORIGIN,
-        }
-    }
-
-    pub fn from_corners(
-        top_left: Position,
-        lower_right: Position,
-    ) -> BoundingBox {
-        BoundingBox {
-            position: top_left,
-            dimensions: Dimensions {
-                w: (lower_right.x - top_left.x) as u16,
-                h: (lower_right.y - top_left.y) as u16,
-            },
-        }
-    }
-
-    pub fn lr_corner(self) -> Position {
-        self.position
-            + (Position {
-                x: self.dimensions.w as i16,
-                y: self.dimensions.h as i16,
-            })
-    }
-
-    pub fn ll_corner(self) -> Position {
-        self.position
-            + (Position {
-                x: 0,
-                y: self.dimensions.h as i16,
-            })
-    }
-
-    /// Returns a bounding box representing the *inside* of this box if it was
-    /// drawn on the screen.
-    pub fn inner(self) -> BoundingBox {
-        self + UNIT_POSITION - UNIT_DIMENSIONS - UNIT_DIMENSIONS
-    }
-
-    /// Moves the top right corner of the bounding box by the offset specified
-    /// by the given position, keeping the lower right corner in place
-    pub fn move_tr_corner(self, offset: Position) -> BoundingBox {
-        self + offset
-            - Dimensions {
-                w: offset.x as u16,
-                h: offset.y as u16,
-            }
-    }
-}
-
-impl ops::Add<Position> for BoundingBox {
-    type Output = BoundingBox;
-    fn add(self, pos: Position) -> BoundingBox {
-        BoundingBox {
-            position: self.position + pos,
-            ..self
-        }
-    }
-}
-
-impl ops::Sub<Dimensions> for BoundingBox {
-    type Output = BoundingBox;
-    fn sub(self, dims: Dimensions) -> BoundingBox {
-        BoundingBox {
-            dimensions: self.dimensions - dims,
-            ..self
-        }
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary, Hash, Ord)]
-pub struct Position {
-    /// x (horizontal) position
-    #[proptest(strategy = "std::ops::Range::<i16>::from(0..100)")]
-    pub x: i16,
-
-    #[proptest(strategy = "std::ops::Range::<i16>::from(0..100)")]
-    /// y (vertical) position
-    pub y: i16,
-}
-
-pub fn pos(x: i16, y: i16) -> Position {
-    Position { x, y }
-}
-
-pub const ORIGIN: Position = Position { x: 0, y: 0 };
-pub const UNIT_POSITION: Position = Position { x: 1, y: 1 };
-
-impl Position {
-    /// Returns true if this position exists within the bounds of the given box,
-    /// inclusive
-    pub fn within(self, b: BoundingBox) -> bool {
-        (self > b.position - UNIT_POSITION) && self < (b.lr_corner())
-    }
-
-    /// Returns a sequence of ASCII escape characters for moving the cursor to
-    /// this Position
-    pub fn cursor_goto(self) -> cursor::Goto {
-        // + 1 because Goto is 1-based, but position is 0-based
-        cursor::Goto(self.x as u16 + 1, self.y as u16 + 1)
-    }
-
-    /// Converts this position to the number of `Tiles` away from the origin it
-    /// represents. Usually done after subtracting two positions. Gives distance
-    /// as the crow flies
-    pub fn as_tiles(self) -> Tiles {
-        Tiles(max(self.x.abs(), self.y.abs()).into())
-    }
-}
-
-impl PartialOrd for Position {
-    fn partial_cmp(&self, other: &Position) -> Option<Ordering> {
-        if self.x == other.x && self.y == other.y {
-            Some(Ordering::Equal)
-        } else if self.x > other.x && self.y > other.y {
-            Some(Ordering::Greater)
-        } else if self.x < other.x && self.y < other.y {
-            Some(Ordering::Less)
-        } else {
-            None
-        }
-    }
-}
-
-/// Implements (bounded) addition of a Dimension to a position.
-///
-/// # Examples
-///
-/// ```
-/// let pos = Position { x: 1, y: 10 }
-///
-/// let left_pos = pos + Direction::Left
-/// assert_eq!(left, Position { x: 0, y: 10 })
-///
-/// let right_pos = pos + Direction::Right
-/// assert_eq!(right_pos, Position { x: 0, y: 10 })
-/// ```
-#[allow(clippy::suspicious_arithmetic_impl)]
-impl ops::Add<Direction> for Position {
-    type Output = Position;
-    fn add(self, dir: Direction) -> Position {
-        match dir {
-            Left => {
-                if self.x > std::i16::MIN {
-                    Position {
-                        x: self.x - 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            Right => {
-                if self.x < std::i16::MAX {
-                    Position {
-                        x: self.x + 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            Up => {
-                if self.y > std::i16::MIN {
-                    Position {
-                        y: self.y - 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            Down => {
-                if self.y < std::i16::MAX {
-                    Position {
-                        y: self.y + 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            UpLeft => self + Up + Left,
-            UpRight => self + Up + Right,
-            DownLeft => self + Down + Left,
-            DownRight => self + Down + Right,
-        }
-    }
-}
-
-impl ops::Add<Position> for Position {
-    type Output = Position;
-    fn add(self, pos: Position) -> Position {
-        Position {
-            x: self.x + pos.x,
-            y: self.y + pos.y,
-        }
-    }
-}
-
-impl ops::Sub<Position> for Position {
-    type Output = Position;
-    fn sub(self, pos: Position) -> Position {
-        Position {
-            x: self.x - pos.x,
-            y: self.y - pos.y,
-        }
-    }
-}
-
-impl Positioned for Position {
-    fn position(&self) -> Position {
-        *self
-    }
-}
-
-pub trait Positioned {
-    fn x(&self) -> i16 {
-        self.position().x
-    }
-
-    fn y(&self) -> i16 {
-        self.position().y
-    }
-
-    fn position(&self) -> Position {
-        Position {
-            x: self.x(),
-            y: self.y(),
-        }
-    }
-}
-
-pub trait PositionedMut: Positioned {
-    fn set_position(&mut self, pos: Position);
-}
-
-// impl<A, I> Positioned for A where A : Deref<Target = I>, I: Positioned {
-//     fn position(&self) -> Position {
-//         self.position()
-//     }
-// }
-
-impl<T: Positioned> Positioned for Box<T> {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: Positioned> Positioned for &'a T {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: Positioned> Positioned for &'a mut T {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: Positioned> Positioned for Rc<T> {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: PositionedMut> PositionedMut for &'a mut T {
-    fn set_position(&mut self, pos: Position) {
-        (**self).set_position(pos)
-    }
-}
-
-#[macro_export]
-macro_rules! positioned {
-    ($name:ident) => {
-        positioned!($name, position);
-    };
-    ($name:ident, $attr:ident) => {
-        impl $crate::types::Positioned for $name {
-            fn position(&self) -> $crate::types::Position {
-                self.$attr
-            }
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! positioned_mut {
-    ($name:ident) => {
-        positioned_mut!($name, position);
-    };
-    ($name:ident, $attr:ident) => {
-        impl crate::types::PositionedMut for $name {
-            fn set_position(&mut self, pos: $crate::types::Position) {
-                self.$attr = pos;
-            }
-        }
-    };
-}
-
-/// A number of ticks
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct Ticks(pub u16);
-
-/// A number of tiles
-///
-/// Expressed in terms of a float to allow moving partial tiles in a number of
-/// ticks
-#[derive(Clone, Copy, Debug, PartialEq, Arbitrary)]
-pub struct Tiles(pub f32);
-
-/// The speed of an entity, expressed in ticks per tile
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary, Deserialize)]
-#[serde(transparent)]
-pub struct Speed(pub u32);
-
-impl Speed {
-    /// Returns the number of tiles that would be moved in the given number of
-    /// ticks at this speed
-    pub fn ticks_to_tiles(self, ticks: Ticks) -> Tiles {
-        Tiles(f32::from(ticks.0) / self.0 as f32)
-    }
-
-    /// Returns the number of ticks required to move the given number of tiles
-    /// at this speed
-    pub fn tiles_to_ticks(self, tiles: Tiles) -> Ticks {
-        Ticks(tiles.0 as u16 * self.0 as u16)
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct Neighbors<A> {
-    pub top_left: A,
-    pub top: A,
-    pub top_right: A,
-    pub left: A,
-    pub right: A,
-    pub bottom_left: A,
-    pub bottom: A,
-    pub bottom_right: A,
-}
-
-impl Neighbors<Position> {
-    fn of_position(pos: Position) -> Self {
-        Neighbors {
-            top_left: pos + Direction::UpLeft,
-            top: pos + Direction::Up,
-            top_right: pos + Direction::UpRight,
-            left: pos + Direction::Left,
-            right: pos + Direction::Right,
-            bottom_left: pos + Direction::DownLeft,
-            bottom: pos + Direction::Down,
-            bottom_right: pos + Direction::DownRight,
-        }
-    }
-}
-
-impl<A> Neighbors<A> {
-    /// it's a functor, yo
-    pub fn map<B, F: Fn(&A) -> B>(&self, f: F) -> Neighbors<B> {
-        Neighbors {
-            top_left: f(&self.top_left),
-            top: f(&self.top),
-            top_right: f(&self.top_right),
-            left: f(&self.left),
-            right: f(&self.right),
-            bottom_left: f(&self.bottom_left),
-            bottom: f(&self.bottom),
-            bottom_right: f(&self.bottom_right),
-        }
-    }
-}
-
-impl<A> Neighbors<Vec<A>> {
-    pub fn mapmap<B, F: Fn(&A) -> B>(&self, f: &F) -> Neighbors<Vec<B>> {
-        self.map(|xs| xs.iter().map(f).collect())
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    #![allow(clippy::unnecessary_operation)]
-    use super::*;
-    use proptest::prelude::*;
-
-    proptest! {
-        #[test]
-        fn position_partialord_lt_transitive(
-            a: Position,
-            b: Position,
-            c: Position
-        ) {
-            if a < b && b < c {
-                assert!(a < c)
-            }
-        }
-
-        #[test]
-        fn position_partialord_eq_transitive(
-            a: Position,
-            b: Position,
-            c: Position
-        ) {
-            if a == b && b == c {
-                assert!(a == c)
-            }
-        }
-
-        #[test]
-        fn position_partialord_gt_transitive(
-            a: Position,
-            b: Position,
-            c: Position,
-        ) {
-            if a > b && b > c {
-                assert!(a > c)
-            }
-        }
-
-        #[test]
-        fn position_partialord_antisymmetric(a: Position, b: Position) {
-            if a < b {
-                assert!(!(a > b))
-            } else if a > b {
-                assert!(!(a < b))
-            }
-        }
-
-        #[test]
-        fn test_position_plus_dimension_as_tiles_monoid_action(
-            pos: Position,
-            dir: Direction,
-        ) {
-            prop_assume!(pos.y > 0 && pos.x > 0);
-            assert_eq!(((pos + dir) - pos).as_tiles(), Tiles(1.0));
-        }
-    }
-
-    #[test]
-    fn test_position_as_tiles() {
-        assert_eq!(pos(0, 0).as_tiles(), Tiles(0.0));
-        assert_eq!(pos(1, 1).as_tiles(), Tiles(1.0));
-        assert_eq!(pos(1, 2).as_tiles(), Tiles(2.0));
-    }
-}