use std::fmt;
use std::iter;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PieceType {
King,
Rook,
Bishop,
Gold,
Silver,
Knight,
Lance,
Pawn,
ProRook,
ProBishop,
ProSilver,
ProKnight,
ProLance,
ProPawn,
}
impl PieceType {
pub fn iter() -> PieceTypeIter {
PieceTypeIter::new()
}
pub fn from_sfen(c: char) -> Option<Self> {
Some(match c {
'k' | 'K' => PieceType::King,
'r' | 'R' => PieceType::Rook,
'b' | 'B' => PieceType::Bishop,
'g' | 'G' => PieceType::Gold,
's' | 'S' => PieceType::Silver,
'n' | 'N' => PieceType::Knight,
'l' | 'L' => PieceType::Lance,
'p' | 'P' => PieceType::Pawn,
_ => return None,
})
}
#[must_use]
pub fn promote(self) -> Option<Self> {
use self::PieceType::*;
Some(match self {
Pawn => ProPawn,
Lance => ProLance,
Knight => ProKnight,
Silver => ProSilver,
Rook => ProRook,
Bishop => ProBishop,
_ => return None,
})
}
#[must_use]
pub fn unpromote(self) -> Option<Self> {
use self::PieceType::*;
Some(match self {
ProPawn => Pawn,
ProLance => Lance,
ProKnight => Knight,
ProSilver => Silver,
ProRook => Rook,
ProBishop => Bishop,
_ => return None,
})
}
pub fn is_hand_piece(self) -> bool {
matches!(
self,
PieceType::Rook
| PieceType::Bishop
| PieceType::Gold
| PieceType::Silver
| PieceType::Knight
| PieceType::Lance
| PieceType::Pawn
)
}
#[inline(always)]
pub fn index(self) -> usize {
self as usize
}
}
impl fmt::Display for PieceType {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
f,
"{}",
match *self {
PieceType::Bishop => "b",
PieceType::Gold => "g",
PieceType::King => "k",
PieceType::Lance => "l",
PieceType::Knight => "n",
PieceType::Pawn => "p",
PieceType::Rook => "r",
PieceType::Silver => "s",
PieceType::ProBishop => "+b",
PieceType::ProLance => "+l",
PieceType::ProKnight => "+n",
PieceType::ProPawn => "+p",
PieceType::ProRook => "+r",
PieceType::ProSilver => "+s",
}
)
}
}
pub struct PieceTypeIter {
current: Option<PieceType>,
}
impl PieceTypeIter {
fn new() -> PieceTypeIter {
PieceTypeIter {
current: Some(PieceType::King),
}
}
}
impl iter::Iterator for PieceTypeIter {
type Item = PieceType;
fn next(&mut self) -> Option<Self::Item> {
let current = self.current;
if let Some(current) = self.current {
self.current = match current {
PieceType::King => Some(PieceType::Rook),
PieceType::Rook => Some(PieceType::Bishop),
PieceType::Bishop => Some(PieceType::Gold),
PieceType::Gold => Some(PieceType::Silver),
PieceType::Silver => Some(PieceType::Knight),
PieceType::Knight => Some(PieceType::Lance),
PieceType::Lance => Some(PieceType::Pawn),
PieceType::Pawn => Some(PieceType::ProRook),
PieceType::ProRook => Some(PieceType::ProBishop),
PieceType::ProBishop => Some(PieceType::ProSilver),
PieceType::ProSilver => Some(PieceType::ProKnight),
PieceType::ProKnight => Some(PieceType::ProLance),
PieceType::ProLance => Some(PieceType::ProPawn),
PieceType::ProPawn => None,
};
}
current
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_sfen() {
let ok_cases = [
('k', PieceType::King),
('r', PieceType::Rook),
('b', PieceType::Bishop),
('g', PieceType::Gold),
('s', PieceType::Silver),
('n', PieceType::Knight),
('l', PieceType::Lance),
('p', PieceType::Pawn),
];
let ng_cases = ['\0', ' ', '_', 'a', 'z', '+'];
for case in ok_cases.iter() {
assert_eq!(Some(case.1), PieceType::from_sfen(case.0));
assert_eq!(
Some(case.1),
PieceType::from_sfen(case.0.to_uppercase().next().unwrap())
);
}
for case in ng_cases.iter() {
assert!(PieceType::from_sfen(*case).is_none());
}
}
#[test]
fn to_sfen() {
let ok_cases = [
("k", PieceType::King),
("r", PieceType::Rook),
("b", PieceType::Bishop),
("g", PieceType::Gold),
("s", PieceType::Silver),
("n", PieceType::Knight),
("l", PieceType::Lance),
("p", PieceType::Pawn),
("+r", PieceType::ProRook),
("+b", PieceType::ProBishop),
("+s", PieceType::ProSilver),
("+n", PieceType::ProKnight),
("+l", PieceType::ProLance),
("+p", PieceType::ProPawn),
];
for case in ok_cases.iter() {
assert_eq!(case.0, case.1.to_string());
}
}
#[test]
fn promote() {
let ok_cases = [
(PieceType::Rook, PieceType::ProRook),
(PieceType::Bishop, PieceType::ProBishop),
(PieceType::Silver, PieceType::ProSilver),
(PieceType::Knight, PieceType::ProKnight),
(PieceType::Lance, PieceType::ProLance),
(PieceType::Pawn, PieceType::ProPawn),
];
let ng_cases = [
PieceType::King,
PieceType::Gold,
PieceType::ProRook,
PieceType::ProBishop,
PieceType::ProSilver,
PieceType::ProKnight,
PieceType::ProLance,
PieceType::ProPawn,
];
for case in ok_cases.iter() {
assert_eq!(Some(case.1), case.0.promote());
}
for case in ng_cases.iter() {
assert!(case.promote().is_none());
}
}
#[test]
fn unpromote() {
let ok_cases = [
(PieceType::ProRook, PieceType::Rook),
(PieceType::ProBishop, PieceType::Bishop),
(PieceType::ProSilver, PieceType::Silver),
(PieceType::ProKnight, PieceType::Knight),
(PieceType::ProLance, PieceType::Lance),
(PieceType::ProPawn, PieceType::Pawn),
];
let ng_cases = [
PieceType::King,
PieceType::Rook,
PieceType::Bishop,
PieceType::Gold,
PieceType::Silver,
PieceType::Knight,
PieceType::Lance,
PieceType::Pawn,
];
for case in ok_cases.iter() {
assert_eq!(Some(case.1), case.0.unpromote());
}
for case in ng_cases.iter() {
assert!(case.unpromote().is_none());
}
}
}