use std::ops::{BitOr, Shl};
use crate::error::ParseError;
use crate::error::ParseError::BadChar;
use crate::pieces::PieceType::{Commander, Guard, King, Knight, Mercenary, Soldier};
use crate::pieces::Side::{Attacker, Defender};
use crate::tiles::Tile;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
pub(crate) use crate::collections::pieceset::PieceSet;
pub const KING: Piece = Piece { piece_type: King, side: Defender };
pub const BASIC_PIECES: PieceSet = PieceSet::none()
.with_piece_type(Soldier)
.with_piece(KING);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Side {
Attacker = 0,
Defender = 8
}
impl Side {
pub fn other(&self) -> Self {
match self {
Attacker => Defender,
Defender => Attacker
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PieceType {
King = 0b0000_0001,
Soldier = 0b0000_0010,
Knight = 0b0000_0100,
Commander = 0b0000_1000,
Guard = 0b0001_0000,
Mercenary = 0b0010_0000
}
impl Shl<Side> for PieceType {
type Output = u16;
fn shl(self, rhs: Side) -> Self::Output {
(self as u16) << (rhs as u16)
}
}
impl BitOr<PieceType> for PieceType {
type Output = u8;
fn bitor(self, rhs: PieceType) -> Self::Output {
(self as u8) | (rhs as u8)
}
}
impl BitOr<PieceType> for u16 {
type Output = u16;
fn bitor(self, rhs: PieceType) -> Self::Output {
self | (rhs as u16)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Piece {
pub piece_type: PieceType,
pub side: Side
}
impl Piece {
pub const fn new(piece_type: PieceType, side: Side) -> Self {
Self { piece_type, side }
}
pub const fn king() -> Self {
Self {
piece_type: King,
side: Defender
}
}
pub const fn attacker(piece_type: PieceType) -> Self {
Self {
piece_type,
side: Attacker
}
}
pub const fn defender(piece_type: PieceType) -> Self {
Self {
piece_type,
side: Defender
}
}
}
impl From<Piece> for char {
fn from(value: Piece) -> Self {
let c = match value.piece_type {
Soldier => 't',
King => 'k',
Knight => 'n',
Commander => 'c',
Guard => 'g',
Mercenary => 'm'
};
match value.side {
Attacker => c,
Defender => c.to_ascii_uppercase()
}
}
}
impl TryFrom<char> for Piece {
type Error = ParseError;
fn try_from(mut value: char) -> Result<Self, Self::Error> {
if !value.is_alphabetic() {
return Err(BadChar(value))
}
let side = if value.is_ascii_uppercase() {
value = value.to_ascii_lowercase();
Defender
} else {
Attacker
};
match value {
't' => Ok(Piece::new(Soldier, side)),
'k' => Ok(Piece::new(King, side)),
'n' => Ok(Piece::new(Knight, side)),
'c' => Ok(Piece::new(Commander, side)),
'g' => Ok(Piece::new(Guard, side)),
'm' => Ok(Piece::new(Mercenary, side)),
other => Err(BadChar(other))
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PlacedPiece {
pub tile: Tile,
pub piece: Piece
}
impl PlacedPiece {
pub fn new(tile: Tile, piece: Piece) -> Self {
Self { tile, piece }
}
}
#[cfg(test)]
mod tests {
use crate::pieces::{Piece, PieceSet, KING};
use crate::pieces::PieceType::{Commander, Guard, King, Knight, Mercenary, Soldier};
use crate::pieces::Side::{Attacker, Defender};
#[test]
fn test_piece_set() {
let mut ps = PieceSet::from(vec![
King,
Soldier,
Guard
]);
for s in [Attacker, Defender] {
assert!(ps.contains(Piece::new(King, s)));
assert!(ps.contains(Piece::new(Soldier, s)));
assert!(ps.contains(Piece::new(Guard, s)));
assert!(!ps.contains(Piece::new(Commander, s)));
assert!(!ps.contains(Piece::new(Knight, s)));
assert!(!ps.contains(Piece::new(Mercenary, s)));
}
ps.unset_piece(Piece::new(King, Attacker));
assert!(ps.contains(Piece::new(King, Defender)));
assert!(!ps.contains(Piece::new(King, Attacker)));
for s in [Attacker, Defender] {
assert!(ps.contains(Piece::new(Soldier, s)));
assert!(ps.contains(Piece::new(Guard, s)));
assert!(!ps.contains(Piece::new(Commander, s)));
assert!(!ps.contains(Piece::new(Knight, s)));
assert!(!ps.contains(Piece::new(Mercenary, s)));
}
ps.set_piece(Piece::new(Commander, Defender));
assert!(ps.contains(Piece::new(Commander, Defender)));
assert!(!ps.contains(Piece::new(Commander, Attacker)));
assert!(ps.contains(Piece::new(King, Defender)));
assert!(!ps.contains(Piece::new(King, Attacker)));
for s in [Attacker, Defender] {
assert!(ps.contains(Piece::new(Soldier, s)));
assert!(ps.contains(Piece::new(Guard, s)));
assert!(!ps.contains(Piece::new(Knight, s)));
assert!(!ps.contains(Piece::new(Mercenary, s)));
}
}
#[test]
fn test_empty() {
assert!(PieceSet::none().is_empty());
assert!(!PieceSet::from(vec![King]).is_empty());
assert!(!PieceSet::from(vec![Soldier, Guard]).is_empty());
assert!(!PieceSet::from_piece(Piece::new(Soldier, Attacker)).is_empty());
assert!(!PieceSet::all().is_empty());
}
#[test]
fn test_king_only() {
assert!(PieceSet::from(vec![King]).is_king_only());
assert!(PieceSet::from_piece(KING).is_king_only());
assert!(!PieceSet::from(vec![King, Soldier]).is_king_only());
assert!(!PieceSet::from(vec![King, Soldier, Guard]).is_king_only());
assert!(!PieceSet::from(vec![Soldier, Guard, Commander]).is_king_only());
assert!(!PieceSet::none().is_king_only());
}
}