Skip to main content

chess/
rank.rs

1use crate::error::Error;
2use std::str::FromStr;
3
4/// Describe a rank (row) on a chess board
5#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
6#[repr(u8)]
7pub enum Rank {
8	First = 0,
9	Second = 1,
10	Third = 2,
11	Fourth = 3,
12	Fifth = 4,
13	Sixth = 5,
14	Seventh = 6,
15	Eighth = 7,
16}
17
18/// How many ranks are there?
19pub const NUM_RANKS: usize = 8;
20
21/// Enumerate all ranks
22pub const ALL_RANKS: [Rank; NUM_RANKS] = [Rank::First, Rank::Second, Rank::Third, Rank::Fourth, Rank::Fifth, Rank::Sixth, Rank::Seventh, Rank::Eighth];
23
24impl Rank {
25	/// Convert a `usize` into a `Rank` (the inverse of to_index).  If the number is > 7, wrap
26	/// around.
27	#[inline]
28	pub fn from_index(i: usize) -> Rank {
29		// match is optimized to no-op with opt-level=1 with rustc 1.53.0
30		match i & 7 {
31			0 => Rank::First,
32			1 => Rank::Second,
33			2 => Rank::Third,
34			3 => Rank::Fourth,
35			4 => Rank::Fifth,
36			5 => Rank::Sixth,
37			6 => Rank::Seventh,
38			7 => Rank::Eighth,
39			_ => unreachable!(),
40		}
41	}
42
43	/// Go one rank down.  If impossible, wrap around.
44	#[inline]
45	pub fn down(&self) -> Rank {
46		Rank::from_index(self.to_index().wrapping_sub(1))
47	}
48
49	/// Go one file up.  If impossible, wrap around.
50	#[inline]
51	pub fn up(&self) -> Rank {
52		Rank::from_index(self.to_index() + 1)
53	}
54
55	/// Convert this `Rank` into a `usize` between 0 and 7 (inclusive).
56	#[inline]
57	pub fn to_index(self) -> usize {
58		self as usize
59	}
60}
61
62impl FromStr for Rank {
63	type Err = Error;
64
65	fn from_str(s: &str) -> Result<Self, Self::Err> {
66		if s.is_empty() {
67			return Err(Error::InvalidRank);
68		}
69		match s.chars().next().unwrap() {
70			'1' => Ok(Rank::First),
71			'2' => Ok(Rank::Second),
72			'3' => Ok(Rank::Third),
73			'4' => Ok(Rank::Fourth),
74			'5' => Ok(Rank::Fifth),
75			'6' => Ok(Rank::Sixth),
76			'7' => Ok(Rank::Seventh),
77			'8' => Ok(Rank::Eighth),
78			_ => Err(Error::InvalidRank),
79		}
80	}
81}