use crate::error;
use crate::prelude::{
actions::Action,
board::main::Board,
pieces::{dove_to_index, try_index_to_dove, Dove},
};
pub trait ActionContainer:
Clone + IntoIterator<Item = Action> + std::ops::Index<usize, Output = Action> + private::Sealed
{
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn contains(&self, action: Action) -> bool;
}
pub mod private {
pub trait Sealed {}
}
#[derive(Clone)]
pub(crate) struct FiniteActionContainer<const N: usize> {
container: [Option<Action>; N],
cursor: usize,
}
impl<const N: usize> std::fmt::Debug for FiniteActionContainer<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<const N: usize> private::Sealed for FiniteActionContainer<N> {}
impl<const N: usize> IntoIterator for FiniteActionContainer<N> {
type Item = Action;
type IntoIter = FiniteActionContainerIntoIter<N>;
fn into_iter(self) -> Self::IntoIter {
FiniteActionContainerIntoIter {
iter: self.container.into_iter(),
}
}
}
impl<const N: usize> std::ops::Index<usize> for FiniteActionContainer<N> {
type Output = Action;
fn index(&self, index: usize) -> &Self::Output {
self.container[index].as_ref().unwrap()
}
}
impl<'a, const N: usize> FiniteActionContainer<N> {
pub fn iter(&'a self) -> FiniteActionContainerIter<'a> {
FiniteActionContainerIter {
iter: self.container.iter(),
}
}
pub fn display_as_ssn(&self, board: &Board) -> Result<String, error::Error> {
let mut vec = Vec::with_capacity(self.len());
for a in self.iter() {
vec.push(a.try_into_ssn(board)?);
}
Ok(format!("[{}]", vec.join(", ")))
}
}
pub(crate) trait MutableActionContainer: ActionContainer {
fn new() -> Self;
fn push(&mut self, action: Action);
}
impl<const N: usize> MutableActionContainer for FiniteActionContainer<N> {
fn new() -> Self {
FiniteActionContainer {
container: [None; N],
cursor: 0,
}
}
fn push(&mut self, action: Action) {
if self.cursor >= N {
panic!("index out of range");
}
self.container[self.cursor] = Some(action);
self.cursor += 1;
}
}
impl<const N: usize> ActionContainer for FiniteActionContainer<N> {
fn len(&self) -> usize {
self.cursor
}
fn is_empty(&self) -> bool {
self.cursor == 0
}
fn contains(&self, action: Action) -> bool {
for (i, a) in self.container.into_iter().enumerate() {
if i >= self.cursor {
return false;
}
if Some(action) == a {
return true;
}
}
false
}
}
impl<'a, const N: usize> IntoIterator for &'a FiniteActionContainer<N> {
type Item = <<Self as IntoIterator>::IntoIter as Iterator>::Item;
type IntoIter = FiniteActionContainerIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone)]
pub(crate) struct FiniteActionContainerIter<'a> {
iter: std::slice::Iter<'a, Option<Action>>,
}
impl<'a> Iterator for FiniteActionContainerIter<'a> {
type Item = &'a Action;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()?.as_ref()
}
}
#[derive(Clone)]
pub(crate) struct FiniteActionContainerIntoIter<const N: usize> {
iter: std::array::IntoIter<Option<Action>, N>,
}
impl<const N: usize> Iterator for FiniteActionContainerIntoIter<N> {
type Item = Action;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()?
}
}
#[derive(Clone, Copy)]
pub struct DoveSet {
pub(crate) hash: u8,
}
impl std::fmt::Debug for DoveSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_set().entries(*self).finish()
}
}
impl DoveSet {
pub fn is_empty(&self) -> bool {
self.hash == 0
}
pub fn len(&self) -> usize {
self.hash.count_ones() as usize
}
pub fn contains(&self, dove: Dove) -> bool {
let bit = 1 << dove_to_index(dove);
self.hash & bit != 0
}
}
impl IntoIterator for DoveSet {
type Item = Dove;
type IntoIter = DoveSetIntoIter;
fn into_iter(self) -> Self::IntoIter {
DoveSetIntoIter::new(self)
}
}
#[derive(Clone)]
pub struct DoveSetIntoIter {
dove_set: DoveSet,
cursor: u8,
}
impl std::fmt::Debug for DoveSetIntoIter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let vec: Vec<Dove> = self.clone().collect();
f.debug_tuple("DoveSetIntoIter").field(&vec).finish()
}
}
impl DoveSetIntoIter {
fn new(dove_set: DoveSet) -> Self {
DoveSetIntoIter {
dove_set,
cursor: 1,
}
}
}
impl Iterator for DoveSetIntoIter {
type Item = Dove;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor.trailing_zeros() >= 6 {
return None;
}
match (self.dove_set.hash & self.cursor).trailing_zeros() {
idx @ 0..=5 => {
let ret = try_index_to_dove(idx as usize);
self.cursor <<= 1;
if ret.is_none() {
unreachable!();
}
ret
}
8 => {
self.cursor <<= 1;
self.next()
}
_ => unreachable!(),
}
}
}