use crate::types::{Color, Piece, PieceType, Square};
pub const FE_HAND_END: usize = 90;
pub const F_HAND_PAWN: u16 = 1;
pub const F_HAND_LANCE: u16 = 39;
pub const F_HAND_KNIGHT: u16 = 49;
pub const F_HAND_SILVER: u16 = 59;
pub const F_HAND_GOLD: u16 = 69;
pub const F_HAND_BISHOP: u16 = 79;
pub const F_HAND_ROOK: u16 = 85;
pub const E_HAND_PAWN: u16 = 20;
pub const E_HAND_LANCE: u16 = 44;
pub const E_HAND_KNIGHT: u16 = 54;
pub const E_HAND_SILVER: u16 = 64;
pub const E_HAND_GOLD: u16 = 74;
pub const E_HAND_BISHOP: u16 = 82;
pub const E_HAND_ROOK: u16 = 88;
pub const F_PAWN: u16 = 90;
pub const E_PAWN: u16 = 171;
pub const F_LANCE: u16 = 252;
pub const E_LANCE: u16 = 333;
pub const F_KNIGHT: u16 = 414;
pub const E_KNIGHT: u16 = 495;
pub const F_SILVER: u16 = 576;
pub const E_SILVER: u16 = 657;
pub const F_GOLD: u16 = 738;
pub const E_GOLD: u16 = 819;
pub const F_BISHOP: u16 = 900;
pub const E_BISHOP: u16 = 981;
pub const F_HORSE: u16 = 1062;
pub const E_HORSE: u16 = 1143;
pub const F_ROOK: u16 = 1224;
pub const E_ROOK: u16 = 1305;
pub const F_DRAGON: u16 = 1386;
pub const E_DRAGON: u16 = 1467;
pub const PIECE_BASE: [[u16; 2]; 15] = [
[0, 0],
[E_PAWN, F_PAWN], [E_LANCE, F_LANCE],
[E_KNIGHT, F_KNIGHT],
[E_SILVER, F_SILVER],
[E_BISHOP, F_BISHOP],
[E_ROOK, F_ROOK],
[E_GOLD, F_GOLD],
[0, 0],
[E_GOLD, F_GOLD],
[E_GOLD, F_GOLD],
[E_GOLD, F_GOLD],
[E_GOLD, F_GOLD],
[E_HORSE, F_HORSE],
[E_DRAGON, F_DRAGON],
];
const _: () = {
use crate::types::PieceType;
assert!(PIECE_BASE[PieceType::Pawn as usize][0] == E_PAWN);
assert!(PIECE_BASE[PieceType::Pawn as usize][1] == F_PAWN);
assert!(PIECE_BASE[PieceType::Lance as usize][0] == E_LANCE);
assert!(PIECE_BASE[PieceType::Lance as usize][1] == F_LANCE);
assert!(PIECE_BASE[PieceType::Knight as usize][0] == E_KNIGHT);
assert!(PIECE_BASE[PieceType::Knight as usize][1] == F_KNIGHT);
assert!(PIECE_BASE[PieceType::Silver as usize][0] == E_SILVER);
assert!(PIECE_BASE[PieceType::Silver as usize][1] == F_SILVER);
assert!(PIECE_BASE[PieceType::Bishop as usize][0] == E_BISHOP);
assert!(PIECE_BASE[PieceType::Bishop as usize][1] == F_BISHOP);
assert!(PIECE_BASE[PieceType::Rook as usize][0] == E_ROOK);
assert!(PIECE_BASE[PieceType::Rook as usize][1] == F_ROOK);
assert!(PIECE_BASE[PieceType::Gold as usize][0] == E_GOLD);
assert!(PIECE_BASE[PieceType::Gold as usize][1] == F_GOLD);
assert!(PIECE_BASE[PieceType::ProPawn as usize][0] == E_GOLD);
assert!(PIECE_BASE[PieceType::ProPawn as usize][1] == F_GOLD);
assert!(PIECE_BASE[PieceType::ProLance as usize][0] == E_GOLD);
assert!(PIECE_BASE[PieceType::ProLance as usize][1] == F_GOLD);
assert!(PIECE_BASE[PieceType::ProKnight as usize][0] == E_GOLD);
assert!(PIECE_BASE[PieceType::ProKnight as usize][1] == F_GOLD);
assert!(PIECE_BASE[PieceType::ProSilver as usize][0] == E_GOLD);
assert!(PIECE_BASE[PieceType::ProSilver as usize][1] == F_GOLD);
assert!(PIECE_BASE[PieceType::Horse as usize][0] == E_HORSE);
assert!(PIECE_BASE[PieceType::Horse as usize][1] == F_HORSE);
assert!(PIECE_BASE[PieceType::Dragon as usize][0] == E_DRAGON);
assert!(PIECE_BASE[PieceType::Dragon as usize][1] == F_DRAGON);
assert!(PIECE_BASE[PieceType::King as usize][0] == 0);
assert!(PIECE_BASE[PieceType::King as usize][1] == 0);
};
pub const FE_END: usize = 1548;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct ExtBonaPiece {
pub fb: BonaPiece,
pub fw: BonaPiece,
}
impl ExtBonaPiece {
pub const ZERO: ExtBonaPiece = ExtBonaPiece {
fb: BonaPiece::ZERO,
fw: BonaPiece::ZERO,
};
#[inline]
pub const fn new(fb: BonaPiece, fw: BonaPiece) -> Self {
Self { fb, fw }
}
#[inline]
pub fn from_board(piece: Piece, sq: Square) -> Self {
if piece.is_none() {
return Self::ZERO;
}
let pt = piece.piece_type();
let color = piece.color();
if pt == PieceType::King {
use super::bona_piece_halfka_hm::{E_KING, F_KING};
let (fb, fw) = if color == Color::Black {
(
BonaPiece::new(F_KING as u16 + sq.index() as u16),
BonaPiece::new(E_KING as u16 + sq.inverse().index() as u16),
)
} else {
(
BonaPiece::new(E_KING as u16 + sq.index() as u16),
BonaPiece::new(F_KING as u16 + sq.inverse().index() as u16),
)
};
return Self { fb, fw };
}
let is_friend_black = (color == Color::Black) as usize;
let is_friend_white = (color == Color::White) as usize;
let base_fb = PIECE_BASE[pt as usize][is_friend_black];
let base_fw = PIECE_BASE[pt as usize][is_friend_white];
Self {
fb: BonaPiece::new(base_fb + sq.index() as u16),
fw: BonaPiece::new(base_fw + sq.inverse().index() as u16),
}
}
#[inline]
pub fn from_hand(owner: Color, pt: PieceType, count: u8) -> Self {
if count == 0 {
return Self::ZERO;
}
let fb = BonaPiece::from_hand_piece(Color::Black, owner, pt, count);
let fw = BonaPiece::from_hand_piece(Color::White, owner, pt, count);
Self { fb, fw }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(transparent)]
pub struct BonaPiece(pub u16);
impl BonaPiece {
pub const ZERO: BonaPiece = BonaPiece(0);
#[inline]
pub const fn new(value: u16) -> Self {
Self(value)
}
#[inline]
pub const fn value(self) -> u16 {
self.0
}
pub fn from_piece_square(piece: Piece, sq: Square, perspective: Color) -> BonaPiece {
if piece.is_none() {
return BonaPiece::ZERO;
}
let pt = piece.piece_type();
let pc_color = piece.color();
let sq_index = if perspective == Color::Black {
sq.index()
} else {
sq.inverse().index()
};
let is_friend = pc_color == perspective;
let base = match pt {
PieceType::Pawn => {
if is_friend {
F_PAWN
} else {
E_PAWN
}
}
PieceType::Lance => {
if is_friend {
F_LANCE
} else {
E_LANCE
}
}
PieceType::Knight => {
if is_friend {
F_KNIGHT
} else {
E_KNIGHT
}
}
PieceType::Silver => {
if is_friend {
F_SILVER
} else {
E_SILVER
}
}
PieceType::Gold
| PieceType::ProPawn
| PieceType::ProLance
| PieceType::ProKnight
| PieceType::ProSilver => {
if is_friend { F_GOLD } else { E_GOLD }
}
PieceType::Bishop => {
if is_friend {
F_BISHOP
} else {
E_BISHOP
}
}
PieceType::Rook => {
if is_friend {
F_ROOK
} else {
E_ROOK
}
}
PieceType::Horse => {
if is_friend {
F_HORSE
} else {
E_HORSE
}
}
PieceType::Dragon => {
if is_friend {
F_DRAGON
} else {
E_DRAGON
}
}
PieceType::King => {
return BonaPiece::ZERO;
}
};
BonaPiece::new(base + sq_index as u16)
}
pub fn from_hand_piece(
perspective: Color,
owner: Color,
pt: PieceType,
count: u8,
) -> BonaPiece {
if count == 0 {
return BonaPiece::ZERO;
}
let is_friend = owner == perspective;
let base = match pt {
PieceType::Pawn => {
if is_friend {
F_HAND_PAWN
} else {
E_HAND_PAWN
}
}
PieceType::Lance => {
if is_friend {
F_HAND_LANCE
} else {
E_HAND_LANCE
}
}
PieceType::Knight => {
if is_friend {
F_HAND_KNIGHT
} else {
E_HAND_KNIGHT
}
}
PieceType::Silver => {
if is_friend {
F_HAND_SILVER
} else {
E_HAND_SILVER
}
}
PieceType::Gold => {
if is_friend {
F_HAND_GOLD
} else {
E_HAND_GOLD
}
}
PieceType::Bishop => {
if is_friend {
F_HAND_BISHOP
} else {
E_HAND_BISHOP
}
}
PieceType::Rook => {
if is_friend {
F_HAND_ROOK
} else {
E_HAND_ROOK
}
}
_ => return BonaPiece::ZERO,
};
let bp = BonaPiece::new(base + count as u16 - 1);
debug_assert!(
(bp.0 as usize) < FE_HAND_END,
"Hand piece BonaPiece {} exceeds FE_HAND_END {}",
bp.0,
FE_HAND_END
);
bp
}
}
#[inline]
pub fn halfkp_index(king_sq: Square, bona_piece: BonaPiece) -> usize {
king_sq.index() * FE_END + bona_piece.0 as usize
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{File, Rank};
#[test]
fn test_bona_piece_zero() {
assert_eq!(BonaPiece::ZERO.value(), 0);
}
#[test]
fn test_bona_piece_from_piece_square() {
let sq = Square::new(File::File7, Rank::Rank7);
let piece = Piece::new(Color::Black, PieceType::Pawn);
let bp = BonaPiece::from_piece_square(piece, sq, Color::Black);
assert_ne!(bp, BonaPiece::ZERO);
}
#[test]
fn test_bona_piece_king_returns_zero() {
let sq = Square::new(File::File5, Rank::Rank9);
let piece = Piece::new(Color::Black, PieceType::King);
let bp = BonaPiece::from_piece_square(piece, sq, Color::Black);
assert_eq!(bp, BonaPiece::ZERO);
}
#[test]
fn test_halfkp_index() {
let king_sq = Square::new(File::File5, Rank::Rank9);
let bp = BonaPiece::new(100);
let index = halfkp_index(king_sq, bp);
assert_eq!(index, king_sq.index() * FE_END + 100);
}
#[test]
fn test_piece_base_table_consistency() {
let all_piece_types = [
PieceType::Pawn,
PieceType::Lance,
PieceType::Knight,
PieceType::Silver,
PieceType::Gold,
PieceType::Bishop,
PieceType::Rook,
PieceType::ProPawn,
PieceType::ProLance,
PieceType::ProKnight,
PieceType::ProSilver,
PieceType::Horse,
PieceType::Dragon,
];
let sq = Square::from_u8(0).unwrap();
let perspective = Color::Black;
for pt in all_piece_types {
for &color in &[Color::Black, Color::White] {
let is_friend = color == perspective;
let piece = Piece::new(color, pt);
let bp_old = BonaPiece::from_piece_square(piece, sq, perspective);
let base = PIECE_BASE[pt as usize][is_friend as usize];
let bp_new = BonaPiece::new(base);
assert_eq!(
bp_old, bp_new,
"Mismatch for {:?}, color={:?}, is_friend={}",
pt, color, is_friend
);
}
}
}
}