use crate::types::Move;
use super::types::MAX_MOVES;
pub struct MoveList {
moves: [Move; MAX_MOVES],
len: usize,
}
impl MoveList {
#[inline]
pub const fn new() -> Self {
Self {
moves: [Move::NONE; MAX_MOVES],
len: 0,
}
}
#[inline]
pub const fn len(&self) -> usize {
self.len
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &Move> {
self.moves[..self.len].iter()
}
pub fn contains(&self, mv: Move) -> bool {
self.moves[..self.len].contains(&mv)
}
#[inline]
pub fn at(&self, i: usize) -> Move {
debug_assert!(i < self.len);
self.moves[i]
}
#[inline]
pub fn push(&mut self, mv: Move) {
if self.len >= MAX_MOVES {
return;
}
self.moves[self.len] = mv;
self.len += 1;
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [Move; MAX_MOVES] {
&mut self.moves
}
#[inline]
pub fn set_len(&mut self, len: usize) {
debug_assert!(len <= MAX_MOVES);
self.len = len;
}
#[inline]
pub fn as_slice(&self) -> &[Move] {
&self.moves[..self.len]
}
}
impl Default for MoveList {
fn default() -> Self {
Self::new()
}
}
impl std::ops::Index<usize> for MoveList {
type Output = Move;
fn index(&self, index: usize) -> &Self::Output {
&self.moves[index]
}
}
impl<'a> IntoIterator for &'a MoveList {
type Item = &'a Move;
type IntoIter = std::slice::Iter<'a, Move>;
fn into_iter(self) -> Self::IntoIter {
self.moves[..self.len].iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{File, PieceType, Rank, Square};
#[test]
fn test_movelist_new() {
let list = MoveList::new();
assert_eq!(list.len(), 0);
assert!(list.is_empty());
}
#[test]
fn test_movelist_push() {
let mut list = MoveList::new();
let sq1 = Square::new(File::File7, Rank::Rank7);
let sq2 = Square::new(File::File7, Rank::Rank6);
let mv = Move::new_move(sq1, sq2, false);
list.push(mv);
assert_eq!(list.len(), 1);
assert!(!list.is_empty());
assert_eq!(list.at(0), mv);
assert!(list.contains(mv));
}
#[test]
fn test_movelist_iter() {
let mut list = MoveList::new();
let sq1 = Square::new(File::File7, Rank::Rank7);
let sq2 = Square::new(File::File7, Rank::Rank6);
let sq3 = Square::new(File::File5, Rank::Rank5);
list.push(Move::new_move(sq1, sq2, false));
list.push(Move::new_drop(PieceType::Pawn, sq3));
let moves: Vec<_> = list.iter().collect();
assert_eq!(moves.len(), 2);
}
#[test]
fn test_movelist_index() {
let mut list = MoveList::new();
let sq = Square::new(File::File5, Rank::Rank5);
let mv = Move::new_drop(PieceType::Gold, sq);
list.push(mv);
assert_eq!(list[0], mv);
}
#[test]
fn test_movelist_push_overflow_is_safe() {
let mut list = MoveList::new();
for _ in 0..MAX_MOVES {
list.push(Move::NONE);
}
let len_before = list.len();
list.push(Move::NONE);
assert_eq!(list.len(), len_before);
}
}