1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
//! The `pos` module contains structures for representation an
//! entity or objects position and facing direction inside the
//! dungeon grid.
use crate::map::MAP_SIZE;
/// The `Direction` type represents a direction an entity
/// or any position object is facing inside the dungeon map.
/// Since the dungeon lives on a grid, there are only four
/// possible directions.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
/// The `Pos` type represents a 2D position inside the dungeon grid.
///
/// The max size for the dungeon map is set by the `MAP_SIZE` constant
/// and therefore the x and y positions can be between 0 and `MAP_SIZE - 1`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Pos(u16, u16);
impl Pos {
/// Creates a new position from a given x and y position.
///
/// Returns `None` if the position goes out of the map.
///
/// # Examples
///
/// ```
/// use dungeon::Pos;
///
/// let pos = Pos::new(0,0);
/// assert!(pos.is_some());
/// ```
///
/// ```
/// use dungeon::{Pos, MAP_SIZE};
///
/// let pos = Pos::new(MAP_SIZE, MAP_SIZE);
/// assert!(pos.is_none())
/// ```
#[must_use]
pub const fn new(x: u16, y: u16) -> Option<Self> {
if x >= MAP_SIZE || y >= MAP_SIZE {
None
} else {
Some(Self(x, y))
}
}
/// Returns the x and y positions of `Pos`.
///
/// # Examples
///
/// ```
/// use dungeon::Pos;
///
/// let pos = Pos::new(5,7).unwrap();
/// let (x,y) = pos.xy();
/// assert_eq!(x, 5);
/// assert_eq!(y, 7);
/// ```
#[must_use]
pub const fn xy(self) -> (u16, u16) {
(self.0, self.1)
}
/// Converts the x and y positions into an index of a continous list.
///
/// # Examples
///
/// ```
/// use dungeon::{Pos, MAP_SIZE};
///
/// let pos = Pos::new(1,2).unwrap();
/// let idx = pos.idx();
/// assert_eq!(idx, 1 + 2 * MAP_SIZE as usize);
/// ```
#[must_use]
pub const fn idx(self) -> usize {
let (x, y) = self.xy();
let idx = x + y * MAP_SIZE;
idx as usize
}
/// Steps `Pos` one space in the `Direction` `dir`.
///
/// Returns `None` if the position goes out of the map.
///
/// # Examples
///
/// ```
/// use dungeon::{Direction, Pos};
///
/// let pos = Pos::new(0, 1).unwrap();
/// let new_pos = pos.step(Direction::North);
/// assert_eq!(new_pos, Pos::new(0, 0));
/// ```
///
/// ```
/// use dungeon::{Direction, Pos};
///
/// let pos = Pos::new(0, 1).unwrap();
/// let new_pos = pos.step(Direction::West);
/// assert!(new_pos.is_none());
/// ```
#[must_use]
pub const fn step(self, dir: Direction) -> Option<Self> {
use Direction as D;
let (x, y) = self.xy();
match dir {
D::North if y > 0 => Self::new(x, y - 1),
D::South => Self::new(x, y + 1),
D::East => Self::new(x + 1, y),
D::West if x > 0 => Self::new(x - 1, y),
_ => None,
}
}
}
|