use auto_ops::impl_op_ex;
use std::fmt::Display;
#[repr(transparent)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Nimber(u32);
impl Nimber {
pub const fn new(value: u32) -> Self {
Self(value)
}
pub const fn value(&self) -> u32 {
self.0
}
pub fn mex(mut nimbers: Vec<Self>) -> Self {
nimbers.sort();
let mut current = 0;
for n in nimbers {
match current.cmp(&n.0) {
std::cmp::Ordering::Less => return Self(current),
std::cmp::Ordering::Equal => current += 1,
std::cmp::Ordering::Greater => {}
}
}
Self(current)
}
}
impl From<u32> for Nimber {
fn from(value: u32) -> Self {
Self(value)
}
}
impl_op_ex!(+|lhs: &Nimber, rhs: &Nimber| -> Nimber { Nimber(lhs.0 ^ rhs.0) });
impl_op_ex!(+=|lhs: &mut Nimber, rhs: &Nimber| { lhs.0 ^= rhs.0 });
impl_op_ex!(-|lhs: &Nimber, rhs: &Nimber| -> Nimber { Nimber(lhs.0 ^ rhs.0) });
impl_op_ex!(-=|lhs: &mut Nimber, rhs: &Nimber| { lhs.0 ^= rhs.0 });
impl_op_ex!(-|lhs: &Nimber| -> Nimber { *lhs });
impl Display for Nimber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0 == 0 {
write!(f, "0")
} else if self.0 == 1 {
write!(f, "*")
} else {
write!(f, "*{}", self.0)
}
}
}
#[test]
fn mex_works() {
assert_eq!(
Nimber(3),
Nimber::mex(vec![Nimber(0), Nimber(0), Nimber(2), Nimber(5), Nimber(1)])
);
assert_eq!(
Nimber(3),
Nimber::mex(vec![Nimber(0), Nimber(1), Nimber(2)])
);
assert_eq!(
Nimber(2),
Nimber::mex(vec![Nimber(0), Nimber(1), Nimber(1)])
);
assert_eq!(Nimber(0), Nimber::mex(vec![]));
}