mod half_ka;
mod half_ka_hm;
mod half_kp;
pub use half_ka::HalfKA;
pub use half_ka_hm::HalfKA_hm;
pub use half_kp::HalfKP;
use super::accumulator::{DirtyPiece, IndexList, MAX_ACTIVE_FEATURES, MAX_CHANGED_FEATURES};
use super::diff::ChangedFeatures;
use crate::position::Position;
use crate::types::{Color, Square};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TriggerEvent {
None,
FriendKingMoved,
EnemyKingMoved,
AnyKingMoved,
AnyPieceMoved,
}
pub trait Feature {
const DIMENSIONS: usize;
const MAX_ACTIVE: usize;
const REFRESH_TRIGGER: TriggerEvent;
fn append_active_indices(
pos: &Position,
perspective: Color,
active: &mut IndexList<MAX_ACTIVE_FEATURES>,
);
fn append_changed_indices(
dirty_piece: &DirtyPiece,
perspective: Color,
king_sq: Square,
removed: &mut IndexList<MAX_CHANGED_FEATURES>,
added: &mut IndexList<MAX_CHANGED_FEATURES>,
);
}
pub trait FeatureSet {
const DIMENSIONS: usize;
const MAX_ACTIVE: usize;
const REFRESH_TRIGGERS: &'static [TriggerEvent];
fn collect_active_indices(pos: &Position, perspective: Color)
-> IndexList<MAX_ACTIVE_FEATURES>;
fn collect_changed_indices(
dirty_piece: &DirtyPiece,
perspective: Color,
king_sq: Square,
) -> ChangedFeatures;
fn needs_refresh(dirty_piece: &DirtyPiece, perspective: Color) -> bool;
}
pub struct HalfKPFeatureSet;
impl FeatureSet for HalfKPFeatureSet {
const DIMENSIONS: usize = HalfKP::DIMENSIONS;
const MAX_ACTIVE: usize = HalfKP::MAX_ACTIVE;
const REFRESH_TRIGGERS: &'static [TriggerEvent] = &[TriggerEvent::FriendKingMoved];
#[inline]
fn collect_active_indices(
pos: &Position,
perspective: Color,
) -> IndexList<MAX_ACTIVE_FEATURES> {
let mut active = IndexList::new();
HalfKP::append_active_indices(pos, perspective, &mut active);
active
}
#[inline]
fn collect_changed_indices(
dirty_piece: &DirtyPiece,
perspective: Color,
king_sq: Square,
) -> ChangedFeatures {
let mut removed = IndexList::new();
let mut added = IndexList::new();
HalfKP::append_changed_indices(dirty_piece, perspective, king_sq, &mut removed, &mut added);
(removed, added)
}
#[inline]
fn needs_refresh(dirty_piece: &DirtyPiece, perspective: Color) -> bool {
dirty_piece.king_moved[perspective.index()]
}
}
#[allow(non_camel_case_types)]
pub struct HalfKA_hm_FeatureSet;
impl FeatureSet for HalfKA_hm_FeatureSet {
const DIMENSIONS: usize = HalfKA_hm::DIMENSIONS;
const MAX_ACTIVE: usize = HalfKA_hm::MAX_ACTIVE;
const REFRESH_TRIGGERS: &'static [TriggerEvent] = &[TriggerEvent::FriendKingMoved];
#[inline]
fn collect_active_indices(
pos: &Position,
perspective: Color,
) -> IndexList<MAX_ACTIVE_FEATURES> {
let mut active = IndexList::new();
HalfKA_hm::append_active_indices(pos, perspective, &mut active);
active
}
#[inline]
fn collect_changed_indices(
dirty_piece: &DirtyPiece,
perspective: Color,
king_sq: Square,
) -> ChangedFeatures {
let mut removed = IndexList::new();
let mut added = IndexList::new();
HalfKA_hm::append_changed_indices(
dirty_piece,
perspective,
king_sq,
&mut removed,
&mut added,
);
(removed, added)
}
#[inline]
fn needs_refresh(dirty_piece: &DirtyPiece, perspective: Color) -> bool {
dirty_piece.king_moved[perspective.index()]
}
}
pub struct HalfKAFeatureSet;
impl FeatureSet for HalfKAFeatureSet {
const DIMENSIONS: usize = HalfKA::DIMENSIONS;
const MAX_ACTIVE: usize = HalfKA::MAX_ACTIVE;
const REFRESH_TRIGGERS: &'static [TriggerEvent] = &[TriggerEvent::FriendKingMoved];
#[inline]
fn collect_active_indices(
pos: &Position,
perspective: Color,
) -> IndexList<MAX_ACTIVE_FEATURES> {
let mut active = IndexList::new();
HalfKA::append_active_indices(pos, perspective, &mut active);
active
}
#[inline]
fn collect_changed_indices(
dirty_piece: &DirtyPiece,
perspective: Color,
king_sq: Square,
) -> ChangedFeatures {
let mut removed = IndexList::new();
let mut added = IndexList::new();
HalfKA::append_changed_indices(dirty_piece, perspective, king_sq, &mut removed, &mut added);
(removed, added)
}
#[inline]
fn needs_refresh(dirty_piece: &DirtyPiece, perspective: Color) -> bool {
dirty_piece.king_moved[perspective.index()]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_needs_refresh_black_king_moved() {
let mut dirty_piece = DirtyPiece::new();
dirty_piece.king_moved[Color::Black.index()] = true;
assert!(HalfKPFeatureSet::needs_refresh(&dirty_piece, Color::Black));
assert!(!HalfKPFeatureSet::needs_refresh(&dirty_piece, Color::White));
}
#[test]
fn test_needs_refresh_white_king_moved() {
let mut dirty_piece = DirtyPiece::new();
dirty_piece.king_moved[Color::White.index()] = true;
assert!(!HalfKPFeatureSet::needs_refresh(&dirty_piece, Color::Black));
assert!(HalfKPFeatureSet::needs_refresh(&dirty_piece, Color::White));
}
#[test]
fn test_needs_refresh_no_king_moved() {
let dirty_piece = DirtyPiece::new();
assert!(!HalfKPFeatureSet::needs_refresh(&dirty_piece, Color::Black));
assert!(!HalfKPFeatureSet::needs_refresh(&dirty_piece, Color::White));
}
}