1use std::str::FromStr;
2
3use crate::{Error, BOARD_SIZE};
4
5#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
7#[repr(u8)]
8pub enum Rank {
9 First,
10 Second,
11 Third,
12 Fourth,
13 Fifth,
14 Sixth,
15 Seventh,
16 Eighth,
17}
18
19pub const NUM_RANKS: usize = BOARD_SIZE.1 as usize;
21
22pub const ALL_RANKS: [Rank; NUM_RANKS] = [
24 Rank::First,
25 Rank::Second,
26 Rank::Third,
27 Rank::Fourth,
28 Rank::Fifth,
29 Rank::Sixth,
30 Rank::Seventh,
31 Rank::Eighth,
32];
33
34impl Rank {
35 #[inline]
39 pub fn new(index: usize) -> Self {
40 ALL_RANKS[index % NUM_RANKS]
41 }
42
43 #[inline]
45 pub fn to_index(&self) -> usize {
46 *self as usize
47 }
48
49 #[inline]
53 pub fn up(&self) -> Self {
54 Rank::new(self.to_index() + 1)
55 }
56
57 #[inline]
61 pub fn down(&self) -> Self {
62 let idx = self.to_index();
63 match idx {
64 0 => Rank::new(NUM_RANKS - 1),
65 _ => Rank::new(idx - 1),
66 }
67 }
68
69 #[inline]
71 pub fn distance(&self, other: Rank) -> u32 {
72 self.to_index().abs_diff(other.to_index()) as u32
73 }
74
75 #[inline]
79 pub fn between(&self, lower_bound: Rank, upper_bound: Rank) -> bool {
80 lower_bound <= *self && *self <= upper_bound
81 }
82}
83
84impl FromStr for Rank {
85 type Err = Error;
86
87 fn from_str(s: &str) -> Result<Self, Self::Err> {
88 if s.is_empty() {
89 return Err(Error::InvalidRank);
90 }
91 match s.chars().next().unwrap() {
92 '1' => Ok(Rank::First),
93 '2' => Ok(Rank::Second),
94 '3' => Ok(Rank::Third),
95 '4' => Ok(Rank::Fourth),
96 '5' => Ok(Rank::Fifth),
97 '6' => Ok(Rank::Sixth),
98 '7' => Ok(Rank::Seventh),
99 '8' => Ok(Rank::Eighth),
100 _ => Err(Error::InvalidRank),
101 }
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn to_index() {
111 assert_eq!(Rank::First.to_index(), 0);
112 assert_eq!(Rank::Second.to_index(), 1);
113 assert_eq!(Rank::Third.to_index(), 2);
114 assert_eq!(Rank::Fourth.to_index(), 3);
115 assert_eq!(Rank::Fifth.to_index(), 4);
116 assert_eq!(Rank::Sixth.to_index(), 5);
117 assert_eq!(Rank::Seventh.to_index(), 6);
118 assert_eq!(Rank::Eighth.to_index(), 7);
119 }
120
121 #[test]
122 fn up() {
123 assert_eq!(Rank::First.up(), Rank::Second);
124 assert_eq!(Rank::Second.up(), Rank::Third);
125 assert_eq!(Rank::Third.up(), Rank::Fourth);
126 assert_eq!(Rank::Fourth.up(), Rank::Fifth);
127 assert_eq!(Rank::Fifth.up(), Rank::Sixth);
128 assert_eq!(Rank::Sixth.up(), Rank::Seventh);
129 assert_eq!(Rank::Seventh.up(), Rank::Eighth);
130 assert_eq!(Rank::Eighth.up(), Rank::First);
131 }
132
133 #[test]
134 fn down() {
135 assert_eq!(Rank::First.down(), Rank::Eighth);
136 assert_eq!(Rank::Second.down(), Rank::First);
137 assert_eq!(Rank::Third.down(), Rank::Second);
138 assert_eq!(Rank::Fourth.down(), Rank::Third);
139 assert_eq!(Rank::Fifth.down(), Rank::Fourth);
140 assert_eq!(Rank::Sixth.down(), Rank::Fifth);
141 assert_eq!(Rank::Seventh.down(), Rank::Sixth);
142 assert_eq!(Rank::Eighth.down(), Rank::Seventh);
143 }
144
145 #[test]
146 fn distance() {
147 assert_eq!(Rank::First.distance(Rank::First), 0);
148 assert_eq!(Rank::First.distance(Rank::Fourth), 3);
149 assert_eq!(Rank::First.distance(Rank::Eighth), 7);
150 }
151
152 #[test]
153 fn between() {
154 assert!(Rank::First.between(Rank::First, Rank::Eighth));
156 assert!(Rank::Eighth.between(Rank::First, Rank::Eighth));
157 assert!(Rank::First.between(Rank::First, Rank::First));
158 assert!(!Rank::First.between(Rank::Second, Rank::Eighth));
160 assert!(!Rank::Eighth.between(Rank::First, Rank::Seventh));
161 assert!(!Rank::Second.between(Rank::Third, Rank::First));
162 }
163
164 #[test]
165 fn from_str() {
166 assert_eq!(Rank::from_str("1"), Ok(Rank::First));
167 assert_eq!(Rank::from_str("2"), Ok(Rank::Second));
168 assert_eq!(Rank::from_str("3"), Ok(Rank::Third));
169 assert_eq!(Rank::from_str("4"), Ok(Rank::Fourth));
170 assert_eq!(Rank::from_str("5"), Ok(Rank::Fifth));
171 assert_eq!(Rank::from_str("6"), Ok(Rank::Sixth));
172 assert_eq!(Rank::from_str("7"), Ok(Rank::Seventh));
173 assert_eq!(Rank::from_str("8"), Ok(Rank::Eighth));
174 }
175
176 #[test]
177 fn from_str_error() {
178 assert_eq!(Rank::from_str(""), Err(Error::InvalidRank));
179 assert_eq!(Rank::from_str(" 1"), Err(Error::InvalidRank));
180 assert_eq!(Rank::from_str("second"), Err(Error::InvalidRank));
181 }
182}