use crate::common::{write_ascii_byte, write_u8};
use crate::{PieceKind, ToUsi};
#[repr(C)]
#[derive(Eq, Clone, Copy, Debug, Default)]
pub struct Hand([u8; 8]);
impl Hand {
#[export_name = "Hand_new"]
#[inline(always)]
pub extern "C" fn new() -> Self {
Self::default()
}
#[inline]
pub fn added(mut self, piece_kind: PieceKind) -> Option<Hand> {
let index = (piece_kind as u8 - 1) as usize;
if index < 7 {
self.0[index] = self.0[index].wrapping_add(1);
return Some(self);
}
None
}
#[inline]
pub fn removed(mut self, piece_kind: PieceKind) -> Option<Hand> {
let index = (piece_kind as u8 - 1) as usize;
if index < 7 {
self.0[index] = self.0[index].checked_sub(1)?;
return Some(self);
}
None
}
#[inline]
pub fn count(self, piece_kind: PieceKind) -> Option<u8> {
let index = (piece_kind as u8 - 1) as usize;
if index < 7 {
return Some(self.0[index]);
}
None
}
#[no_mangle]
pub extern "C" fn Hand_add(&mut self, piece_kind: PieceKind) -> bool {
if let Some(new) = self.added(piece_kind) {
*self = new;
true
} else {
false
}
}
#[no_mangle]
pub extern "C" fn Hand_remove(&mut self, piece_kind: PieceKind) -> bool {
if let Some(new) = self.removed(piece_kind) {
*self = new;
true
} else {
false
}
}
#[no_mangle]
pub extern "C" fn Hand_count(self, piece_kind: PieceKind) -> u8 {
self.count(piece_kind).unwrap_or(0)
}
#[inline(always)]
fn as_u64(self) -> u64 {
unsafe { core::mem::transmute(self) }
}
#[inline]
pub const fn is_hand_piece(piece_kind: PieceKind) -> bool {
(piece_kind as u8) < 8
}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn Hand_is_hand_piece(piece_kind: PieceKind) -> bool {
Hand::is_hand_piece(piece_kind)
}
#[inline]
pub fn all_hand_pieces() -> impl Iterator<Item = PieceKind> {
(1..8).map(|repr| unsafe { PieceKind::from_u8_unchecked(repr) })
}
pub const NUM_HAND_PIECES: usize = 7;
}
impl PartialEq for Hand {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.as_u64() == other.as_u64()
}
}
impl_ord_for_single_field!(Hand);
impl_hash_for_single_field!(Hand);
impl ToUsi for [Hand; 2] {
fn to_usi<W: core::fmt::Write>(&self, sink: &mut W) -> core::fmt::Result {
if self[0] == Hand::new() && self[1] == Hand::new() {
return sink.write_str("-");
}
let pieces = [b"PLNSGBR", b"plnsgbr"];
for i in 0..2 {
for j in (0..7).rev() {
let count = *unsafe { self[i].0.get_unchecked(j) };
if count > 0 {
if count >= 2 {
write_u8(sink, count)?;
}
unsafe { write_ascii_byte(sink, *pieces[i].get_unchecked(j)) }?;
}
}
}
Ok(())
}
}