use super::bona_piece::{BonaPiece, ExtBonaPiece, FE_HAND_END};
use crate::types::Square;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(transparent)]
pub struct PieceNumber(pub u8);
impl PieceNumber {
pub const NONE: PieceNumber = PieceNumber(u8::MAX);
pub const KING: u8 = 38;
pub const NB: usize = 40;
}
const PIECE_NUMBER_BASE: [u8; 8] = [
0, 18, 22, 26, 30, 34, 36, 38, ];
const PT_TO_BASE_INDEX: [u8; 9] = [
u8::MAX, 0, 1, 2, 3, 5, 6, 4, 7, ];
#[derive(Clone)]
pub struct PieceList {
piece_list_fb: [BonaPiece; PieceNumber::NB],
piece_list_fw: [BonaPiece; PieceNumber::NB],
piece_no_on_board: [PieceNumber; Square::NUM + 1],
piece_no_on_hand: [PieceNumber; FE_HAND_END],
}
impl PieceList {
pub fn new() -> Self {
Self {
piece_list_fb: [BonaPiece::ZERO; PieceNumber::NB],
piece_list_fw: [BonaPiece::ZERO; PieceNumber::NB],
piece_no_on_board: [PieceNumber::NONE; Square::NUM + 1],
piece_no_on_hand: [PieceNumber::NONE; FE_HAND_END],
}
}
#[inline]
pub fn put_piece_on_board(&mut self, piece_no: PieceNumber, bp: ExtBonaPiece, sq: Square) {
self.piece_list_fb[piece_no.0 as usize] = bp.fb;
self.piece_list_fw[piece_no.0 as usize] = bp.fw;
self.piece_no_on_board[sq.index()] = piece_no;
}
#[inline]
pub fn put_piece_on_hand(&mut self, piece_no: PieceNumber, bp: ExtBonaPiece) {
self.piece_list_fb[piece_no.0 as usize] = bp.fb;
self.piece_list_fw[piece_no.0 as usize] = bp.fw;
debug_assert!(
(bp.fb.value() as usize) < FE_HAND_END,
"fb ({}) out of hand range (< {})",
bp.fb.value(),
FE_HAND_END
);
self.piece_no_on_hand[bp.fb.value() as usize] = piece_no;
}
#[inline]
pub fn piece_no_of_board(&self, sq: Square) -> PieceNumber {
self.piece_no_on_board[sq.index()]
}
#[inline]
pub fn piece_no_of_hand(&self, fb: BonaPiece) -> PieceNumber {
debug_assert!(
(fb.value() as usize) < FE_HAND_END,
"fb ({}) out of hand range (< {})",
fb.value(),
FE_HAND_END
);
self.piece_no_on_hand[fb.value() as usize]
}
#[inline]
pub fn bona_piece(&self, piece_no: PieceNumber) -> ExtBonaPiece {
ExtBonaPiece {
fb: self.piece_list_fb[piece_no.0 as usize],
fw: self.piece_list_fw[piece_no.0 as usize],
}
}
#[inline]
pub fn piece_list_fb(&self) -> &[BonaPiece; PieceNumber::NB] {
&self.piece_list_fb
}
#[inline]
pub fn piece_list_fw(&self) -> &[BonaPiece; PieceNumber::NB] {
&self.piece_list_fw
}
}
impl Default for PieceList {
fn default() -> Self {
Self::new()
}
}
#[inline]
pub fn piece_number_base(pt: crate::types::PieceType) -> u8 {
let raw_pt = pt.unpromote() as u8;
debug_assert!(raw_pt <= 8, "Invalid PieceType: {raw_pt}");
let idx = PT_TO_BASE_INDEX[raw_pt as usize];
debug_assert!(idx != u8::MAX, "Unsupported PieceType for piece_number_base");
PIECE_NUMBER_BASE[idx as usize]
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::PieceType;
#[test]
fn test_piece_number_base() {
assert_eq!(piece_number_base(PieceType::Pawn), 0);
assert_eq!(piece_number_base(PieceType::Lance), 18);
assert_eq!(piece_number_base(PieceType::Knight), 22);
assert_eq!(piece_number_base(PieceType::Silver), 26);
assert_eq!(piece_number_base(PieceType::Gold), 30);
assert_eq!(piece_number_base(PieceType::Bishop), 34);
assert_eq!(piece_number_base(PieceType::Rook), 36);
assert_eq!(piece_number_base(PieceType::King), 38);
}
#[test]
fn test_piece_number_base_promoted() {
assert_eq!(piece_number_base(PieceType::ProPawn), piece_number_base(PieceType::Pawn));
assert_eq!(piece_number_base(PieceType::Horse), piece_number_base(PieceType::Bishop));
assert_eq!(piece_number_base(PieceType::Dragon), piece_number_base(PieceType::Rook));
}
#[test]
fn test_piece_list_put_and_get() {
let mut pl = PieceList::new();
let pn = PieceNumber(0);
let bp = ExtBonaPiece::new(BonaPiece::new(100), BonaPiece::new(200));
let sq = Square::SQ_55;
pl.put_piece_on_board(pn, bp, sq);
assert_eq!(pl.piece_no_of_board(sq), pn);
assert_eq!(pl.bona_piece(pn), bp);
assert_eq!(pl.piece_list_fb()[0], BonaPiece::new(100));
assert_eq!(pl.piece_list_fw()[0], BonaPiece::new(200));
}
#[test]
fn test_piece_list_hand() {
let mut pl = PieceList::new();
let pn = PieceNumber(0);
let bp = ExtBonaPiece::new(BonaPiece::new(1), BonaPiece::new(20));
pl.put_piece_on_hand(pn, bp);
assert_eq!(pl.piece_no_of_hand(BonaPiece::new(1)), pn);
assert_eq!(pl.bona_piece(pn), bp);
}
}