use core::fmt::{Debug, Display, Formatter};
use core::ops::{Add, Sub};
use derive_more::{From, Into};
#[derive(Copy, Clone, Default, Eq, PartialEq, Hash, From, Into)]
pub struct Player(u8);
pub const P0: Player = Player(0);
pub const P1: Player = Player(1);
pub const P2: Player = Player(2);
pub const P3: Player = Player(3);
pub const ALL_PLAYERS: [Player; 4] = [P0, P1, P2, P3];
impl Player {
pub const fn new(x: u8) -> Self { Player(x & 3) }
pub const fn add(self, other: Player) -> Player {
Player(self.0.wrapping_add(other.0) & 3)
}
pub const fn add_u8(self, other: u8) -> Player {
Player(self.0.wrapping_add(other) & 3)
}
pub const fn sub(self, other: Player) -> Player {
Player(self.0.wrapping_sub(other.0) & 3)
}
pub const fn sub_u8(self, other: u8) -> Player {
Player(self.0.wrapping_sub(other) & 3)
}
pub const fn to_u8(self) -> u8 { self.0 }
pub const fn to_usize(self) -> usize { self.0 as usize }
pub const fn succ(self) -> Self { self.add(P1) }
pub const fn oppo(self) -> Self { self.add(P2) }
pub const fn pred(self) -> Self { self.add(P3) }
}
impl From<usize> for Player {
fn from(x: usize) -> Self { Self::new(x as u8) }
}
impl Into<usize> for Player {
fn into(self) -> usize { self.0 as usize }
}
impl Add for Player {
type Output = Player;
fn add(self, rhs: Self) -> Self::Output { self.add(rhs) }
}
impl Add<u8> for Player {
type Output = Player;
fn add(self, rhs: u8) -> Self::Output { self.add_u8(rhs) }
}
impl Sub for Player {
type Output = Player;
fn sub(self, rhs: Self) -> Self::Output { self.sub(rhs) }
}
impl Sub<u8> for Player {
type Output = Player;
fn sub(self, rhs: u8) -> Self::Output { self.sub_u8(rhs) }
}
impl Debug for Player {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "Player({})", self.0)
}
}
impl Display for Player {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
pub const fn player(i: u8) -> Player { Player::new(i) }
pub const fn all_players_from(player: Player) -> [Player; 4] {
[player.add(P0), player.add(P1), player.add(P2), player.add(P3)]
}
pub const fn other_players_after(player: Player) -> [Player; 3] {
[player.add(P1), player.add(P2), player.add(P3)]
}
#[cfg(feature = "serde")]
mod player_serde {
use core::fmt::Formatter;
use serde::{*};
use serde::de::{Error, Visitor};
use super::*;
impl Serialize for Player {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> where S: Serializer {
s.serialize_u8(self.0.into())
}
}
impl<'de> Deserialize<'de> for Player {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
struct PlayerVisitor;
impl<'a> Visitor<'a> for PlayerVisitor {
type Value = Player;
fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "0..=3")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> where E: Error {
if (0..=3).contains(&v) {
Ok(Player(v as u8))
} else {
Err(E::custom("out of range"))
}
}
}
deserializer.deserialize_u8(PlayerVisitor)
}
}
}