use super::PieceType;
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct HandPiece(i8);
const _: () = {
assert!(core::mem::size_of::<HandPiece>() == 1);
assert!(core::mem::align_of::<HandPiece>() == 1);
};
pub const HAND_BIT_MASK: u32 =
0x1f | (0x7 << 8) | (0x7 << 12) | (0x7 << 16) | (0x3 << 20) | (0x3 << 24) | (0x7 << 28);
pub const HAND_BORROW_MASK: u32 = (HAND_BIT_MASK << 1) & !HAND_BIT_MASK;
impl HandPiece {
pub const PAWN: Self = Self(0);
pub const LANCE: Self = Self(1);
pub const KNIGHT: Self = Self(2);
pub const SILVER: Self = Self(3);
pub const BISHOP: Self = Self(4);
pub const ROOK: Self = Self(5);
pub const GOLD: Self = Self(6);
pub const COUNT: usize = 7;
#[inline]
#[must_use]
pub const fn new(raw: i8) -> Self {
Self(raw)
}
#[must_use]
pub const fn from_piece_type(pt: PieceType) -> Option<Self> {
match pt {
PieceType::PAWN => Some(Self::PAWN),
PieceType::LANCE => Some(Self::LANCE),
PieceType::KNIGHT => Some(Self::KNIGHT),
PieceType::SILVER => Some(Self::SILVER),
PieceType::BISHOP => Some(Self::BISHOP),
PieceType::ROOK => Some(Self::ROOK),
PieceType::GOLD => Some(Self::GOLD),
_ => None,
}
}
#[must_use]
pub const fn to_piece_type(self) -> PieceType {
match self {
Self::PAWN => PieceType::PAWN,
Self::LANCE => PieceType::LANCE,
Self::KNIGHT => PieceType::KNIGHT,
Self::SILVER => PieceType::SILVER,
Self::BISHOP => PieceType::BISHOP,
Self::ROOK => PieceType::ROOK,
Self::GOLD => PieceType::GOLD,
_ => PieceType::NONE,
}
}
#[must_use]
pub const fn is_valid(self) -> bool {
self.raw() >= 0 && self.raw() <= Self::GOLD.raw()
}
#[inline]
#[must_use]
pub const fn raw(self) -> i8 {
self.0
}
#[inline]
#[must_use]
pub fn iter() -> impl DoubleEndedIterator<Item = Self> + ExactSizeIterator {
(0..Self::COUNT).map(|i| Self::new(i as i8))
}
}
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Hand(u32);
const _: () = {
assert!(core::mem::size_of::<Hand>() == 4);
assert!(core::mem::align_of::<Hand>() == 4);
};
impl Hand {
pub const ZERO: Self = Self(0);
#[inline]
#[must_use]
pub const fn from_bits(bits: u32) -> Self {
Self(bits)
}
#[inline]
#[must_use]
pub const fn bits(self) -> u32 {
self.0
}
const PIECE_BITS: [u32; 7] = [
0, 8, 12, 16, 20, 24, 28, ];
const PIECE_BIT_MASK: [u32; 7] = [
0x1f, 0x07, 0x07, 0x07, 0x03, 0x03, 0x07, ];
const PIECE_BIT_ONE: [u32; 7] = [
1 << 0, 1 << 8, 1 << 12, 1 << 16, 1 << 20, 1 << 24, 1 << 28, ];
#[inline]
#[must_use]
pub const fn count_of(hand: Self, hp: HandPiece) -> u32 {
if let Some(idx) = Self::index_for(hp) {
let shift = Self::PIECE_BITS[idx];
let mask = Self::PIECE_BIT_MASK[idx];
(hand.0 >> shift) & mask
} else {
0
}
}
#[inline]
#[must_use]
pub const fn has(hand: Self, hp: HandPiece) -> bool {
Self::count_of(hand, hp) > 0
}
#[inline]
#[must_use]
pub const fn add_one(hand: Self, hp: HandPiece) -> Self {
if let Some(idx) = Self::index_for(hp) {
Self(hand.0 + Self::PIECE_BIT_ONE[idx])
} else {
hand
}
}
#[inline]
#[must_use]
pub const fn sub_one(hand: Self, hp: HandPiece) -> Self {
if let Some(idx) = Self::index_for(hp) {
Self(hand.0 - Self::PIECE_BIT_ONE[idx])
} else {
hand
}
}
#[must_use]
pub const fn is_equal_or_superior(h1: Self, h2: Self) -> bool {
(h1.0.wrapping_sub(h2.0) & HAND_BORROW_MASK) == 0
}
#[must_use]
#[inline]
pub const fn has_overflow(self) -> bool {
(self.0 & HAND_BORROW_MASK) != 0
}
#[must_use]
#[inline]
pub fn checked_add(self, hp: HandPiece, n: u32) -> Option<Self> {
let hand = if let Some(idx) = Self::index_for(hp) {
let shift = Self::PIECE_BITS[idx];
let mask = Self::PIECE_BIT_MASK[idx];
let current = (self.0 >> shift) & mask;
let next = current.checked_add(n)?;
if next > mask {
return None;
}
let cleared = self.0 & !(mask << shift);
Self(cleared | (next << shift))
} else {
self
};
if hand.has_overflow() { None } else { Some(hand) }
}
#[inline]
#[must_use]
pub const fn count(&self, hp: HandPiece) -> u32 {
Self::count_of(*self, hp)
}
#[inline]
pub fn add(&mut self, hp: HandPiece, n: u32) {
if let Some(idx) = Self::index_for(hp) {
self.0 += Self::PIECE_BIT_ONE[idx] * n;
}
}
#[inline]
pub fn sub(&mut self, hp: HandPiece, n: u32) {
if let Some(idx) = Self::index_for(hp) {
self.0 -= Self::PIECE_BIT_ONE[idx] * n;
}
}
#[inline]
#[must_use]
pub const fn pawn_count(&self) -> u32 {
self.count(HandPiece::PAWN)
}
const fn index_for(hp: HandPiece) -> Option<usize> {
match hp {
HandPiece::PAWN => Some(0),
HandPiece::LANCE => Some(1),
HandPiece::KNIGHT => Some(2),
HandPiece::SILVER => Some(3),
HandPiece::BISHOP => Some(4),
HandPiece::ROOK => Some(5),
HandPiece::GOLD => Some(6),
_ => None,
}
}
}
impl Default for Hand {
fn default() -> Self {
Self::ZERO
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hand_piece_constants() {
assert_eq!(HandPiece::PAWN.raw(), 0);
assert_eq!(HandPiece::LANCE.raw(), 1);
assert_eq!(HandPiece::KNIGHT.raw(), 2);
assert_eq!(HandPiece::SILVER.raw(), 3);
assert_eq!(HandPiece::BISHOP.raw(), 4);
assert_eq!(HandPiece::ROOK.raw(), 5);
assert_eq!(HandPiece::GOLD.raw(), 6);
assert_eq!(HandPiece::COUNT, 7);
}
#[test]
fn test_hand_piece_conversion() {
let test_cases = [
(PieceType::PAWN, HandPiece::PAWN),
(PieceType::LANCE, HandPiece::LANCE),
(PieceType::KNIGHT, HandPiece::KNIGHT),
(PieceType::SILVER, HandPiece::SILVER),
(PieceType::BISHOP, HandPiece::BISHOP),
(PieceType::ROOK, HandPiece::ROOK),
(PieceType::GOLD, HandPiece::GOLD),
];
for (pt, hp) in test_cases {
assert_eq!(HandPiece::from_piece_type(pt), Some(hp));
assert_eq!(hp.to_piece_type(), pt);
}
assert_eq!(HandPiece::from_piece_type(PieceType::KING), None);
assert_eq!(HandPiece::from_piece_type(PieceType::PRO_PAWN), None);
assert_eq!(HandPiece::from_piece_type(PieceType::NONE), None);
}
#[test]
fn test_hand_piece_is_ok() {
for i in 0..7 {
assert!(HandPiece::new(i).is_valid());
}
assert!(!HandPiece::new(-1).is_valid());
assert!(!HandPiece::new(7).is_valid());
assert!(!HandPiece::new(100).is_valid());
}
#[test]
fn test_hand_bit_packing() {
assert_eq!(Hand::ZERO.bits(), 0);
let mut hand = Hand::ZERO;
hand = Hand::add_one(hand, HandPiece::PAWN);
assert_eq!(Hand::count_of(hand, HandPiece::PAWN), 1);
assert_eq!(hand.bits(), 1);
hand = Hand::add_one(hand, HandPiece::LANCE);
assert_eq!(Hand::count_of(hand, HandPiece::LANCE), 1);
assert_eq!(hand.bits(), 1 | (1 << 8));
hand = Hand::add_one(hand, HandPiece::KNIGHT);
assert_eq!(Hand::count_of(hand, HandPiece::KNIGHT), 1);
assert_eq!(hand.bits(), 1 | (1 << 8) | (1 << 12));
}
#[test]
fn test_hand_add_sub() {
let mut hand = Hand::ZERO;
for _ in 0..5 {
hand = Hand::add_one(hand, HandPiece::PAWN);
}
assert_eq!(Hand::count_of(hand, HandPiece::PAWN), 5);
hand.sub(HandPiece::PAWN, 2);
assert_eq!(Hand::count_of(hand, HandPiece::PAWN), 3);
hand = Hand::add_one(hand, HandPiece::BISHOP);
hand = Hand::add_one(hand, HandPiece::BISHOP);
assert_eq!(Hand::count_of(hand, HandPiece::BISHOP), 2);
hand = Hand::add_one(hand, HandPiece::ROOK);
assert_eq!(Hand::count_of(hand, HandPiece::ROOK), 1);
}
#[test]
fn test_hand_exists() {
let mut hand = Hand::ZERO;
assert!(!Hand::has(hand, HandPiece::PAWN));
assert!(!Hand::has(hand, HandPiece::GOLD));
hand = Hand::add_one(hand, HandPiece::GOLD);
assert!(Hand::has(hand, HandPiece::GOLD));
assert!(!Hand::has(hand, HandPiece::PAWN));
}
#[test]
fn test_hand_is_equal_or_superior() {
let h1 = Hand::ZERO;
let mut h2 = Hand::ZERO;
assert!(Hand::is_equal_or_superior(h1, h2));
h2 = Hand::add_one(h2, HandPiece::PAWN);
assert!(!Hand::is_equal_or_superior(h1, h2));
let mut h3 = Hand::add_one(h1, HandPiece::PAWN);
h3 = Hand::add_one(h3, HandPiece::PAWN);
assert!(Hand::is_equal_or_superior(h3, h2));
let mut h4 = Hand::ZERO;
let mut h5 = Hand::ZERO;
for _ in 0..3 {
h4 = Hand::add_one(h4, HandPiece::PAWN);
}
h4 = Hand::add_one(h4, HandPiece::GOLD);
for _ in 0..2 {
h5 = Hand::add_one(h5, HandPiece::PAWN);
}
h5 = Hand::add_one(h5, HandPiece::GOLD);
assert!(Hand::is_equal_or_superior(h4, h5));
assert!(!Hand::is_equal_or_superior(h5, h4));
}
#[test]
fn test_hand_overflow_boundary() {
let mut hand = Hand::ZERO;
for _ in 0..18 {
hand = Hand::add_one(hand, HandPiece::PAWN);
}
assert_eq!(Hand::count_of(hand, HandPiece::PAWN), 18);
for _ in 0..4 {
hand = Hand::add_one(hand, HandPiece::GOLD);
}
assert_eq!(Hand::count_of(hand, HandPiece::GOLD), 4);
assert_eq!(Hand::count_of(hand, HandPiece::PAWN), 18);
assert_eq!(Hand::count_of(hand, HandPiece::LANCE), 0);
}
#[test]
fn test_hand_has_overflow() {
let mut hand = Hand::ZERO;
for _ in 0..31 {
hand = Hand::add_one(hand, HandPiece::PAWN);
}
assert!(!hand.has_overflow());
hand = Hand::add_one(hand, HandPiece::PAWN);
assert!(hand.has_overflow());
}
#[test]
fn test_hand_checked_add() {
let hand =
Hand::ZERO.checked_add(HandPiece::PAWN, 18).expect("pawn count within field width");
assert_eq!(hand.count(HandPiece::PAWN), 18);
assert!(!hand.has_overflow());
let hand =
Hand::ZERO.checked_add(HandPiece::GOLD, 7).expect("gold count within field width");
assert_eq!(hand.count(HandPiece::GOLD), 7);
assert!(hand.checked_add(HandPiece::GOLD, 1).is_none());
assert!(Hand::ZERO.checked_add(HandPiece::PAWN, 32).is_none());
}
}